networkD3 icon indicating copy to clipboard operation
networkD3 copied to clipboard

sankey very small with firefox

Open smartinsightsfromdata opened this issue 8 years ago • 29 comments

I have a simple shiny app with a sankey chart. It works on all browsers, but in Firefox is incredibly small to the point of been unusable. Could it be a recent regression?

Mozilla Firefox ESR 38.4.0 on Centos 7. I've given below a snippet of the code and my sessionInfo() details. I've tried to use height and width (see below) as a way to avoid the issue with no luck.

output$sankey <- renderSankeyNetwork({  

networkD3::sankeyNetwork(Links = clink, Nodes = cnodes, Source = "source",
                          Target = "target", Value = "value", NodeID = "id", 
                          colourScale = JS("d3.scale.category20()") , 
                         fontSize = 12, nodeWidth = 30, height = 700, width = 500)
})
sessionInfo()
R version 3.2.2 (2015-08-14)
Platform: x86_64-redhat-linux-gnu (64-bit)
Running under: CentOS Linux 7 (Core)

locale:
 [1] LC_CTYPE=en_GB.UTF-8      
 [2] LC_NUMERIC=C              
 [3] LC_TIME=en_GB.UTF-8       
 [4] LC_COLLATE=en_GB.UTF-8    
 [5] LC_MONETARY=en_GB.UTF-8   
 [6] LC_MESSAGES=en_GB.UTF-8   
 [7] LC_PAPER=en_GB.UTF-8      
 [8] LC_NAME=C                 
 [9] LC_ADDRESS=C              
[10] LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_GB.UTF-8
[12] LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils    
[5] datasets  methods   base     

other attached packages:
 [1] dplyr_0.4.3        networkD3_0.2.7   
 [3] jsonlite_0.9.19    RColorBrewer_1.1-2
 [5] classInt_0.1-23    leaflet_1.0.0     
 [7] data.table_1.9.6   maptools_0.8-37   
 [9] rgeos_0.3-15       rgdal_1.1-1       
[11] sp_1.2-1           shiny_0.12.2      

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.2     magrittr_1.5   
 [3] xtable_1.8-0    lattice_0.20-33
 [5] R6_2.1.1        tools_3.2.2    
 [7] parallel_3.2.2  grid_3.2.2     
 [9] DBI_0.3.1       e1071_1.6-7    
[11] htmltools_0.2.6 class_7.3-13   
[13] yaml_2.1.13     assertthat_0.1 
[15] digest_0.6.8    htmlwidgets_0.5
[17] mime_0.4        httpuv_1.3.3   
[19] foreign_0.8-65  chron_2.3-47  

smartinsightsfromdata avatar Dec 13 '15 14:12 smartinsightsfromdata

I am seeing the same issue in Chrome, Firefox, and Safari when running from a shiny-server instance. This does not show up when the app is started in RStudio.

It looks like the issue is related to how the viewbox is calculated here: https://github.com/christophergandrud/networkD3/blob/master/inst/htmlwidgets/sankeyNetwork.js#L186

The app I'm using modifies the data used to generate the diagram. Sometimes this ends up fine, other times it completely breaks the viewbox calculations and ends up with a tiny diagram.

Removing the viewbox attribute completely solved the issue for me, but lost the dynamic resizing when changing the browser window size. I'm going to try to track down the problem with the calculations, but may just stick with my fix of not using the viewbox at all.

askene avatar Feb 19 '16 19:02 askene

I'm wondering if this might be a race condition and possibly related to this StackOverflow. Unfortunately, I can't reproduce these on my side, so I'm not sure how to debug.

timelyportfolio avatar Feb 23 '16 14:02 timelyportfolio

Can you update to the github version of Shiny and htmlwidgets to make sure these don't cure the problem? I don't remember any changes that would have addressed this problem, but at least we will be able to eliminate this as a potential source of the problem.

timelyportfolio avatar Feb 23 '16 14:02 timelyportfolio

Thinking through this, are there cycles in your network? We added support for cycles in Sankey that could potentially have introduced a regression.

timelyportfolio avatar Feb 23 '16 14:02 timelyportfolio

For reference, this is the code I am using to test.

library(networkD3)
library(shiny)

# simple network with cycles
net_cycles <- list(
  links = data.frame(
    source = c(0,0,0,1,1,5),
    target = c(1,2,3,4,5,0),
    value = 10
  ),
  nodes = data.frame(
    name = letters[1:6]
  )
)

URL <- paste0("https://cdn.rawgit.com/christophergandrud/networkD3/",
              "master/JSONdata/energy.json")
