You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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)

关键说明

  1. 带状图实现:通过fill = "tonexty"让plotly填充当前trace的y值和ymax/ymin之间的区域,对应add_ribbons的效果
  2. 样式统一:保持line透明、fillcolor半透明红色,和原静态图表样式一致
  3. hover显示数值:通过hovertemplate指定hover时显示的内容,确保能查看CI的具体数值
  4. 无重绘更新:使用plotlyProxy仅更新图表的trace部分,不会重绘整个图表,提升交互性能

内容的提问来源于stack exchange,提问作者Sean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 06:24:57