【问题标题】:Tiny plot output from sankeyNetwork (NetworkD3) in FirefoxFirefox 中 sankeyNetwork (NetworkD3) 的小图输出
【发布时间】:2018-12-11 05:23:15
【问题描述】:

根据对象,当在 中使用sankeyNetwork() 中的sankeyNetwork() 时,我在 Firefox 中得到一个非常小的图,但在 Chrome 或 RStudio 中没有。

我没有在脚本中包含任何 CSS 或 JS - 下面的代码为我生成了这个结果。

有没有我遗漏的 CSS 属性?

我正在使用 R 3.4.1、闪亮的 1.1.0、networkD3 0.4 和 Firefox 52.9.0。

火狐:

铬:

library(shiny)
library(magrittr)
library(shinydashboard)
library(networkD3)

labels = as.character(1:9)
ui <- tagList(
  dashboardPage(
    dashboardHeader(
      title = "appName"
    ),
    ##### dasboardSidebar #####
    dashboardSidebar(
      sidebarMenu(
        id = "sidebar",
        menuItem("plots",
                 tabName = "sPlots")
      )
    ),
    ##### dashboardBody #####
    dashboardBody(
      tabItems(
        ##### tab #####
        tabItem(
          tabName = "sPlots",
          tabsetPanel(
            tabPanel(
              "Sankey plot",
              fluidRow(
                box(title = "title",
                    solidHeader = TRUE, collapsible = TRUE, status = "primary",
                    sankeyNetworkOutput("sankeyHSM1")
                )
              )
            )
          )
        )
      )
    )
  )
)

server <- function(input, output, session) {

  HSM = matrix(rep(c(10000, 700, 10000-700, 200, 500, 50, 20, 10, 2,40,10,10,10,10),4),ncol = 4)
  sankeyHSMNetworkFun = function(x,ndx) {
    nodes = data.frame("name" = factor(labels, levels = labels),
                       "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, NA,
      0, 2, NA,
      1, 3, NA,
      1, 4, NA,
      3, 5, NA,
      3, 6, NA,
      3, 7, NA,
      3, 8, NA
    )))
    links[,3] = HSM[2:(nrow(links)+1),] %>% {rowSums(.[,(ndx-1)*2+c(1,2)])}
    names(links) = c("source","target","value")
    sankeyNetwork(Links = links, Nodes = nodes, Source = "source", Target = "target", Value = "value", NodeID = "name",NodeGroup = "group",
                  fontSize=12,sinksRight = FALSE)
  }
  output$sankeyHSM1 = renderSankeyNetwork({
    sankeyHSMNetworkFun(values$HSM,1)
  })
}

# Run the application
shinyApp(ui = ui, server = server)

------------------ 编辑 --------------------

感谢@CJYetman 指出onRender() 是一种可能的解决方案-但是,当下面的MRE 中并排生成两个图时,这将失败(请注意,除了第二个sankey 图之外,我还添加了javascript 代码当窗口大小发生变化时重新绘制图形,因为绘图似乎不会自动执行。

library(shiny)
library(magrittr)
library(shinydashboard)
library(networkD3)
library(htmlwidgets)

labels = as.character(1:9)
ui <- tagList(
  tags$head(
    tags$script('
var dimension = [0, 0];
$(document).on("shiny:connected", function(e) {
    dimension[0] = window.innerWidth;
    dimension[1] = window.innerHeight;
    Shiny.onInputChange("dimension", dimension);
});
$(window).resize(function(e) {
    dimension[0] = window.innerWidth;
    dimension[1] = window.innerHeight;
    Shiny.onInputChange("dimension", dimension);
});
                            ')
  ),
  dashboardPage(
    dashboardHeader(
      title = "appName"
    ),
    ##### dasboardSidebar #####
    dashboardSidebar(
      sidebarMenu(
        id = "sidebar",
        menuItem("plots",
                 tabName = "sPlots")
      )
    ),
    ##### dashboardBody #####
    dashboardBody(
      tabItems(
        ##### tab #####
        tabItem(
          tabName = "sPlots",
          tabsetPanel(
            tabPanel(
              "Sankey plot",
              fluidRow(
                box(title = "title",
                    solidHeader = TRUE, collapsible = TRUE, status = "primary",
                    sankeyNetworkOutput("sankeyHSM1")
                ),
                box(title = "plot2",
                    solidHeader = TRUE, collapsible = TRUE, status = "primary",
                    sankeyNetworkOutput("sankeyHSM2"))
              )
            )
          )
        )
      )
    )
  )
)

server <- function(input, output, session) {

  HSM = matrix(rep(c(10000, 700, 10000-700, 200, 500, 50, 20, 10, 2,40,10,10,10,10),4),ncol = 4)
  sankeyHSMNetworkFun = function(x,ndx) {
    nodes = data.frame("name" = factor(labels, levels = labels),
                       "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, NA,
      0, 2, NA,
      1, 3, NA,
      1, 4, NA,
      3, 5, NA,
      3, 6, NA,
      3, 7, NA,
      3, 8, NA
    )))
    links[,3] = HSM[2:(nrow(links)+1),] %>% {rowSums(.[,(ndx-1)*2+c(1,2)])}
    names(links) = c("source","target","value")
    sankeyNetwork(Links = links, Nodes = nodes, Source = "source", Target = "target", Value = "value", NodeID = "name",NodeGroup = "group",
                  fontSize=12,sinksRight = FALSE)
  }
  output$sankeyHSM1 = renderSankeyNetwork({
    req(input$dimension)
    sankeyHSMNetworkFun(values$HSM,1) %>%
      onRender('document.getElementsByTagName("svg")[0].setAttribute("viewBox", "")')
  })
  output$sankeyHSM2 = renderSankeyNetwork({
    req(input$dimension)
    sankeyHSMNetworkFun(values$HSM,2) %>%
      onRender('document.getElementsByTagName("svg")[0].setAttribute("viewBox", "")')
  })
}

