thomasp85 / ggraph

Grammar of Graph Graphics
https://ggraph.data-imaginist.com
Other
1.08k stars 116 forks source link

start_cap and end_cap appear to only use the first cap #316

Closed billdenney closed 2 years ago

billdenney commented 2 years ago

It appears that start_cap and end_cap only use the first cap value and not all cap values. In the example below, the arrows appear to all point as though they were offset by the "SC" node instead of the current node.

library(tidygraph)
#> Warning: package 'tidygraph' was built under R version 4.1.3
#> 
#> Attaching package: 'tidygraph'
#> The following object is masked from 'package:stats':
#> 
#>     filter
library(ggraph)
#> Loading required package: ggplot2
#> Warning: package 'ggplot2' was built under R version 4.1.3

nodes <-
  data.frame(
    nodes_key=c("SC", "Central", "Peripheral", "Linear Clearance", "Michaelis-Menten\nClearance"),
    x=c(0, 0, 1, -0.5, 0.5),
    y=c(1, 0, 0, -1, -1)
  )
edges <-
  data.frame(
    from=c("SC", "Central", "Peripheral", "Central", "Central"),
    to=c("Central", "Peripheral", "Central", "Linear Clearance", "Michaelis-Menten\nClearance")
  )
structure_graph <-
  tbl_graph(nodes=nodes, edges=edges)
ggraph(structure_graph, layout="manual", x=nodes$x, y=nodes$y) +
  geom_edge_link(
    aes(start_cap=label_rect(from, padding=margin(0.25, 0.25, 0.25, 0.25, "lines")),
        end_cap=label_rect(to, padding=margin(0.25, 0.25, 0.25, 0.25, "lines"))
    ),
    arrow=grid::arrow()
  ) +
  geom_node_label(aes(label=nodes_key))

Created on 2022-06-11 by the reprex package (v2.0.1)

billdenney commented 2 years ago

As I worked at this more, I think that it is a user error. Setting the start_cap and end_cap as part of the edge data before creating the plot fixed it. Is that the expected behavior or is it something that should be fixed?

library(tidygraph)
#> Warning: package 'tidygraph' was built under R version 4.1.3
#> 
#> Attaching package: 'tidygraph'
#> The following object is masked from 'package:stats':
#> 
#>     filter
library(ggraph)
#> Loading required package: ggplot2
#> Warning: package 'ggplot2' was built under R version 4.1.3

nodes <-
  data.frame(
    nodes_key=c("SC", "Central", "Peripheral", "Linear Clearance", "Michaelis-Menten\nClearance"),
    x=c(0, 0, 1, -0.5, 0.5),
    y=c(1, 0, 0, -1, -1)
  )
edges <-
  data.frame(
    from=c("SC", "Central", "Peripheral", "Central", "Central"),
    to=c("Central", "Peripheral", "Central", "Linear Clearance", "Michaelis-Menten\nClearance")
  )
edges$scap <- label_rect(edges$from, padding=margin(0.25, 0.25, 0.25, 0.25, "lines"))
edges$ecap <- label_rect(edges$to, padding=margin(0.25, 0.25, 0.25, 0.25, "lines"))
structure_graph <-
  tbl_graph(nodes=nodes, edges=edges)
ggraph(structure_graph, layout="manual", x=nodes$x, y=nodes$y) +
  geom_edge_link(
    aes(start_cap=scap,
        end_cap=ecap
    ),
    arrow=grid::arrow()
  ) +
  geom_node_label(aes(label=nodes_key))

Created on 2022-06-11 by the reprex package (v2.0.1)

thomasp85 commented 2 years ago

The issue is that tbl_graph converts from and to to integers when you create your graph so those are no longer your names. As a rule, from and to is always integers pointing to the index when working with tidygraph

You can get the expected result by correctly referencing the node names

nodes <-
    data.frame(
        nodes_key=c("SC", "Central", "Peripheral", "Linear Clearance", "Michaelis-Menten\nClearance"),
        x=c(0, 0, 1, -0.5, 0.5),
        y=c(1, 0, 0, -1, -1)
    )
edges <-
    data.frame(
        from=c("SC", "Central", "Peripheral", "Central", "Central"),
        to=c("Central", "Peripheral", "Central", "Linear Clearance", "Michaelis-Menten\nClearance")
    )
structure_graph <-
    tbl_graph(nodes=nodes, edges=edges)
ggraph(structure_graph, layout="manual", x=nodes$x, y=nodes$y) +
    geom_edge_link(
        aes(start_cap=label_rect(node1.nodes_key, padding=margin(0.25, 0.25, 0.25, 0.25, "lines")),
            end_cap=label_rect(node2.nodes_key, padding=margin(0.25, 0.25, 0.25, 0.25, "lines"))
        ),
        arrow=grid::arrow()
    ) +
    geom_node_label(aes(label=nodes_key))