Udostępnij za pośrednictwem


Convert igraph R objects to Gexf GePhi format

GePhi has interesting visualization capabilities built around graphs - and igraph is one of the widely used graph processing libraries for R. But there is no straightway to combine these two at present in R. The gexf format used by GePhi is not currently supported by the igraph package.

GePhi has its own package, the rgexf package for R, that provides some support for creating GePhi styled graphs out of custom matrix/dataframe data. It would have been great if it accepted an igraph object straight out-of-the box and generated a gexf object from it. But the current version does not support it. However, rolling out your own exporter is not that difficult. Here is something to get you started.

   # load the igraph and rgexf packages
  library(igraph)
  library(rgexf)

  # create a sample igraph object
  cg1 <- erdos.renyi.game(10, 0.8)

  # construct the nodes and edges data for gexf conversion
  nodes <- data.frame(cbind(V(cg1), as.character(V(cg1))))
  edges <- t(Vectorize(get.edge, vectorize.args='id')(cg1, 1:ecount(cg1)))

  # do the conversion
  write.gexf(nodes, edges)    

This piece of code will generate xml formatted in gexf ready for GePhi. You can further add node attributes and edge weights in similar fashion.

There are couple of points to be taken care though, such as xml & problem. For some reason, write.gexf fails to properly handle & symbols in the attribute vectors, so you would have to convert the & symbol to & before sending it to write.gexf.

Also note that write.gexf writes to console output and does not save to file. You would have to use print method for that. This is somewhat confusing naming convension !!

A reusable method with complete source code for exporting the igraph nodes and edges along with the associated attribute data can be found here.

Comments

  • Anonymous
    November 20, 2013
    Very useful. I had a look at the reusable method and I think that the function saveAsGEXF could be improved as saveAsGEXF = function(g, filepath="converted_graph.gexf") {  require(igraph)  require(rgexf)  # gexf nodes require two column data frame (id, label)  # check if the input vertices has label already present  # if not, just have the ids themselves as the label  if(is.null(V(g)$label))    V(g)$label <- as.character(V(g)$name)  # similarily if edges does not have weight, add default 1 weight  if(is.null(E(g)$weight))    E(g)$weight <- rep.int(1, ecount(g))  nodes <- data.frame(cbind(V(g), V(g)$label))  edges <- t(Vectorize(get.edge, vectorize.args='id')(g, 1:ecount(g)))  # combine all node attributes into a matrix (and take care of & for xml)  vAttrNames <- setdiff(list.vertex.attributes(g), "label")  nodesAtt <- data.frame(sapply(vAttrNames, function(attr) sub("&", "&",get.vertex.attribute(g, attr))),                         stringsAsFactors = FALSE)  # combine all edge attributes into a matrix (and take care of & for xml)  eAttrNames <- setdiff(list.edge.attributes(g), "weight")  edgesAtt <- data.frame(sapply(eAttrNames, function(attr) sub("&", "&",get.edge.attribute(g, attr))),                         stringsAsFactors = FALSE)  # generate the gexf object  output <- write.gexf(nodes, edges,                       edgesWeight=E(g)$weight,                       edgesAtt = edgesAtt,                       nodesAtt = nodesAtt)  print(output, filepath, replace=T) } avoiding the transformation of string attributes int factors that would result as numeric in the gexf dump (as a matter of fact loosing the textual content).

  • Anonymous
    November 20, 2013
    Thanks Roberto Brunelli

  • Anonymous
    November 20, 2013
    I think that this is better, as it preserves the differences between numbers and string ...  # combine all node attributes into a matrix (and take care of & for xml)  vAttrNames <- setdiff(list.vertex.attributes(g), "label")  nodesAtt <- data.frame(lapply(vAttrNames,                                function(attr) {                                  v = get.vertex.attribute(g, attr);                                  if(typeof(v) == "character")                                    v = sub("&", "&", get.vertex.attribute(g, attr))                                  v                                }),                         stringsAsFactors = FALSE)  colnames(nodesAtt) <- vAttrNames the same goes for edgesAtt