如何在R Shiny中用plotlyProxy添加置信区间带状图不重绘图表
问题:在Shiny中用plotlyProxy实现添加置信区间带状图(而非线条)且不重绘图表
需求是在R Shiny应用中使用plotlyProxy添加置信区间(CI)的带状图,添加时不重绘整个图表,同时要能查看CI的数值,但不清楚如何在plotlyProxyInvoke中对应add_ribbons()的JS方法。
初始绘图代码(实现了带置信区间带状图的静态图表)
library(plotly) month <- c('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December') ci_high_2014 <- c(28.8, 28.5, 37.0, 56.8, 69.7, 79.7, 78.5, 77.8, 74.1, 62.6, 45.3, 39.9) ci_low_2014 <- c(12.7, 14.3, 18.6, 35.5, 49.9, 58.0, 60.0, 58.6, 51.7, 45.2, 32.2, 29.1) data <- data.frame(month, ci_high_2014, ci_low_2014) data$average_2014 <- rowMeans(data[,c("ci_high_2014", "ci_low_2014")]) # 指定月份顺序,避免按字母排序 data$month <- factor(data$month, levels = data[["month"]]) plot_ly() %>% add_trace( data = data, x = ~month, y = ~average_2014, type = 'scatter', mode = 'lines', name = "Average" )%>% add_ribbons( inherit = FALSE, data = data, x = ~month, ymin = ~average_2014, ymax = ~ci_high_2014, name = "CI hi", line = list(color = 'rgba(0, 0, 0, 0)'), fillcolor = 'rgba(255, 0, 0, 0.4)' ) %>% add_ribbons( inherit = FALSE, data = data, x = ~month, ymin = ~average_2014, ymax = ~ci_low_2014, name = "CI lo", line = list(color = 'rgba(0, 0, 0, 0)'), fillcolor = 'rgba(255, 0, 0, 0.4)' ) %>% layout(hovermode = "x unified")
当前实现的代码(仅能添加线条,无法实现带状图)
library(shiny) library(shinyWidgets) library(plotly) month <- c('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December') ci_high_2014 <- c(28.8, 28.5, 37.0, 56.8, 69.7, 79.7, 78.5, 77.8, 74.1, 62.6, 45.3, 39.9) ci_low_2014 <- c(12.7, 14.3, 18.6, 35.5, 49.9, 58.0, 60.0, 58.6, 51.7, 45.2, 32.2, 29.1) data <- data.frame(month, ci_high_2014, ci_low_2014) data$average_2014 <- rowMeans(data[,c("ci_high_2014", "ci_low_2014")]) # 指定月份顺序,避免按字母排序 data$month <- factor(data$month, levels = data[["month"]]) ui <- fluidPage( titlePanel("plotlyProxy add Ribbons"), sidebarLayout( sidebarPanel( materialSwitch(inputId = "ci", label = "Add CI", value = FALSE) ), mainPanel( plotlyOutput(outputId = "plot") ) ) ) server <- function(input, output, session = session){ output$plot <- renderPlotly({ plot_ly() %>% add_trace( data = data, x = ~month, y = ~average_2014, type = 'scatter', mode = 'lines', name = "Average" ) %>% layout(hovermode = "x unified") }) observeEvent(input$ci, { if(input$ci){ plotlyProxy("plot", session = session) %>% plotlyProxyInvoke( method = "addTraces", list( # 疑问:如何在这里指定带状图和ymin/ymax? x = as.list(data$month), y = as.list(data$ci_high_2014), name = "CI high" ) ) %>% plotlyProxyInvoke( method = "addTraces", list( # 疑问:如何在这里指定带状图和ymin/ymax? x = as.list(data$month), y = as.list(data$ci_low_2014), name = "CI low" ) ) }else{ plotlyProxy(outputId = "plot", session) %>% plotlyProxyInvoke("deleteTraces", list(-1)) %>% plotlyProxyInvoke("deleteTraces", list(-1)) } }) } shinyApp(ui, server)
解决方案:修改plotlyProxyInvoke实现带状图
要通过plotlyProxy添加带状图,需要在addTraces中明确指定散点图类型并配置填充参数,对应add_ribbons的逻辑。核心修改点如下:
- 指定
type = 'scatter',mode = 'lines',同时将线条设为透明隐藏 - 使用
ymin和ymax定义置信区间的上下限 - 设置
fill = 'tonexty'实现区间填充 - 配置
fillcolor和原代码保持一致,确保样式统一 - 配置
hovertemplate保证hover时能显示CI数值
修改后的完整代码
library(shiny) library(shinyWidgets) library(plotly) month <- c('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December') ci_high_2014 <- c(28.8, 28.5, 37.0, 56.8, 69.7, 79.7, 78.5, 77.8, 74.1, 62.6, 45.3, 39.9) ci_low_2014 <- c(12.7, 14.3, 18.6, 35.5, 49.9, 58.0, 60.0, 58.6, 51.7, 45.2, 32.2, 29.1) data <- data.frame(month, ci_high_2014, ci_low_2014) data$average_2014 <- rowMeans(data[,c("ci_high_2014", "ci_low_2014")]) # 指定月份顺序,避免按字母排序 data$month <- factor(data$month, levels = data[["month"]]) ui <- fluidPage( titlePanel("plotlyProxy add Ribbons"), sidebarLayout( sidebarPanel( materialSwitch(inputId = "ci", label = "Add CI", value = FALSE) ), mainPanel( plotlyOutput(outputId = "plot") ) ) ) server <- function(input, output, session = session){ output$plot <- renderPlotly({ plot_ly() %>% add_trace( data = data, x = ~month, y = ~average_2014, type = 'scatter', mode = 'lines', name = "Average" ) %>% layout(hovermode = "x unified") }) observeEvent(input$ci, { if(input$ci){ # 添加上方置信区间带状图 plotlyProxy("plot", session = session) %>% plotlyProxyInvoke( method = "addTraces", list( type = "scatter", mode = "lines", x = as.list(data$month), y = as.list(data$average_2014), ymax = as.list(data$ci_high_2014), ymin = as.list(data$average_2014), fill = "tonexty", name = "CI hi", line = list(color = 'rgba(0, 0, 0, 0)'), fillcolor = 'rgba(255, 0, 0, 0.4)', hovertemplate = "CI hi: %{ymax}<extra></extra>" ) ) %>% # 添加下方置信区间带状图 plotlyProxyInvoke( method = "addTraces", list( type = "scatter", mode = "lines", x = as.list(data$month), y = as.list(data$average_2014), ymax = as.list(data$average_2014), ymin = as.list(data$ci_low_2014), fill = "tonexty", name = "CI lo", line = list(color = 'rgba(0, 0, 0, 0)'), fillcolor = 'rgba(255, 0, 0, 0.4)', hovertemplate = "CI lo: %{ymin}<extra></extra>" ) ) }else{ # 删除最后添加的两个trace(先删第二个,再删第一个) plotlyProxy(outputId = "plot", session) %>% plotlyProxyInvoke("deleteTraces", list(-1)) %>% plotlyProxyInvoke("deleteTraces", list(-1)) } }) } shinyApp(ui, server)
关键说明
- 带状图实现:通过
fill = "tonexty"让plotly填充当前trace的y值和ymax/ymin之间的区域,对应add_ribbons的效果 - 样式统一:保持
line透明、fillcolor半透明红色,和原静态图表样式一致 - hover显示数值:通过
hovertemplate指定hover时显示的内容,确保能查看CI的具体数值 - 无重绘更新:使用
plotlyProxy仅更新图表的trace部分,不会重绘整个图表,提升交互性能
内容的提问来源于stack exchange,提问作者Sean
相关产品推荐
相关产品推荐

