rich-iannone / DiagrammeR

Graph and network visualization using tabular data in R
https://rich-iannone.github.io/DiagrammeR/
Other
1.68k stars 247 forks source link

Update the logic of edge attribute generation #521

Open fenguoerbian opened 3 months ago

fenguoerbian commented 3 months ago

Previously, edge attribute is generated based on whether colnames(edges_df)[j] is in selected attributes and the content for current edge edges_df[i, j] is valid.

The checks on edges_df[i, j] is whether it is NA or not empty string. But this logic is not closed since edges_df[i, j] can be empty string (''). This is possible since in previous code in generate_dot(), empty attributes have been set to empty string, not NA. This will lead to some bad behavior:

  1. If the 1st edge does not have attributes set, this function will throw a "object 'attribute' not found" error. #440

  2. If the previous edge has some attributes set while latters don't, then the previous attributes will be carried over to latter edges since attribute is not properly set to NULL at the beginning for each edge. e.g.

library(DiagrammeR)

graph <- create_graph() %>%
    add_n_nodes(n = 3) %>%
    add_edge(from = 1, to = 2, edge_aes = edge_aes(label = "a")) %>%
    add_edge(from = 2, to = 3)

graph %>%
    generate_dot() %>%
    cat()
#> digraph {
#> 
#> graph [layout = 'neato',
#>        outputorder = 'edgesfirst',
#>        bgcolor = 'white']
#> 
#> node [fontname = 'Helvetica',
#>       fontsize = '10',
#>       shape = 'circle',
#>       fixedsize = 'true',
#>       width = '0.5',
#>       style = 'filled',
#>       fillcolor = 'aliceblue',
#>       color = 'gray70',
#>       fontcolor = 'gray50']
#> 
#> edge [fontname = 'Helvetica',
#>      fontsize = '8',
#>      len = '1.5',
#>      color = 'gray80',
#>      arrowsize = '0.5']
#> 
#>   '1'
#>   '2'
#>   '3'
#> '1'->'2' [label = 'a'] 
#> '2'->'3' [label = 'a'] 
#> }

This patch adds a new check for edges_df[i, j] being empty string to fix this loop hole.