# Run the application
shinyApp(ui = ui, server = server)

-------------------- EDIT2 --------

解决了上面的第二个问题 - 或者通过使用document.getElementsByTagName("svg")[1].setAttribute("viewBox","") 参考下面@CJYetman 的评论来引用页面上的第二个 svg 项目,或者通过使用 document.getElementById("sankeyHSM2").getElementsByTagName("svg")[0].setAttribute("viewBox","") 进入对象本身选择它们的第一个 svg 元素。

【问题讨论】:

    标签: networkd3 shiny r shiny sankey-diagram htmlwidgets networkd3


    【解决方案1】:

    这似乎是 Firefox 对viewbox svg 属性的反应与其他浏览器不同的结果。将其作为问题在这里提交https://github.com/christophergandrud/networkD3/issues

    可能是值得的

    与此同时,您可以通过使用一些 JavaScript 和 htmlwidgets::onRender() 重置 viewbox 属性来解决此问题。这是一个使用示例的最小化版本的示例。 (重置viewbox属性可能会产生其他后果)

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

    更新(2019.10.26)

    这可能是移除 viewBox 的更安全的实现方式...

    htmlwidgets::onRender(sn, 'function(el) { el.getElementsByTagName("svg")[0].removeAttribute("viewBox") }')
    

    更新 2020.04.02

    我目前首选的方法是使用 htmlwidgets::onRender 专门针对传递的 htmlwidget 包含的 SVG,如下所示...

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

    然后可以根据需要专门针对您页面上尽可能多的htmlwidgets,例如...

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

    【讨论】:

    • 感谢@CJYetman - 当页面上有一个图表时效果很好,但当有两个图表时会失败,有什么想法吗?我正在用 MRE 编辑上面的问题
    • 将 JavaScript 行中的 [0] 更改为 [1] 以选择第二个 svg。复制整个 JacaScript 行并适当设置数字以影响多个 svg(在 JavaScript 命令之间使用 ;
    • 刚刚设法通过使用document.getElementById().getElementsByTagName("svg")[0].setAttribute() 解决了这个问题,这就像一个魅力。非常感谢!
    • 我正在尝试在 blogdown 中使用@CJ Yetman 解决方案,但在我的情况下它不起作用:(
    • 感谢@CJYetman 指出这个解决方案。在rmarkdown 中,这也可以很好地用作自定义函数的最后一行,以使用lapply 从 dfs 列表中创建多个 sankey 图。例如list_sn &lt;- lapply (list_dfs, function(x) {'functional arguments defining sn ending with:' onRender(sn, 'function(el) { el.querySelector("svg").removeAttribute("viewBox") }')}) 和使用list_sn[[i]] 的后续输出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-04
    • 2016-06-19
    • 1970-01-01
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多