Energy <- jsonlite::fromJSON(URL)

ui <- fluidPage(fluidRow(
  column(6,sankeyNetworkOutput("sankey",height=300)),
  column(6,sankeyNetworkOutput("sankey2",height=300))
))

# notice how few arguments we need now
# some output but not the nice output I expect
server <- function(input,output,session){
  output$sankey <- renderSankeyNetwork({
    invalidateLater(1000)
    sankeyNetwork(
      net_cycles$links,
      net_cycles$nodes,
      Value = "value"
    )
  })

  output$sankey2  <- renderSankeyNetwork({
    invalidateLater(1000)
    sankeyNetwork(Links = Energy$links, Nodes = Energy$nodes, Source = "source",
                  Target = "target", Value = "value", NodeID = "name",
                  units = "TWh", fontSize = 12, nodeWidth = 30)
  })
}

shinyApp(ui,server)

timelyportfolio avatar Feb 23 '16 14:02 timelyportfolio

I upgraded to the latest github versions of htmltools, shiny, and networkD3, but I am still seeing some strange behavior. To clarify, this only shows up when I run the code from the a shiny server instance. Not when I run it out of rstudio. I am running this on the latest shiny-server v 1.4.2 built from github's master branch.

The test code you posted seems to jump around on every refresh. The cycles render fine, but move up and down a lot. The energy diagram grows and shrinks. I added console.log(s.attr("viewBox")) to see the viewBox values on each refresh.

This is what I see for the energy diagram.

-11.399993896484375,-18.649993896484375,625.7000122070312,325.2166748046875 sankeyNetwork.js:221:1
12.600006103515625,-1.5666656494140625,580.2999877929688,303.3500061035156 sankeyNetwork.js:221:1
-8.166671752929688,-17.116668701171875,619.25,322.1000061035156 sankeyNetwork.js:221:1
9.98333740234375,-2.8166656494140625,585.5166625976562,305.8666687011719 sankeyNetwork.js:221:1
-5.75,-15.916671752929688,614.4666748046875,319.8000030517578 sankeyNetwork.js:221:1
8,-3.8166656494140625,589.4500122070312,307.76666259765625 sankeyNetwork.js:221:1
-3.9666595458984375,-14.966659545898438,610.9500122070312,318.0833282470703 sankeyNetwork.js:221:1
6.48333740234375,-4.616668701171875,592.4166259765625,309.183349609375 sankeyNetwork.js:221:1
-2.616668701171875,-14.216659545898438,608.316650390625,316.8333282470703

Shrinking the browser window seems to exacerbates the issue.

-82.96665954589844,5.6666717529296875,563.316650390625,289.0666809082031 sankeyNetwork.js:221:1
92.71665954589844,-24.48333740234375,662.9166870117188,335.8833312988281 sankeyNetwork.js:221:1
-75.96665954589844,35.44999694824219,320.2166748046875,229.75 sankeyNetwork.js:221:1
101.85000610351562,-64.53334045410156,590,412.5 sankeyNetwork.js:221:1
-81.86666870117188,27.899993896484375,346.33331298828125,247.2666778564453 sankeyNetwork.js:221:1
100.14999389648438,-52.21665954589844,551.0499877929688,386.40000915527344 sankeyNetwork.js:221:1
-84.5,21.583328247070312,367.0333251953125,261.1166687011719 sankeyNetwork.js:221:1
96.61666870117188,-43.25,523.933349609375,367.2333526611328 sankeyNetwork.js:221:1
-85.41667175292969,16.433334350585938,384.1000061035156,273.5500030517578 sankeyNetwork.js:221:1
92.98333740234375,-36.55000305175781,501.933349609375,352.5166778564453 sankeyNetwork.js:221:1
-84.89999389648438,12.25,398.4666748046875,283.16668701171875

The initial code that I've got usually ends up with a large negative x offset, which I think is where the shrinking comes from. I'm not sure where in the viewBox calculation things are breaking, but that seems to be the most logical place to fix things.

askene avatar Feb 29 '16 14:02 askene

I tried @timelyportfolio code on my apple mac.

If I display in the browser, and the browser is Firefox, I have the problem (but while the two viz are smaller, they do not seems as small as a single viz would looks like).

I do not seem to have the problem with Chrome though.

smartinsightsfromdata avatar Apr 18 '16 12:04 smartinsightsfromdata

same problem when rendering a Sankey from R Markdown to html: tiny on firefox, fine on chrome and safari... is there a workaround to get to a normal size in firefox...?

ChristelSwift avatar Jul 31 '18 16:07 ChristelSwift

