Search code examples
rggplot2plotggraph

Why doesn't scale_edge_width_identity(guide = "legend") work?


I am using ggraph to plot two networks containing nodes and edges of varying sizes and widths, respectively.

I want to maintain the absolute sizes of nodes and edges using scale_size_identity() and scale_edge_width_identity().

I'd like to display legends and am using scale_size_identity(legend = "guide") for nodes, which works as expected, but for edges scale_edge_width_identity(legend = "guide") I get the following error:

Error: Continuous value supplied to discrete scale

If I don't provide legend = "guide" to scale_edge_width_identity(), everything works. The variable I'm scaling is numeric. This problem also occurs if I'm using scale_edge_alpha_identity(legend = "guide") Why is this and is there any way I can still show the legends? Appreciate any suggestions.

UPDATE: It works with the suggestion by @teunbrand below. However, I noticed that scale_size_continuous() for scaling node size does not work with this approach. Use scale_radius() instead:

# building on example by @teunbrand
library(ggraph)
#> Loading required package: ggplot2
require(tidygraph)
#> Loading required package: tidygraph
#> 
#> Attaching package: 'tidygraph'
#> The following object is masked from 'package:stats':
#> 
#>     filter
library(patchwork)

gr <- create_notable("bull")
layout <- create_layout(gr, layout = "igraph", algorithm = "kk")

edge_guide <- guide_legend()

# Edges are plotted using the same scale but nodes are not when scale_size_continuous() is used.
# Notice the differently sized nodes between the legend guides:
ggraph(layout) +
  geom_node_point(aes(size = seq(1, 5, length.out = 5))) +
  geom_edge_link(aes(edge_width = seq(1, 5, length.out = 5))) +
  scale_size_continuous(range = c(1, 5), breaks = c(1, 3, 5)) +
  scale_edge_width_continuous(range = c(1, 5), breaks = c(1, 2, 3)) |
ggraph(layout) +
  geom_node_point(aes(size = seq(1, 10, length.out = 5))) +
  geom_edge_link(aes(edge_width = seq(1, 10, length.out = 5))) +
  scale_size_continuous(range = c(1, 10), breaks = c(1, 3, 5)) +
  scale_edge_width_continuous(range = c(1, 10), breaks = c(1, 2, 3)) 

plotOutput1

# However, using scale_radius() instead does the job:
ggraph(layout) +
  geom_node_point(aes(size = seq(1, 5, length.out = 5))) +
  geom_edge_link(aes(edge_width = seq(1, 5, length.out = 5))) +
  scale_radius(range = c(1, 5), breaks = c(1, 3, 5)) +
  scale_edge_width_continuous(range = c(1, 5), breaks = c(1, 2, 3)) |
ggraph(layout) +
  geom_node_point(aes(size = seq(1, 10, length.out = 5))) +
  geom_edge_link(aes(edge_width = seq(1, 10, length.out = 5))) +
  scale_radius(range = c(1, 10), breaks = c(1, 3, 5)) +
  scale_edge_width_continuous(range = c(1, 10), breaks = c(1, 2, 3)) 


Created on 2020-12-04 by the reprex package (v0.3.0)

plotOutput2


Solution

  • I get the confusion and this might be a bug, but here are workarounds. The workaround is basically to use the _continuous() version of the scales to mimick the _identity() version as close as possible by setting the range to the exact range of the data.

    library(ggraph)
    #> Loading required package: ggplot2
    require(tidygraph)
    #> Loading required package: tidygraph
    #> 
    #> Attaching package: 'tidygraph'
    #> The following object is masked from 'package:stats':
    #> 
    #>     filter
    
    gr <- create_notable('bull')
    layout <- create_layout(gr, layout = 'igraph', algorithm = 'kk')
    
    edge_guide <- guide_legend()
    
    ggraph(layout) +
      geom_node_point() +
      geom_edge_link(aes(edge_width = 1:5)) +
      scale_edge_width_continuous(range = c(1, 5))
    

    ggraph(layout) +
      geom_node_point() +
      geom_edge_link(aes(edge_alpha = seq(0.1, 1, length.out = 5))) +
      scale_edge_alpha_continuous(range = c(0.1, 1))
    

    Created on 2020-12-03 by the reprex package (v0.3.0)