rsankey-diagramhtmlwidgetsnetworkd3webshot

I used htmlwidgets::onRender to add numbers to a sankey network, but the numbers do not seem to be appear after saving the plot as png


I was following this guide and tried using htmlwidgets::onRender to add numbers next to node labels. It displays the change in an html file with no problem, but then when I tried saving it as png, the numbers seem to disappear. I was using webshot::webshot to save the screenshot of the plot as png from the html file, and I suspect maybe this is causing the issue? Any help would be much appreciated!

saved as html using networkD3::saveNetwork: enter image description here

saved as png using webshot::webshot: enter image description here

code:

library(networkD3)

# prepare data
links <- data.frame(
  source = c("group_A","group_A", "group_B", "group_C", "group_C", "group_E"), 
  target = c("group_C","group_D", "group_E", "group_F", "group_G", "group_H"), 
  value = c(2,3, 2, 3, 1, 3)
)

nodes <- data.frame(
  name = c(as.character(links$source), as.character(links$target)) |> unique()
)

links$IDsource <- match(links$source, nodes$name) - 1
links$IDtarget <- match(links$target, nodes$name) - 1

# sankey network
sankey = sankeyNetwork(Links = links,
                       Nodes = nodes,
                       Source = "IDsource",
                       Target = "IDtarget",
                       Value = "value",
                       NodeID = "name",
                       fontSize = 20)

# display values
js_string <-
  '
  function(el, x){
    d3.select(el).selectAll(".node text")
      .text(d => d.name + " (n = " + d.value + ")");
  }
  '
sankey <- htmlwidgets::onRender(sankey, js_string)

# save plot
saveNetwork(sankey, "sn.html")

# save as png
webshot::webshot("sn.html", "sn.png")

Solution

  • The issue is with the PhantomJS browser that webshot relies on, which is not actively maintained and archived as-is years ago. See here. If you use webshot2 instead, it produces your expected output. Not sure what the exact cause is, however.

    library(networkd3) 
    library(webshot2)
    
    # prepare data
    links <- data.frame(
      source = c("group_A","group_A", "group_B", "group_C", "group_C", "group_E"), 
      target = c("group_C","group_D", "group_E", "group_F", "group_G", "group_H"), 
      value = c(2,3, 2, 3, 1, 3)
    )
    
    nodes <- data.frame(
      name = c(as.character(links$source), as.character(links$target)) |> unique()
    )
    
    links$IDsource <- match(links$source, nodes$name) - 1
    links$IDtarget <- match(links$target, nodes$name) - 1
    
    # sankey network
    sankey = sankeyNetwork(Links = links,
                           Nodes = nodes,
                           Source = "IDsource",
                           Target = "IDtarget",
                           Value = "value",
                           NodeID = "name",
                           fontSize = 20)
    
    # display values
    js_string <-
      '
      function(el, x){
        d3.select(el).selectAll(".node text")
          .text(d => d.name + " (n = " + d.value + ")");
      }
      '
    sankey <- htmlwidgets::onRender(sankey, js_string)
    
    # save plot
    saveNetwork(sankey, "sn.html")
    
    # save as png
    webshot2::webshot("sn.html", "sn.png")