Shiny处理reactive dataframe报invalid (NULL)赋值错误
报错原因
你遇到的invalid (NULL) left side of assignment报错由两个问题直接引发:
- Shiny中通过
reactive()生成的响应式对象是只读的,每次调用reactiveDf()只会返回计算好的结果副本,你不能直接对这个返回的临时副本做赋值操作,这类赋值本身不符合Shiny响应式规则。 - 代码中
reactiveDf()[i]="Insignificant"的写法是对数据框的第i列做整列赋值,而非对行赋值;当循环的i值超过数据框总列数时,索引到的位置为NULL,就触发了左值无效的报错。
修复方法
- 在绘图逻辑中,先把
reactiveDf()的返回值存为普通的非响应式数据框变量,所有修改操作都针对这个普通变量执行,不要直接改reactive的返回结果。 - 修正数据框索引逻辑,给行赋值时明确指定行列位置,避免单索引默认取列的问题。
- 补全绘图的返回逻辑,生成ggplot对象后要转为plotly并返回,否则图表无法渲染。
修正后完整代码
library(shiny) library(shinydashboard) library(plotly) library(tidyr) library(dplyr) library(DT) BRAND<-c("CHOKIS","CHOKIS","CHOKIS","CHOKIS","CHOKIS","CHOKIS","LARA CHOCO CHIPS","LARA CHOCO CHIPS","LARA CHOCO CHIPS") BRAND_COLOR<-c("#8050f0","#8050f0","#8050f0","#8050f0","#8050f0","#8050f0","#f050c0","#f050c0","#f050c0") SellOut.x<-c(23,34,56,77,78,34,34,64,76) SellOut.y<-c(43,54,76,78,87,98,76,76,56) GrossProfit.x1<-c(23,34,56,75,78,34,34,64,76) GrossProfit.y1<-c(33,54,76,76,87,98,76,76,56) GrossSales.x2<-c(53,34,56,77,78,34,34,84,76) GrossSales.y2<-c(63,54,76,78,87,98,76,76,86) r<-c(58,46,76,76,54,21,69,98,98) graph1.data<-data.frame(BRAND,BRAND_COLOR,r) # 待合并的指标数据框 df6 <- data.frame(SellOut.x, SellOut.y, GrossProfit.x1, GrossProfit.y1, GrossSales.x2, GrossSales.y2) ui <- dashboardPage( dashboardHeader(), dashboardSidebar( selectInput("metric","Metric",c('Gross Sales','Gross Profit','Sell Out'),multiple = T,selected = "Sell Out") ), dashboardBody( DTOutput("df"), plotlyOutput("plot") ) ) server <- function(input, output) { choices <- reactive({ c3 <- gsub(" ", "", input$metric) # 移除指标名空格做匹配 return(c3) }) reactiveDf <- reactive({ if(length(choices()) > 0){ # 匹配选中指标对应的列 g1 <- apply(sapply(X = choices(), FUN = grepl, colnames(df6)), MARGIN = 1, FUN = any) addedDf <- df6[, g1] # 提取要添加的指标列 colnames(addedDf) <- c("x", "y", "x1", "y1", "x2", "y2")[1:ncol(addedDf)] # 统一列名 combinedDf <- cbind(graph1.data, addedDf) # 合并基础数据和指标数据 combinedDf$label<-paste(combinedDf$BRAND,"-",input$metric) return(combinedDf) }else{ graph1.data$label<-paste(graph1.data$BRAND,"-",input$metric) return(graph1.data) } }) output$df<-renderDT({ reactiveDf() }) output$plot<-renderPlotly({ req(reactiveDf(), length(input$metric)>=1) metric<-input$metric # 先把响应式数据转成普通变量再修改 plot_df <- reactiveDf() brand.colors <- plot_df$BRAND_COLOR names(brand.colors) <- plot_df$BRAND data<-unique(plot_df$BRAND) ind=which(names(brand.colors) %in% data) if(length(metric) == 1) { for ( i in 1:nrow(plot_df)) { plot_df$BRAND[i]=paste(plot_df$BRAND[i],metric) } if (metric!="Sell Out") { for (i in ind) { brand.colors[i]="gray" # 明确指定行、列索引,避免维度索引错误 plot_df[i, "BRAND"]="Insignificant" } } names(brand.colors) <- plot_df$BRAND p <- plot_df %>% ggplot2::ggplot(aes(x, y, color = BRAND, group=BRAND)) p <- p + ggplot2::geom_line() + suppressWarnings(ggplot2::geom_point(aes(size = r), show.legend = TRUE)) + ggplot2::scale_color_manual(values = brand.colors) # 转成plotly对象返回 ggplotly(p) } }) } shinyApp(ui, server)
内容的提问来源于stack exchange,提问作者firmo23
相关产品推荐
相关产品推荐

