4

I am having a little trouble understanding the difference between ggplot2 and ggraph with respect to facetting. Consider the following data:

library(igraph)
library(ggraph)
library(ggplot2)

df <- structure(list(x = c("H001", "H024", "H090", "H090", "H098", 
                     "H103", "H126", "H152", "H155", "H155", "B002", "B011", "B075", 
                     "B092", "M002", "M002", "M002", "M050", "M050", "M085", "M085", 
                     "M247", "M247", "M247"), 
               y = c("H103", "H126", "H152", "H155","H155", "H001", "H024", "H090", "H090", "H098", "B092", "B075", 
                      "B011", "B002", "M050", "M085", "M247", "M002", "M247", "M002", "M247", "M002", "M050", "M085"), 
               r = c(0.963248925980302, 0.991452643542894, 0.965947578382865, 
                     0.963234153063794, 0.962277411462605, 0.963248925980302, 
                     0.991452643542894, 0.965947578382865, 0.963234153063794, 
                     0.962277411462605, 0.960948147492217, 0.957371360458182, 
                     0.957371360458182, 0.960948147492217, 0.96976135236222, 
                     0.977435712803837, 0.997037031981303, 0.96976135236222, 
                     0.978553503235858, 0.977435712803837, 0.992741796542001, 
                     0.997037031981303, 0.978553503235858, 0.992741796542001), 
               facet_var = c("08MH", "08MH", "08MH", "08MH", "08MH", "08MH", "08MH", "08MH", "08MH", 
                             "08MH", "08HB", "08HB", "08HB", "08HB", "08NM", "08NM", "08NM", "08NM", 
                             "08NM", "08NM", "08NM", "08NM", "08NM", "08NM")), 
          class = "data.frame", row.names = c(NA, -24L), .Names = c("x", "y", "r", "facet_var")
)

If I plot the data using a simple ggplot I can facet in a way that I consider "normal":

ggplot(df, aes(x = x, y = y)) +
         geom_point() +
         facet_wrap(~facet_var)

enter image description here

That is each level of facet_var has some points associated with it and ONLY those point are plotted in the corresponding facet. Now if I try a similar approach using ggraph I encounter what to me is odd behaviour (though I obviously acknowledge it simply reflect a lack of understanding):

graph_cors <- graph_from_data_frame(df, directed = FALSE)

ggraph(graph_cors) +
  geom_edge_link(aes(edge_alpha = abs(r), color = r), edge_width = 2) +
  guides(edge_alpha = "none") +
  scale_edge_colour_gradientn(limits = c(-1, 1), colors = topo.colors(5)) +
  geom_node_point(color = "black", size = 5) +
  geom_node_text(aes(label = name), repel = TRUE) +
  facet_edges(~facet_var)

enter image description here

So that all nodes are plotted in each facet though edges respect the facetting. Can anyone outline what I'm doing wrong here?

Session Info

> sessionInfo()
R version 3.4.2 (2017-09-28)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

Matrix products: default

locale:
[1] LC_COLLATE=English_Canada.1252  LC_CTYPE=English_Canada.1252    LC_MONETARY=English_Canada.1252 LC_NUMERIC=C                   
[5] LC_TIME=English_Canada.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] ggraph_1.0.0    ggplot2_2.2.1   igraph_1.1.2    testthat_1.0.2  devtools_1.13.3

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.13          compiler_3.4.2        plyr_1.8.4            bindr_0.1             viridis_0.4.0        
 [6] tools_3.4.2           digest_0.6.12         viridisLite_0.2.0     memoise_1.1.0         tibble_1.3.4         
[11] gtable_0.2.0          pkgconfig_2.0.1       rlang_0.1.2           rstudioapi_0.7.0-9000 ggrepel_0.7.0        
[16] yaml_2.1.14           bindrcpp_0.2          gridExtra_2.3         withr_2.0.0           dplyr_0.7.4          
[21] grid_3.4.2            glue_1.1.1            R6_2.2.2              tweenr_0.1.5          udunits2_0.13        
[26] magrittr_1.5          scales_0.5.0          fortunes_1.5-4        MASS_7.3-47           units_0.4-6          
[31] assertthat_0.2.0      swtext_0.0.1          ggforce_0.1.1         colorspace_1.3-2      lazyeval_0.2.0       
[36] munsell_0.4.3         crayon_1.3.4    
boshek
  • 4,100
  • 1
  • 31
  • 55

