rigraphggraphtidygraph

Controling arc position (up or down) in linear ggraph arcplot


Background

I have a network of nodes and edges which I would like to visualize as a linear arcplot. Based on my limited knowledge, I believe that {ggraph} is a good tool for this (especially given my familiarity with {ggplot2}) so that's what I'm trying here, but if theres's a compelling alternative I'm open to it.

Problem

I know it can render arcs above the line of nodes (as shown in my example below) but can also sometimes render them below. It looks like this can be controled by the strength argument. This works when I put strength outside aes for the arc (e.g. strength = -1 flips them all down), but gives the warning Ignoring unknown aesthetics: strength when applied inside aes as shown below.

Current effort

Below is a simple example to illustrate what I've tried so far and the resulting plot. I have searched StackOverflow and the ggraph documentation but can't seem to find the answer there. I have also tried the variants geom_edge_arc2 and geom_edge_arc0 without success. As a workaround, I could make a vector of values to feed to strength outside aes, but ideally I could do something inside aes with the data already provided to the function. Am I misunderstanding the intended syntax or being too picky?

Desired output

I would like to be able to control the direction (above or below) of each arc. For example, blue arcs above and red below based on the sign of edge_width (i.e. strength = sign(edge_width)).


# load packages
library(tidyverse, warn.conflicts = FALSE)
library(tidygraph, warn.conflicts = FALSE)
library(igraph, warn.conflicts = FALSE)
library(ggraph, warn.conflicts = FALSE)

# make random sim data reproducible
set.seed(1)

# define nodes
nodes <- data.frame(node_name = paste0("node", 1:5))

# define edges
edges <- t(combn(nodes$node_name, 2)) %>%
  as_tibble(.name_repair = "universal") %>% 
  rename(from = 1, to = 2) %>% 
  mutate(edge_width = sample(x = -10:10, size = nrow(.), replace = T))
#> New names:
#> * `` -> ...1
#> * `` -> ...2

# build network from nodes and edges
network <- tbl_graph(edges = edges, nodes = nodes, directed = FALSE)

# visualize network as arcplot
network %>% 
  ggraph(layout = "linear") +
  geom_edge_arc(aes(color = edge_width >= 0,
                    width = abs(edge_width),
                    strength = sign(edge_width)),
                alpha = 0.65) +
  geom_node_label(aes(label = node_name), size = 3)
#> Warning: Ignoring unknown aesthetics: strength

Created on 2021-02-26 by the reprex package (v1.0.0)


Session info

In case it matters:

sessionInfo()
#> R version 4.0.3 (2020-10-10)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 10 x64 (build 18363)
#> 
#> Matrix products: default
#> 
#> locale:
#> [1] LC_COLLATE=English_United States.1252 
#> [2] LC_CTYPE=English_United States.1252   
#> [3] LC_MONETARY=English_United States.1252
#> [4] LC_NUMERIC=C                          
#> [5] LC_TIME=English_United States.1252    
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> loaded via a namespace (and not attached):
#>  [1] ps_1.5.0          digest_0.6.27     assertthat_0.2.1  magrittr_2.0.1   
#>  [5] reprex_1.0.0      evaluate_0.14     highr_0.8         stringi_1.5.3    
#>  [9] rlang_0.4.10      cli_2.3.1         rstudioapi_0.13   fs_1.5.0         
#> [13] rmarkdown_2.7     tools_4.0.2       stringr_1.4.0     glue_1.4.2       
#> [17] xfun_0.21         yaml_2.2.1        compiler_4.0.2    htmltools_0.5.1.1
#> [21] knitr_1.31

Created on 2021-02-26 by the reprex package (v1.0.0)


Solution

  • It's been almost a year so until a better answer arrives, I'll post my workaround as a solution in case anyone else has this issue.

    As proposed in the question, a workaround is to separately pull a vector of strength values and then feed that to the geom_edge_arc call outside of aes.

    # load packages
    library(tidyverse)
    library(tidygraph)
    library(igraph)
    library(ggraph)
    
    # make random sim data reproducible
    set.seed(1)
    
    # define nodes
    nodes <- data.frame(node_name = paste0("node", 1:5))
    
    # define edges
    edges <- t(combn(nodes$node_name, 2)) %>%
      as_tibble(.name_repair = "universal") %>% 
      rename(from = 1, to = 2) %>% 
      mutate(edge_width = sample(x = -10:10, size = nrow(.), replace = T))
    
    # extract vector of desired arc positions based on sign of edge width
    arc_direction <- sign(edges$edge_width)
    
    # build network from nodes and edges
    network <- tbl_graph(edges = edges, nodes = nodes, directed = FALSE)
    
    # visualize network as arcplot
    network %>% 
      ggraph(layout = "linear") +
      geom_edge_arc(aes(color = edge_width >= 0,
                        width = abs(edge_width)),
                    strength = arc_direction,
                    alpha = 0.65) +
      geom_node_label(aes(label = node_name), size = 3)
    

    Created on 2021-12-30 by the reprex package (v2.0.1)