Search code examples
rggplot2gradientlinear-gradientsggraph

Apply color gradient to ggraph's `geom_conn_bundle`


Context

I am using ggraph to arrange nodes (leaves of a tree) in a circular dendrogram and then add connections between some of the nodes (using hierarchical bundling using geom_conn_bundle):

library(ggraph)
library(igraph)

# Example data
edges <- data.frame(from="root", to=paste("leaf", seq(1,100), sep=""))
vertices <- data.frame(name = unique(c(as.character(edges$from), as.character(edges$to))) ) 
tree <- graph_from_data_frame( edges, vertices=vertices )

# Drawing nodes
pr <- ggraph(tree, layout = "dendrogram", circular = TRUE) + 
    geom_edge_diagonal(alpha = 0.2)

# Example connection
pr <- pr + geom_conn_bundle(
    data = get_con(from = 23, to = 42),
    alpha=0.8, 
    width=3, 
    colour="skyblue", 
    tension = 0.9
)
print(pr)

This nicely displays a nearly transparent dendrogram and some (in this example one) connections in skyblue.

Problem / Desired output

What I'd like though, is the direction of the connection being indicated by a color gradient (i.e. starting with green, slowly changing into red) instead of showing the connection in just one color (skyblue). How can I achive such a color gradient using R and ggraph's geom_conn_bundle?

The following excerpt from Holten (2006) can serve of an example of how I'd like the connections to look:

enter image description here


Solution

  • Several of the ggraph geoms for drawing edges, including geom_conn_bundle and geom_edge_diagonal, have a calculated index stat. It's a number from 0 to 1 of how far along the edge a point is. Note that the simplified versions of these geoms (geom_*0) don't calculate it. Some mentions of it are in this blog post by the ggraph author.

    In this case, map the index stat(index) to color inside your bundle's aes, then set a gradient scale with (scale_edge_color_gradient, not scale_color_gradient as I initially tried).

    In the example picture, I can't tell whether the width is also scaled, but the same would work, e.g. edge_width = stat(index).

    library(ggraph)
    library(igraph)
    
    ggraph(tree, layout = "dendrogram", circular = TRUE) + 
      geom_edge_diagonal(alpha = 0.2) + 
      geom_conn_bundle(aes(color = stat(index)),
        data = get_con(from = 23, to = 42),
        alpha=0.8, 
        width=3,
        # colour="skyblue", 
        tension = 0.9
      ) +
      scale_edge_color_gradient(low = "green", high = "red")
    

    Created on 2019-03-09 by the reprex package (v0.2.1)