2 Answers2

2

You need to assign the relevant variable as a node attribute to facet by nodes. Your facet_var variable is an edge attribute; if you assign it to each node in each dyad as node attribute, the faceting works.

facet_graph facets by two variables (e.g. an edge attribute and a node attribute). Seems like facet_nodes is what you want, but you need to send a node attribute to the argument, not an edge attribute.

Currently, your igraph object only has an edge attribute:

> graph_cors
IGRAPH UN-- 16 24 -- 
+ attr: name (v/c), r (e/n), facet_var (e/c)
+ edges (vertex names):
 [1] H001--H103 H024--H126 H090--H152 H090--H155 H098--H155 H001--H103 H024--H126 H090--H152
 [9] H090--H155 H098--H155 B002--B092 B011--B075 B011--B075 B002--B092 M002--M050 M002--M085
[17] M002--M247 M002--M050 M050--M247 M002--M085 M085--M247 M002--M247 M050--M247 M085--M247

graph_cors <- graph_from_data_frame(df, directed = FALSE)

facet_nodes <- cbind(c(df[,1], df[,2]), 
                     df[match(c(df[,1], df[,2]), df[,1]),4])

# Assign the facet_var variable to corresponding dyad pairs
V(graph_cors)$facet_node <- facet_nodes[match(V(graph_cors)$name, facet_nodes[,1]),2]

Now, the igraph object has a node attribute ("facet_node"):

> graph_cors
IGRAPH UN-- 16 24 -- 
+ attr: name (v/c), facet_node (v/c), r (e/n), facet_var (e/c)
+ edges (vertex names):
 [1] H001--H103 H024--H126 H090--H152 H090--H155 H098--H155 H001--H103 H024--H126 H090--H152
 [9] H090--H155 H098--H155 B002--B092 B011--B075 B011--B075 B002--B092 M002--M050 M002--M085
[17] M002--M247 M002--M050 M050--M247 M002--M085 M085--M247 M002--M247 M050--M247 M085--M247

# Use the facet_nodes argument with the nodal attribute
ggraph(graph_cors) +
  geom_edge_link(aes(edge_alpha = abs(r), color = r), edge_width = 2) +
  guides(edge_alpha = "none") +
  scale_edge_colour_gradientn(limits = c(-1, 1), colors = topo.colors(5)) +
  geom_node_point(color = "black", size = 5) +
  geom_node_text(aes(label = name), repel = TRUE) +
  facet_nodes(~facet_node)

enter image description here

paqmo
  • 3,649
  • 1
  • 11
  • 21
  • This is great. I do find setting the `facet_node` to be more intuitive if I do it like this: `library(tidyverse) V(graph_cors)$facet_node <- df %>% gather(vars, values, -r, -facet_var) %>% distinct(values, .keep_all = TRUE) %>% pull(facet_var)`. But that is just so others can try that approach too. – boshek Oct 17 '17 at 20:20
  • If you were plotting some non-igraph data here would you be able to also use `facet_wrap` as long as the facets were the same name? – boshek Oct 17 '17 at 20:23
0

I think this is by design and you're not doing anything "wrong".

facet_edges repeats nodes in every panel and draws edges which map to the variable.

facet_nodes draws nodes which map to the variable and draws edges for which terminal nodes are present in the panel.

facet_graph - from its documentation - "takes care of all of these issues, allowing you to define which data type the rows and columns are referencing as well as filtering the edges based on the nodes in each panel (even when nodes are not drawn)."

So it may be that the behaviour of facet_nodes or facet_graph is more like what you expected.

neilfws
  • 32,751
  • 5
  • 50
  • 63
  • I should have mentioned that I did try `facet_nodes()` and get this error `Error in combine_vars(data, params$plot_env, vars, drop = params$drop) : At least one layer must contain all variables used for facetting` – boshek Oct 12 '17 at 23:06
  • In that case, perhaps `facet_graph` is more like what you expected; edited answer. – neilfws Oct 12 '17 at 23:28
  • Worked for me using your example data. I use the latest R (3.4.2), ggplot2 (2.2.1) and ggraph from Github (1.0.0). – neilfws Oct 12 '17 at 23:35
  • Same - added session info to the question. Weird. – boshek Oct 12 '17 at 23:43