How to draw graph corresponding with its attributes in ggraph [R]
Asked Answered
A

0

1

I am trying to draw following graph in ggraph.

Desired graph

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:

Unexpected result

## 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 in weight does not correspond to node ID (from/to in edge and name in node). For instance, weight 3 is given to 0->1 and 1->0 in data frame but it appears between0<->2 in the graph,
  • An edge between 0<->1 gets inside of node 0 even if margins are set by start_cap and end_cap,
  • Weight labels besides edges are not centralized (it is located near from node 0)
  • Labels defined by geom_node_label overlaps nodes
  • Size of labels inside nodes (w and s) seems okay, however they are not located as dodge (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

## 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()

enter image description here

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

Arriola answered 28/7, 2018 at 9:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.