Search code examples
rsankey-diagram

R networkD3::sankeyNetwork, how to add y-axis labels without losing added elements from htmlwidgets::onRender


I'm trying to add y-axis labels to my sankey network. I managed to add x-axis labels using htmlwidgets::onRender. I tried adding some y-axis labels based on this answer. However, my x-axis labels from earlier disappears after adding the y labels. How do I keep the x labels?

code:

library(networkD3)
library(manipulateWidget)
library(htmltools)
library(htmlwidgets)

# 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 = unique(c(as.character(links$source), as.character(links$target)))
)

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)

# add x-axis labels 
js_string <-
  '
   function(el) {

    var cols_x = this.sankey.nodes()
      .map(d => d.x).filter((v, i, a) => a.indexOf(v) === i)
      .sort(function(a, b){return a - b});

    var labels = ["A", "B", "C" ]

    cols_x.forEach((d, i) => {
      d3.select(el).select("svg")
        .append("text")
        .attr("x", d)
        .attr("y", 12)
        .attr("text-anchor", "start")
        .text(labels[i]);
    })
   }
  '

# original plot
sankey <- onRender(sankey, js_string)
sankey


# try adding y-axis labels
leftTx = tags$div( 
  style="max-width: 30vw; padding-bottom: 15px; height: 100%; display: flex; align-items: center; justify-content: center;", 
  tags$p("This text is on the left side"))
rightTx = tags$p("This text is on the right",
                 style="max-width:30vw")

cS <- combineWidgets(sankey,
                     leftCol = leftTx,
                     rightCol = rightTx)

cS

original diagram

enter image description here

after adding y labels

enter image description here


Solution

  • You could add text to the left and the right within the same custom JavaScript you are using...

    onRender(sankey, jsCode = '
    function(el) {
      var cols_x = this.sankey.nodes()
        .map(d => d.x).filter((v, i, a) => a.indexOf(v) === i)
        .sort(function(a, b){return a - b});
    
      var labels = ["A", "B", "C" ]
    
      cols_x.forEach((d, i) => {
        d3.select(el).select("svg")
          .append("text")
          .attr("x", d)
          .attr("y", 12)
          .attr("text-anchor", "start")
          .text(labels[i]);
      })
      
      d3.select(el).select("svg")
          .append("text")
          .attr("x", 0)
          .attr("y", d3.select(el).select("svg").node().clientHeight / 2)
          .attr("text-anchor", "end")
          .text("text on left");
      
      d3.select(el).select("svg")
          .append("text")
          .attr("x", d3.select(el).select("svg").node().clientWidth)
          .attr("y", d3.select(el).select("svg").node().clientHeight / 2)
          .attr("text-anchor", "start")
          .text("text on right");
    }
    ')
    

    enter image description here