Pretty sure this is caused by the viewbox SVG property. I gave the following solution to a user on Stack Overflow and it satisfied their specific use case. Can you check if some variant of this works in your case as well?

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")

sn <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source", 
                    Target = "target", Value = "value", NodeID = "name", 
                    NodeGroup = "group", fontSize = 12, sinksRight = FALSE)

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

cjyetman avatar Aug 01 '18 19:08 cjyetman

thank you so much! it works great for 1 chart, but i'm having trouble with multiple charts, despite adding the onRender and updating the number in square brackets each time... any idea how to fix this? Here's my code using your data (only the 1st chart renders):

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", "")')

same chart with sinksRight = FALSE:

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", "")')

ChristelSwift avatar Aug 02 '18 08:08 ChristelSwift

You'll have to provide a full, reproducible example, because that works for me.

cjyetman avatar Aug 02 '18 09:08 cjyetman

and technically, these issues are not meant to be used as a support forum, so it may be better to create a question on Stack Overflow

cjyetman avatar Aug 02 '18 10:08 cjyetman

sorry - i'll add it to the existing thread on stackoverflow.

ChristelSwift avatar Aug 02 '18 10:08 ChristelSwift

I basically have the same thing happening as well. I have a Sankey Network I'm using with the R blogdown package. And my Sankey Network also renders fine in Chrome and IE11, but is very small in Firefox. My StackOverflow question can be seen here. I tried @cjyetman previous solution but it doesn't appear to work in my case.

ghost avatar Mar 04 '19 18:03 ghost

@jhuntergit can you put a reprex here to match your comment please? If it’s not the same issue as here, which it sounds like it might not be, then we should open a new issue to figure it out.

cjyetman avatar Mar 04 '19 21:03 cjyetman

I think it's the same issue. The only difference is I'm running this code as an R blogdown site. Here is the code that generates a small Sankey Network, but only in Firefox. In Chrome and IE this same Sankey Network is normal sized.


