Manual legend in ggraph/ggplot2 [R]

廉价感情. 提交于 2019-12-13 16:55:20

问题


Apart from this post, here I am asking new questions how to make adjustment in legends built by ggraph.

Here are scripts to produce current plot:

    ## Packages
    library(igraph)
    library(tidygraph)
    library(ggraph)
    library(ggplot2)
    library(tidyverse)

    ## Edge and node
    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,1,1,1),
                       size=c(9,3,1,1),
                       gr=c(0,1,1,2))

    ## 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.4,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
        ## Plot location id
        geom_node_label(aes(label=id,hjust=log(size+6),vjust=log(size+6)),repel=TRUE,
                        label.padding=unit(0.8,"mm"),label.r=unit(0.0,"mm"),label.size=0.1,size=3.5) +
        ## Circle
        geom_node_circle(aes(r=log(size)+1),color="black",fill="white",size=0.4) +
        ## Plot work activity
        geom_node_text(aes(size=w,hjust=log(w)+0.4),label="w",color="red",
                       position="identity",vjust=0.4,fontface="bold") +
        ## Plot school activity
        geom_node_text(aes(size=s,hjust=-log(s)-0.2),label="s",color="blue",
                       position="identity",vjust=0.4,fontface="bold") +
        ## Size scale
        scale_size(range=c(0,5),breaks=c(1:100),name="Numberof\nActivities",
                   guide=guide_legend(override.aes=list(label="a",color="black"))) +
        # scale_color() +
    ## Theme
    theme_graph() + coord_fixed()

This is my desired result.

This is the result from above scripts.

There are two issues related to legend to reach my desired result:

  • How can I replace overlapped "w" and "s" in "Number of Activities" by other font, such as "a" (activity) in black as shown in desired result?
  • How can I add one more manual legend "Types of activity" shown in desired result?

Though it is written in ggraph, I suppose the grammar seems to be similar to that in ggplot2. I appreciate your suggestions!!

========== UPDATE ==========

The first issue has solved by changing scale_size argument as shown in updated scripts.

However, the second issue is still remaining and I found one more issue on 0-value symbols at the center of circles (very small dot). I have found some solutions to solve the issue by applying 1) subset() to omit 0-value records from data frame in data=subset(df,x!=0), 2) simply filling 0 value by NA in data=ifelse(x==0,NA,.) methods, however as it is written from graph object, it may not work for this case straightforward.

========== UPDATE ver.2 ==========

It is really tricky but somehow I could remove dots at the center of line as well as adding one legend.

I am really not sure the reason but the former issue was solved by 1) replacing 0 values in node data frame by NA, 2) replace NA in aes(size=...) statement in geom_node_text as aes(size=ifelse(is.na(w),0,w) ..., then 3) specify color by color=ifelse(w==0,"white","red"). It does not remove the data but just change color of 0-value into white to make it invisible.

I suppose it is not formal solution but only the way that I encountered during dozens of trials. Interesting thing is that 1) and 2) should be combined otherwise it returns an error.

Thus this is the final update:

## Packages
    library(igraph)
    library(tidygraph)
    library(ggraph)
    library(ggplot2)
    library(tidyverse)

    ## Edge and node
    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,1,1,1),
                       size=c(9,3,1,1),
                       gr=c(0,1,1,2))

    ## Load data frames as tbl_graph class
    edge <- edge %>% mutate(from=from+1,to=to+1)
    # THIS IS QUITE STRANGE OPERATION FOR CHANGING COLOR
    node <- node %>% mutate_at(vars(p,w,s,size),funs(ifelse(.==0,NA,.)))
    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.4,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
        ## Plot location id
        geom_node_label(aes(label=id,hjust=log(size+6),vjust=log(size+6)),repel=TRUE,
                        label.padding=unit(0.8,"mm"),label.r=unit(0.0,"mm"),label.size=0.1,size=3.5) +
        ## Circle
        geom_node_circle(aes(r=log(size)+1),color="black",fill="white",size=0.4) +
        ## Plot work activity: NOT KNOW WHY IT WORKS!!
        geom_node_text(aes(size=ifelse(is.na(w),0,w),hjust=log(w)+0.4,color=ifelse(w==0,"white","red")),label="w",
                       position="identity",vjust=0.4,fontface="bold") +
        ## Plot school activity
        geom_node_text(aes(size=ifelse(is.na(s),0,s),hjust=-log(s)-0.2,color=ifelse(s==0,"white","blue")),label="s",
                       position="identity",vjust=0.4,fontface="bold") +
        ## Edit legend
        scale_size_continuous(range=c(0,5),breaks=c(1:100),name="Numberof\nActivities",
                   guide=guide_legend(override.aes=list(label="a",color="black"))) +
        scale_color_manual(name="Type of Activity",guide=guide_legend(override.aes=list(label=c("w","s"))),
                           values=c("red","blue"),labels=c("Work","School")) +
    ## Theme
    theme_graph() + coord_fixed()

However, as it is still ugly codes, I am still waiting for your suggestions for more appropriate operations.

来源:https://stackoverflow.com/questions/51581399/manual-legend-in-ggraph-ggplot2-r

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!