在Shiny app中创建动态标签集会给ggploty带来错误

时间:2017-04-22 13:52:56

标签: r ggplot2 plotly shiny

我有一个我不明白的Shiny应用程序的问题。我认为这是一个反应性对象的概念问题,但我不确定。

该应用程序使用uiOutput根据数据集列的名称创建一个选项卡。然后我在Observe中动态创建相应的plotlyOutput。

问题在于,当我更改数据集时,它们的列也会更改其名称,并且应用程序似乎记得最后一个入口,并尝试使用不再存在的数据呈现对象。

结果是这样的警告:

  

警告:UseMethod出错:'ggplotly'没有适用的方法   应用于类“NULL”的对象堆栈跟踪(最里面的第一个):       79:ggplotly       78:功能       77:origRenderFunc       76:输出$ tabPlot_a1        1:runApp

我创建了一个Shiny应用程序来重新创建错误,只需打开它,转到选项卡2,然后将“前缀”更改为“b”,例如。

标签发生变化,但会发出警告。

有关正在发生的事情的任何提示?

代码:

library("shiny")
library("shinydashboard")
library("plotly")
library("ggplot2")

shinyApp(
  ui=shinyUI(dashboardPage(skin = "blue",
                           dashboardHeader(title = "Dashboard"),
                           dashboardSidebar(
                             textInput("prefix", label = "Columns prefix", value = "a")
                           ),
                           dashboardBody(
                             tabBox(
                               tabPanel("Tab 1", "This is tab number 1", tableOutput("tabData")),
                               tabPanel("Tab 2", "This is tab number 2", uiOutput("tabPlot"))
                             )
                           )
  ))
  ,
  server=shinyServer(function(input, output) {

    create_data <- reactive({
      x<-seq(-2,2,length.out=100)
      y1<-dnorm(x)
      y2<-dunif(x)
      y3<-dexp(x,2)
      y4<-dbeta(x,1,2)
      data<-data.frame(x,y1,y2,y3,y4)
      names(data)<-c("x",paste(input$prefix,1:4,sep=""))
      data
    })

    output$tabData<-renderTable({
      data<-create_data()
      data
    })

    output$tabPlot = renderUI({
      data <- create_data()
      tabnames<-names(data)[-1]
      do.call(tabsetPanel,
              lapply(tabnames,function(s){
                call("tabPanel",s,call('plotlyOutput',outputId=paste0("tabPlot_",s)))
              })
      )
    })

    observe({
      data <- create_data()
      tabnames<-names(data)[-1]
      lapply(tabnames, function(s){output[[paste0("tabPlot_",as.character(s))]] <- renderPlotly({
        data <- create_data()
        if (as.character(s) %in% names(data)){
          data.plot<-data[c("x",as.character(s))]
          p <- plotthis(data.plot)
          z <- ggplotly(p)          
        }else{
          z<-NULL
        }
        z
      })})
    })

    plotthis<-function(data){
      names(data)<-c("x","y")
      p<-ggplot(data=data,aes(x=x,y=y))+
        geom_line()
      p
    }

  })
)

1 个答案:

答案 0 :(得分:2)

似乎旧的输出节点之一(具有以前的名称)仍然被激活,而你内置的警卫即使看起来应该也没有帮助。我尝试了几种方法来修复它,比如修改输出节点的名称不要更改,或者更改为从data数字中选择列,但最后更简单一些修复它 - 隔离其中一个{ {1}}陈述。这抑制了不需要的输出节点激活。

以下是create_data()的代码 - 当我添加observe时,我没有收到ggplotly NULL警告。请注意,只需要更改一行:

isolate

顺便说一下,我在这篇文章中学到了很多东西,我不知道observe({ data <- create_data() tabnames<-names(data)[-1] lapply(tabnames,function(s){output[[paste0("tabPlot_",as.character(s))]]<-renderPlotly({ data <- isolate(create_data()) if (as.character(s) %in% names(data)){ data.plot<-data[c("x",as.character(s))] p <- plotthis(data.plot) z <- ggplotly(p) }else{ z<-NULL } z }) }) 可以像这样生成输出节点。但我确实想知道你是否过于聪明,就像这样重命名数据列和输出节点。你为什么要那样做?