Search code examples
rr-markdownblogdownhtmlwidgetsnetworkd3

Sankey Network (within R blogdown) won't render properly on Firefox


My blogdown sites (including plots, markdown, etc.) typically render fine on both Chrome and Firefox. Incidentally they usually work fine on IE as well, although I don't care as much about that browser. I'll include it in the discussion for completeness.

When I include a Sankey Network in blogdown utilizing the networkD3 R package things render 'properly' in Chrome and IE, but not in Firefox. Firefox artificially shrinks the size of the Sankey Network, see below:

enter image description here

Here's the code I'm using. Is there anything I can do to get the Sankey Network to render properly on Firefox, when using Sankey Networks with blogdown?

I did mess around with {r, fig.width=x, fig.height=y}. Increasing x and y increases the overall image size, while keeping the overall image in the same 'small' blogdown box, effectively decreasing the Sankey Network size even further than shown above. Decreasing x and y just decreases the image size, also making the Sankey Network smaller than shown above. I think I need to fix the rendering issue (present in Firefox, not present in Chrome).

---
title: "Data Analysis"
date: "2019-01-01T18:00:00-09:00"
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(tidyverse)
library(blogdown)
library(networkD3)
```

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

```{r sankey, echo=FALSE, error=FALSE, message=FALSE, warning=FALSE}
source <- c("A", "A", "B", "C", "D", "D", "E", "E")
target <- c("D", "E", "E", "D", "H", "I", "I", "H")
values <- c(1, 22, 5, 5, 5, 10, 10, 10)
nodes <- data.frame(name = unique(c(source, target)))
links <- data.frame(source = match(source, nodes$name) - 1,
                    target = match(target, nodes$name) - 1,
                    value = values)
sankeyNetwork(Links = links, Nodes = nodes, Source = "source", 
              Target = "target", Value = "value", NodeID = "name", 
              units = "unitX", fontSize = 12, nodeWidth = 20)
```

[EDIT] I've updated my code as shown below, based on this previous SO question. However, it still renders 'small' with no apparent change :(

---
title: "Data Analysis"
date: "2019-01-01T18:00:00-09:00"
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(tidyverse)
library(blogdown)
library(networkD3)
```

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

```{r sankey, echo=FALSE, error=FALSE, message=FALSE, warning=FALSE}
source <- c("A", "A", "B", "C", "D", "D", "E", "E")
target <- c("D", "E", "E", "D", "H", "I", "I", "H")
values <- c(1, 22, 5, 5, 5, 10, 10, 10)
nodes <- data.frame(name = unique(c(source, target)))
links <- data.frame(source = match(source, nodes$name) - 1,
                    target = match(target, nodes$name) - 1,
                    value = values)

sn <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source", 
                    Target = "target", Value = "value", NodeID = "name", 
                    units = "unitX", fontSize = 12, nodeWidth = 20)

htmlwidgets::onRender(sn, 'document.getElementsByTagName("svg")[0].setAttribute("viewBox", "")')

# also tried this to no avail
# htmlwidgets::onRender(sn, 'document.getElementById().getElementsByTagName("svg")[0].setAttribute()')            
```

Solution

  • Based on the discussion in the Github issue, it seems the solution was to set the proper index number of the sankey plot in the htmlwidgets::onRender command.

    So if the sankey plot is the first SVG on the page, the command should be:

    htmlwidgets::onRender(sn, 'document.getElementsByTagName("svg")[0].setAttribute("viewBox", "")')
    

    If the sankey plot is the second SVG on the page, the command should be:

    htmlwidgets::onRender(sn, 'document.getElementsByTagName("svg")[1].setAttribute("viewBox", "")')
    

    and so forth


    UPDATE 2020.04.02

    My currently preferred method to do this is to use htmlwidgets::onRender to target specifically the SVG contained by the passed htmlwidget, like this...

    onRender(sn, 'function(el) { el.querySelector("svg").removeAttribute("viewBox") }')
    

    That can then be done specifically to as many htmlwidgets on your page as necessary, for instance...

    onRender(sn, 'function(el) { el.querySelector("svg").removeAttribute("viewBox") }')
    
    onRender(sn2, 'function(el) { el.querySelector("svg").removeAttribute("viewBox") }')