首页 > 解决方案 > 渲染绘图列表时出现 renderPlot 问题

问题描述

我正在编写一个 R 闪亮的应用程序,它应该允许用户创建一些数据的可定制图。这个想法是我的应用程序提供了一个“创建新情节”按钮,它可以渲染情节并将其存储在反应式中。renderUI 函数“监视”此列表并呈现该响应式中的所有绘图。

我发现了几个相关的问题r-markdown-shiny-renderplot-list-of-plots-from-lapplyshiny-r-renderplots-on-the-fly但这对我的情况并没有真正的帮助。我希望我没有在某个地方错过一个好的答案(我认为这是因为我认为这不是一个罕见的用例)。

实施时,我注意到一个奇怪的行为:当只有一个情节要显示时,一切正常。但是,当我有 n (n>1) 个绘图时,应用程序只显示 n 次绘图 n,而不是渲染绘图 1、绘图 2、...、绘图 n。

请参阅下面的示例应用程序。我通过让用户选择要显示的绘图数量来简化问题。然后,renderUI 函数有一个循环,在变量 p 中创建这些图,然后调用 renderPlot(p)。我假设闪亮会进行一些缓存,并且由于某种原因无法识别循环中的 p 变化?!

我通过用 do.call("renderPlot", list(expr = p) 替换 renderPlot(p) 找到了一种解决方法。这可以完成工作,但我仍然很想知道为什么直接 renderPlot 不起作用。

这是我的示例应用程序:

library(shiny)
library(ggplot2)


# Define UI
ui <- shinyUI(fluidPage(
  titlePanel("renderPlot Test"),

  sidebarLayout(
    sidebarPanel(
      numericInput(inputId = "n", label = "Number of Plots", value = 1L, min = 1L, max = 5L, step = 1L),
      checkboxInput(inputId = "use_do.call", label = "use 'do.call'", value = FALSE)
    ),

    mainPanel(
      uiOutput("show_plots")
    )
  )
))

# Define server logic
server <- shinyServer(function(input, output) {

  output$show_plots <- renderUI({
    ui <- tags$div(tags$h4("Plots"))

    for( i in 1:input$n ) {
      p <- ggplot() + ggtitle(paste("plot", i))
      if( input$use_do.call ) { # this works
        ui <- tagAppendChild(ui, do.call("renderPlot", args=list(expr=p, width = 200, height = 200)))
      } else {                  # this doesn't ...
        ui <- tagAppendChild(ui, renderPlot(p, width = 200, height = 200))
      }
    }
    return(ui)
  })
})

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

标签: rggplot2shiny

解决方案


我同意@JonMinton,我也遇到了同样的问题。我发现当我重用相同的变量来保存绘图并渲染它们(例如你对 p 所做的事情)时,绘图会被下一个绘图覆盖,并且只有最终绘图会像你说的那样被复制 n 次。

为了解决这个问题,我为每个地块定义了一个新变量,这对于您的项目可能不可持续,但它是一种解决方法。


推荐阅读