---
    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)
    ```

ghost avatar Mar 05 '19 03:03 ghost

this works for me (macOS 10.14.3, Firefox 65.0.1)

---
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.

```{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", "")')
```

cjyetman avatar Mar 05 '19 05:03 cjyetman

@jhuntergit can you attach the generated HTML file that you get from running my example code above (the version that has the fix that works on my computer). I'll test if your generated HTML code works on my machine as expected in Firefox and/or if it's the same as the HTML generated on my machine. If our HTML files are the same, then yeah, unfortunately it's a difference between OS and browser environments, which I can't easily investigate. Otherwise, there must be some reason you're getting a different HTML output than I am using the same code.

cjyetman avatar Mar 05 '19 12:03 cjyetman

Will do. I just need to put the request on pause for the next week or so. Currently the site only exists when I serve it through blogdown and R Studio. The static HTML files don't display properly unless served via blogdown within R Studio. When I deploy the site soon, I'll also grab the static HTML and attach here and @ mention you so you'll be aware. Thanks for your patience.

ghost avatar Mar 06 '19 02:03 ghost

@jhuntergit thanks for your willingness, but please do not attach a page from your website here. That doesn’t have any relevance here. Only attach the HTML output from running precisely the above Rmd code, no more, no less. Anything more/other than that will only complicate things and make me waste time investigating it.

cjyetman avatar Mar 06 '19 08:03 cjyetman

@cjyetman I can do that. Do you want the output from my R console? That is simply the block shown below. As I'm building my website I'm serving it locally using the R package blowdown. Or the HTML output I'd get from right clicking and View Page Source within Firefox?


> blogdown::serve_site()
Building sites … 
                   | EN  
+------------------+----+
  Pages            | 21  
  Paginator pages  |  0  
  Non-page files   |  0  
  Static files     | 36  
  Processed images |  0  
  Aliases          |  0  
  Sitemaps         |  1  
  Cleaned          |  0  

Total in 521 ms
To stop the server, run servr::daemon_stop(1) or restart your R session
Serving the directory /home/j/blogdown-website at http://127.0.0.1:4321

ghost avatar Mar 10 '19 15:03 ghost

Definitely don’t want the R console output. Just one HTML file.

Still looks like you’re trying to show me your webpage. I don’t want that. I want the output from my example.

cjyetman avatar Mar 10 '19 21:03 cjyetman

@cjyetman I determined what my issue is. I can run your code block above and it works exactly as expected, BUT, only in isolation. If you look at the same R chunk below, except I added a "radial network" chunk, which neutralizes your htmlwidgets::onRender(sn, 'document.getElementsByTagName("svg")[0].setAttribute("viewBox", "")') solution.

Try and run this code chunk and you'll discover Firefox makes the Sankey Network small again. Why does the "radial network" chunk neutralize your solution? And how do I work around this? Yes, I need to keep the radial network in this R Markdown document. Thanks

*and sorry I can't really get this complete *.Rmd file to format properly on this Github forum, if you copy paste the following into R Studio, then select all, then Shift+Tab to remove the first two spaces it should work within R Studio

---
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)
```

```{r radial network, echo=FALSE, error=FALSE, message=FALSE, warning=FALSE}
nd3 <- list(name = "Start", children = list(list(name = "A",
                                          children = list(list(name = 		"1"),
                                                          list(name = 		"2"),
                                                          list(name = 		"3")
                                                          		)),

                                         		list(name = "B")))
diagonalNetwork(List = nd3, fontSize = 10, opacity = 0.9)
```

Lorem ipsum dolor sit amet.

```{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", "")')
```

ghost avatar Mar 16 '19 02:03 ghost

Great, thanks. I’m on vacation for the next 10 days or so, but this reduced/minimized example is probably exactly what I need to figure it out.

cjyetman avatar Mar 16 '19 05:03 cjyetman

Without being able to try it out myself, I can make a guess already that there should be a [1] instead of a [0] in the JavaScript you’re passing with htmlwidgets::onRender since the diagonal network is probably runs first and would be the first SVG element.

Also please do not refer to the plot produced by diagonalNetwork as a radial network to avoid confusion.

cjyetman avatar Mar 16 '19 06:03 cjyetman

@cjyetman yes - right again! I stepped up [0] sequentially in increments of 1 and the first try everything worked. I'll continue doing that going forward when I am using multiple networkD3 elements in one *.Rmd document. Thank you. Enjoy the vacation. Well deserved.

ghost avatar Mar 16 '19 14:03 ghost

I encountered this same problem today, here's how I fixed it:

Put this code in your Rmd somewhere to loop through and set all the svg's viewBox = null.

htmlwidgets::onStaticRenderComplete('$.each( document.getElementsByTagName("svg"), function( index, value ){value.setAttribute("viewBox", null);});')

gdmcdonald avatar Apr 02 '20 03:04 gdmcdonald

Just be aware that...

htmlwidgets::onStaticRenderComplete('$.each( document.getElementsByTagName("svg"), function( index, value ){value.setAttribute("viewBox", null);});')

requires jQuery and removes the viewBox from every SVG on the page, no matter what they are or where they came from.

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 be done on each htmlwidget necessary, specifically. For example, using an example from above...

library(networkD3)
library(shiny)
library(htmlwidgets)

# simple network with cycles
net_cycles <- list(
  links = data.frame(
    source = c(0,0,0,1,1,5),
    target = c(1,2,3,4,5,0),
    value = 10
  ),
  nodes = data.frame(
    name = letters[1:6]
  )
)

URL <- paste0("https://cdn.rawgit.com/christophergandrud/networkD3/",
              "master/JSONdata/energy.json")
Energy <- jsonlite::fromJSON(URL)

ui <- fluidPage(fluidRow(
  column(6,sankeyNetworkOutput("sankey",height=300)),
  column(6,sankeyNetworkOutput("sankey2",height=300))
))

# notice how few arguments we need now
# some output but not the nice output I expect
server <- function(input,output,session){
  output$sankey <- renderSankeyNetwork({
    invalidateLater(1000)
    sn <- sankeyNetwork(net_cycles$links, net_cycles$nodes, Value = "value")
    onRender(sn, 'function(el) { el.querySelector("svg").removeAttribute("viewBox") }')
  })
  
  output$sankey2  <- renderSankeyNetwork({
    invalidateLater(1000)
    sn2 <- sankeyNetwork(Links = Energy$links, Nodes = Energy$nodes, Source = "source",
                  Target = "target", Value = "value", NodeID = "name",
                  units = "TWh", fontSize = 12, nodeWidth = 30)
    onRender(sn2, 'function(el) { el.querySelector("svg").removeAttribute("viewBox") }')
  })
}

shinyApp(ui,server)

cjyetman avatar Apr 02 '20 08:04 cjyetman

I wanted to add my thanks to @cjyetman and @gdmcdonald. The viewBox property is definitely the issue at hand, and this was the only solution I found to fix it at render.

For completeness, I'll add that if you're saving a stand-alone network to a .HTML file, you can do something like this to take advantage of the fix:

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

saveNetwork(output, path)

chapb avatar Nov 22 '21 13:11 chapb