Shiny中如何将reactiveValues作为参数传入ggplot?
如何在Shiny中正确将reactiveValues传入ggplot?
问题重现
使用reactiveValues存储数据并传入ggplot时触发错误,错误代码如下:
library(shiny) library(tidyverse) ui <- fluidPage( sidebarPanel( actionButton('getdata', 'Get Data') ), mainPanel( plotOutput('plot', brush = brushOpts(id = 'brush'), dblclick = 'dclick') ) ) server <- function(input, output, session) { dat <- reactiveValues(val = NULL) dat$val <- eventReactive(input$getdata, { tibble('BusDate' = Sys.Date() - 0:10, 'Val' = rnorm(11)) }) output$plot <- renderPlot({ ggplot(dat$val, aes(x = BusDate, y = Val)) + geom_line() }) } shinyApp(ui, server)
运行后报错:
Error in ggplot: You're passing a function as global data.Have you misspelled the
dataargument inggplot()
而改用reactiveVal结合eventReactive的写法可正常运行:
library(shiny) library(tidyverse) ui <- fluidPage( sidebarPanel( actionButton('getdata', 'Get Data') ), mainPanel( plotOutput('plot', brush = brushOpts(id = 'brush'), dblclick = 'dclick') ) ) server <- function(input, output, session) { dat <- eventReactive(input$getdata, { tibble('BusDate' = Sys.Date() - 0:10, 'Val' = rnorm(11)) }) output$plot <- renderPlot({ ggplot(dat(), aes(x = BusDate, y = Val)) + geom_line() }) } shinyApp(ui, server)
错误原因
错误写法中,dat$val被赋值为eventReactive返回的反应式函数对象,而非直接的数据框。ggplot接收的是函数而非数据,因此触发报错。而reactiveVal的写法中,通过dat()调用反应式函数获取实际数据,所以能正常绘图。
正确解决方案
方案一:用observeEvent直接给reactiveValues赋值数据
reactiveValues的设计初衷是存储值而非反应式函数,因此更合理的写法是用observeEvent响应按钮点击,直接将生成的数据框赋值给dat$val:
library(shiny) library(tidyverse) ui <- fluidPage( sidebarPanel( actionButton('getdata', 'Get Data') ), mainPanel( plotOutput('plot', brush = brushOpts(id = 'brush'), dblclick = 'dclick') ) ) server <- function(input, output, session) { dat <- reactiveValues(val = NULL) # 用observeEvent响应按钮,直接赋值数据框 observeEvent(input$getdata, { dat$val <- tibble('BusDate' = Sys.Date() - 0:10, 'Val' = rnorm(11)) }) output$plot <- renderPlot({ # 确保数据存在后再绘图,避免空值报错 req(dat$val) ggplot(dat$val, aes(x = BusDate, y = Val)) + geom_line() }) } shinyApp(ui, server)
方案二:保留eventReactive,调用时加()获取数据
如果一定要在reactiveValues中存储反应式函数对象,需要在使用时通过()调用它来获取实际数据:
library(shiny) library(tidyverse) ui <- fluidPage( sidebarPanel( actionButton('getdata', 'Get Data') ), mainPanel( plotOutput('plot', brush = brushOpts(id = 'brush'), dblclick = 'dclick') ) ) server <- function(input, output, session) { dat <- reactiveValues(val = NULL) dat$val <- eventReactive(input$getdata, { tibble('BusDate' = Sys.Date() - 0:10, 'Val' = rnorm(11)) }) output$plot <- renderPlot({ # 调用反应式函数获取数据,并用req确保数据存在 req(dat$val()) ggplot(dat$val(), aes(x = BusDate, y = Val)) + geom_line() }) } shinyApp(ui, server)
注意事项
reactiveValues适合存储需要随时修改的值,而eventReactive/reactive返回的是反应式函数,两者用途不同,尽量不要混淆存储。- 绘图前用
req()检查数据是否存在,可避免数据未加载时的空值报错。
内容的提问来源于stack exchange,提问作者hjw
相关产品推荐
相关产品推荐

