I am trying to draw following graph in ggraph.
igraph class object is obtained from a data frame below:
edge <- data.frame(from=c(0,0,0,0,1,2,3),
to=c(0,1,2,3,0,0,0),
weight=c(1,3,1,1,3,1,1))
node <- data.frame(id=c(0,1,2,3),
p=c(9,1,0,0),
w=c(0,2,0,0),
s=c(0,0,1,1),
size=c(9,3,1,1),
gr=c(0,1,1,2))
# Convert data frame into igraph class object
net <- graph_from_data_frame(d=edge,vertices=node,directed=TRUE)
However, when I draw the graph in the following scripts, it produces unexpected width of edges:
## Set arrows
ar <- arrow(angle=30,length=unit(5,"mm"),ends="last",type="closed")
## Plot
ggraph(net,layout="graphopt") +
## Edges
geom_edge_link(aes(width=weight,label=weight,
start_cap=circle(node1.size+1,unit="native"),
end_cap=circle(node2.size+1,unit="native")),
angle_calc="along",force_flip=TRUE,
label_dodge=unit(3.0,"mm"),label_push=unit(-0.4,"mm")) +
## Width scale
scale_edge_width(range=c(0.2,4),breaks=c(1:10),name="Movements\nbetween zones") +
## Add arrows separately
geom_edge_link(arrow=ar,aes(start_cap=circle(node1.size,unit="native"),
end_cap=circle(node2.size,unit="native"))) +
## Nodes
geom_node_circle(aes(r=size)) +
## Plot location id
geom_node_label(aes(label=id),color="red",repel=TRUE,label.r=0.3,position="identity") +
## Plot work activity
geom_node_text(aes(size=w),label="w",color="green",position="identity") +
## Plot school activity
geom_node_text(aes(size=s),label="s",color="blue",position="identity") +
## Theme
theme_graph() + coord_fixed()
There are some fundamental issues:
Width of edges defined inweightdoes not correspond to node ID (from/toinedgeandnameinnode). For instance, weight3is given to0->1and1->0in data frame but it appears between0<->2in the graph,An edge between0<->1gets inside of node0even if margins are set bystart_capandend_cap,Weightlabels besides edges are not centralized (it is located near from node 0)- Labels defined by
geom_node_labeloverlaps nodes - Size of labels inside nodes (
wands) seems okay, however they are not located asdodge(they are overlapped each other)
Issues other than the first point are just aesthetic issues but the first point is fatal error of the plot. I plotted it in igraph which gives appropriate relations between nodes and edges.
## Sample in igraph
E(net)$width <- E(net)$weight
plot(net,edge.width=E(net)$weight*5,vertex.size=V(net)$size*5,vertex.label.cex=3)
I highly appreciate your suggestions to solve any of above issues to obtain desired graph. I am new to use ggraph and found some solutions to obtain current graph, however I have been stacking to fix above issues at this moment.
(I prefer to use ggraph rather than igraph to control its appearance precisely)
========== UPDATE ==========
Most of issues could be solved by the following scripts though it is very manual adjustment. One most important key is to remove loop edge between 0<->0 which caused inappropriate correspondence between label and actual width of edges.
## Load data frames as tbl_graph class
edge <- edge %>% mutate(from=from+1,to=to+1)
net <- tbl_graph(nodes=node,edges=edge,directed=TRUE)
## Set arrows
ar <- arrow(angle=30,length=unit(5,"mm"),ends="last",type="closed")
## Plot
ggraph(net,layout="graphopt") +
## Edges
geom_edge_link(aes(start_cap=circle(log(node1.size)+2,unit="native"),
end_cap=circle(log(node2.size)+2,unit="native"),
width=weight,label=weight),
position="identity",angle_calc="along",force_flip=TRUE,
label_dodge=unit(4.0,"mm"),label_push=unit(-0.4,"mm")) +
## Width scale
scale_edge_width(range=c(0.2,4),breaks=c(1:10),name="Movements\nbetween zones") +
## Add arrows separately
geom_edge_link(arrow=ar,aes(start_cap=circle(log(node1.size)+1,unit="native"),
end_cap=circle(log(node2.size)+1,unit="native"))) +
## Nodes
geom_node_circle(aes(r=log(size)+1)) +
## Plot location id
geom_node_label(aes(label=id,hjust=log(size+5),vjust=log(size+5)),repel=TRUE,
label.padding=unit(0.8,"mm"),label.r=unit(0.0,"mm"),label.size=0.1,size=3.5) +
## Plot work activity
geom_node_text(aes(size=w,hjust=log(w)+0.6),label="w",color="red",position="identity",vjust=0.4) +
## Plot school activity
geom_node_text(aes(size=s,hjust=-log(s)-0.3),label="s",color="blue",position="identity",vjust=0.4) +
## Size scale
scale_size(range=c(0,5),breaks=c(1:100),name="Numberof\nActivities",
guide=guide_legend(override.aes=list(rep("a",100)))) +
# scale_color() +
## Theme
theme_graph() + coord_fixed()
However there are two remaining issues on legend:
- How can I replace overlapped "w" and "s" by other font, such as "a" (activity)?
- How can I add one more manual legend "Types of activity" shown in desired result?
I posted it as a new question here



