0

This is a follow up to a similar post.

I have the same issue, but when knitting to HTML from R Markdown. With the solution kindly posted by @CJYetman, I was able to get the correct size for my sankey but only for the first one.

I tried adding the onRender and updating the number in square brackets each time, but I must be doing something wrong. Here's the full R Markdown code (only the 1st chart renders when knitted to HTML):

---
title: "test"
author: "CS"
date: "02/08/2018"
output:
  html_document: default
  pdf_document: default
---

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

```{r}
library(htmlwidgets)
library(networkD3)
library(magrittr)

nodes = data.frame("name" = factor(as.character(1:9)),
                   "group" = as.character(c(1,2,2,3,3,4,4,4,4)))

links = as.data.frame(matrix(byrow = T, ncol = 3, c(
  0, 1, 1400,
  0, 2, 18600,
  1, 3, 400,
  1, 4, 1000,
  3, 5, 100,
  3, 6, 40,
  3, 7, 20,
  3, 8, 4
)))
names(links) = c("source","target","value")

links
```

this chart works fine in firefox:
```{r}
sn1 <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source", 
                    Target = "target", Value = "value", NodeID = "name", 
                    NodeGroup = "group", fontSize = 12)

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

but this one doesn't display at all when knitted:
```{r}
sn2 <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source", 
                    Target = "target", Value = "value", NodeID = "name", 
                    NodeGroup = "group", fontSize = 12, sinksRight = FALSE)

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

and neither does this one:
```{r}
sn3 <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source", 
                    Target = "target", Value = "value", NodeID = "name", 
                    NodeGroup = "group", fontSize = 12, sinksRight = FALSE)

htmlwidgets::onRender(sn3, 'document.getElementsByTagName("svg")[2].setAttribute("viewBox", "")')
```
CJ Yetman
  • 8,373
  • 2
  • 24
  • 56
chrisjacques
  • 635
  • 1
  • 5
  • 17

1 Answers1

1

1) Only use the htmlwidgets::onRender() function once, otherwise it's less clear when the JavaScript will run and what other elements will or will not exist when they run.

2) In the htmlwidgets::onRender() function (ideally run when the last sankeyNetwork is rendered) remove the viewbox from each of the rendered sankeyNetworks.

3) In order to run multiple JavaScript commands using the htmlwidgets::onRender() function, wrap all of the commands in a (JavaScript) function

---
title: "test"
author: "CS"
date: "02/08/2018"
output:
  html_document: default
pdf_document: default
---

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

```{r}
library(htmlwidgets)
library(networkD3)
library(magrittr)

nodes = data.frame("name" = factor(as.character(1:9)),
                   "group" = as.character(c(1,2,2,3,3,4,4,4,4)))

links = as.data.frame(matrix(byrow = T, ncol = 3, c(
  0, 1, 1400,
  0, 2, 18600,
  1, 3, 400,
  1, 4, 1000,
  3, 5, 100,
  3, 6, 40,
  3, 7, 20,
  3, 8, 4
)))
names(links) = c("source","target","value")

links
```

this chart works fine in firefox:
  ```{r}
sn1 <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source",
                     Target = "target", Value = "value", NodeID = "name",
                     NodeGroup = "group", fontSize = 12)

sn1
```

but this one doesn't display at all when knitted:
```{r}
sn2 <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source",
                    Target = "target", Value = "value", NodeID = "name",
                    NodeGroup = "group", fontSize = 12, sinksRight = FALSE)

sn2
```

and neither does this one:
```{r}
sn3 <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source",
                    Target = "target", Value = "value", NodeID = "name",
                    NodeGroup = "group", fontSize = 12, sinksRight = FALSE)

htmlwidgets::onRender(sn3, jsCode =
        'function(){
          document.getElementsByTagName("svg")[0].setAttribute("viewBox", "");
          document.getElementsByTagName("svg")[1].setAttribute("viewBox", "");
          document.getElementsByTagName("svg")[2].setAttribute("viewBox", "");
        }')
```

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") }')
CJ Yetman
  • 8,373
  • 2
  • 24
  • 56