我有一个我不明白的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
}
})
)
答案 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
})
})
可以像这样生成输出节点。但我确实想知道你是否过于聪明,就像这样重命名数据列和输出节点。你为什么要那样做?