问题
I am trying to plot small networks using igraph in R. Each vertex in the network has a name, which is equivalent to its label. I would like to make each vertex have a rectangular symbol that is just large enough to fit its label.
This is my main inspiration.
What is the best way to do this with igraph?
Edit: more information
The code is here
jsonToNM <- function(jfile, directed=TRUE) {
# Requires "rjson" and "igraph"
nm.json <- fromJSON(file=jfile)
nm.graph <- c()
# Initialize the graph with the given nodes
g <- graph.empty(n=length(nm.json), directed=directed)
# Add their names
V(g)$name <- names(nm.json)
V(g)$label <- V(g)$name
# Now, add the edges
for(i in 1:length(nm.json)) {
# If the node has a "connected" field,
# then we note the connections by looking
# the names up.
if(length(nm.json[[i]]$connected > 0)) {
for(j in 1:length(nm.json[[i]]$connected)) {
# Add the entry
g <- g + edge(names(nm.json)[i],
nm.json[[i]]$connected[j])
}
}
}
plot(g, vertex.label.dist=1.5)
}
And the current output is below.
My goal is to place the labels inside of the vertex graphic, and expand the width of the vertex to accommodate the label.
回答1:
Here is an example. Among some dirty tricks (i.e. multiplying the vertex size by 200), the key is to use two plot commands, so that we can measure the width (and height) of the labels with strwidth()
, after the plot size is set with the first (empty) plot.
library(igraph)
camp <- graph.formula(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
Holly - Carol:Pat:Pam:Jennie:Bill,
Bill - Pauline:Michael:Lee:Holly,
Pauline - Bill:Jennie:Ann,
Jennie - Holly:Michael:Lee:Ann:Pauline,
Michael - Bill:Jennie:Ann:Lee:John,
Ann - Michael:Jennie:Pauline,
Lee - Michael:Bill:Jennie,
Gery - Pat:Steve:Russ:John,
Russ - Steve:Bert:Gery:John,
John - Gery:Russ:Michael)
V(camp)$label <- V(camp)$name
set.seed(42) ## to make this reproducable
co <- layout.auto(camp)
plot(0, type="n", ann=FALSE, axes=FALSE, xlim=extendrange(co[,1]),
ylim=extendrange(co[,2]))
plot(camp, layout=co, rescale=FALSE, add=TRUE,
vertex.shape="rectangle",
vertex.size=(strwidth(V(camp)$label) + strwidth("oo")) * 100,
vertex.size2=strheight("I") * 2 * 100)
Btw. this does not really work well with SVG graphics, because there is no way to measure the width of the text from R, the SVG device only makes guesses.
回答2:
I know that this is not a direct answer to your question but I would suggest to use a different tool for visualization. yEd is very good at adjusting the nodes' width to the label's size. You can also manipulate the visualization easily, and export it to SVG for a final polish. It can be obtained for free from www.yworks.com (Disclaimer: I am not working there).
To export the graph in a well-readable format (yEd does not understand igraph's gml-format), use graphml:
write.graph(graph, "test.graphml", format="graphml")
Open it in yEd. Go to edit-> properties mapper and click on "new configuration (Node)" (the green "plus" symbol, upper left). In the middle of the fram, under "data source", search for the name of your labels (should be 'name'). In the middle tab called "map to" choose "label text" and in the right column leave the "conversion" be set to "Automatic".
Now choose Tools -> fit node to label (the default parameters are fine for a first try) and then choose your favourite layout. You can export to various image-formats but to my knowledge all are implemented using a bitmap-intermediate. Thus, I normally export to SVG and do the polishing in inkscape. If anyone knows a more efficient procedure to get good-looking layouts of medium-sized graphs produced in igraph, let me know.
来源:https://stackoverflow.com/questions/14472079/match-vertex-size-to-label-size-in-igraph