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

共享X轴多Plot分组错乱:Plotly如何实现正确分组?

解决Plotly子图合并后图例分组错乱的问题

问题描述

我有两组指标图表,单独绘制时分组显示正常,但通过subplot共享X轴合并到同一图表后,图例分组出现错乱。第一组(v_plot_sec1)包含K线(candlestick)、ema_8、布林带(bbands);第二组(v_plot_sec2)包含MACD、MACD_signal、RSI、VOLUME,合并后的v_plot_fnl中分组混乱,如何实现正确的分组?

解决方案

Plotly默认不会自动为子图的trace划分图例分组,需手动给每个子图内的所有trace指定相同的legendgroup参数,补全缺失的trace名称,再通过布局优化图例的分组交互:

  • 给第一组所有trace设置统一的legendgroup(如"主图指标"),确保每个trace的name准确对应指标
  • 给第二组所有trace设置另一组统一的legendgroup(如"副图指标"),补全RSI、成交量等trace的name
  • 合并子图后,通过layout配置图例的分组折叠功能,支持点击单个指标、双击切换整组显示

修正后的完整代码

library(quantmod)
library(dplyr)
library(purrr)
library(plotly)
library(data.table) # 补充加载依赖包,避免报错

get_data <- function(symbols = c("AAPL", "MSFT", "META", "ORCL",
                                 "TSLA", "GOOG")) {
    syms <- getSymbols(symbols, from = "2020/01/01", 
                       to = Sys.Date(), periodicity = "daily")
    map_dfr(syms, function(sym) {
        raw_data <- get(sym)
        raw_data %>%
            as_tibble() %>% 
            set_names(c("OPEN", "HIGH", "LOW", "CLOSE", "VOLUME", "ADJUSTED")) %>% 
            mutate(SYMBOL = sym,
                   DATE = index(raw_data)) %>% 
            select(SYMBOL, DATE, OPEN, HIGH, LOW, CLOSE, VOLUME, ADJUSTED)
    })
}

if (!exists("df_all")) {
    df_all <- get_data()
}

p_from_date = Sys.Date() -180
p_to_date   = Sys.Date()
p_isin = 'AAPL'

dt_tst <- as.data.table(df_all[df_all$SYMBOL == 'AAPL',])
dt_tst$inc_dec <- sign(dt_tst$CLOSE-dt_tst$OPEN)

dt_tst[dt_tst$inc_dec ==0, ]$inc_dec = 1
dt_tst$Color = ''
dt_tst[inc_dec==1,]$Color  = '#2F6346'# '#00ff00'
dt_tst[inc_dec== -1,]$Color = '#FF4136' #'#ff0000'
# t line data
dt_tmp_ema8 <- as.data.table(EMA(dt_tst[,CLOSE], n = 8))
names(dt_tmp_ema8) <- 'ema_8'
dt_tst <- cbind(dt_tst, dt_tmp_ema8)                             
#  #--Processing BBANDS
dt_tmp_bbands <-  as.data.table(BBands(dt_tst[,CLOSE]))
names(dt_tmp_bbands) <- paste0('bbands_',names(dt_tmp_bbands)) 
dt_tst <- cbind(dt_tst,dt_tmp_bbands)
#----On Balance Volume
dt_tmp_obv        <-  as.data.table(OBV(dt_tst[,CLOSE], dt_tst[,VOLUME]))
names(dt_tmp_obv) <- 'obv'
dt_tst  <- cbind(dt_tst,dt_tmp_obv)
#----StochWPR
dt_tmp_wpr       <- as.data.table(sprintf(WPR(dt_tst[,c(HIGH,LOW,CLOSE)]),fmt = '%#.3f'))
#---- Average Directional Index
dt_tmp_adx       <- as.data.table(ADX(dt_tst[,.(HIGH,LOW,CLOSE)]))
dt_tst <- cbind(dt_tst,dt_tmp_adx)
#-----RSI
dt_tmp_RSI      <- as.data.table(RSI(dt_tst[,.(CLOSE)]))
names(dt_tmp_RSI) = 'RSI'
dt_tst <- cbind(dt_tst,dt_tmp_RSI)
#---- MACD
dt_tmp_macd        <- as.data.table(MACD(dt_tst[,.(CLOSE)], 12, 26,9,maType = 'EMA'))
names(dt_tmp_macd) <- c('macd','macd_signal')
dt_tst   <- cbind(dt_tst,dt_tmp_macd)
#-- Graphing--------------------------------------------------------------------
# Section 1:主图指标(K线、EMA、布林带)
cndlstick   <- plot_ly(name = 'K线' ,data = dt_tst,type='candlestick', x = ~DATE, low=~LOW, high = ~HIGH, open = ~OPEN, close=~CLOSE, legendgroup = "主图指标")
v_plot_sec1 <- add_trace(cndlstick, name = 'ema_8',  data = dt_tst, type = 'scatter', mode = 'lines', x= ~DATE, y = ~ema_8, line = list(color = 'black', width = 2), legendgroup = "主图指标")
v_plot_sec1 <- add_trace(v_plot_sec1, name = '布林带下轨',  data = dt_tst, type = 'scatter', mode = 'lines', x= ~DATE, y = ~bbands_dn, line = list(color = 'gray', width = 1), legendgroup = "主图指标")
v_plot_sec1 <- add_trace(v_plot_sec1, name = '布林带中轨',  data = dt_tst, type = 'scatter', mode = 'lines', x= ~DATE, y = ~bbands_mavg, 
                         line = list(color = 'black', width = 1,linetype =I("dash")  ), legendgroup = "主图指标")
v_plot_sec1 <- add_trace(v_plot_sec1, name = '布林带上轨',  data = dt_tst, type = 'scatter', mode = 'lines', x= ~DATE, y = ~bbands_up, line = list(color = 'gray', width = 1), legendgroup = "主图指标")

# Section 2:副图指标(MACD、RSI、成交量)
v_plot_sec2     <- plot_ly(name =  'MACD', data = dt_tst, type = 'scatter', mode = 'lines', x=~DATE,y=~macd,line = list(color = 'black', width = 1), legendgroup = "副图指标")
v_plot_sec2     <- add_trace(v_plot_sec2, name =  'MACD信号线', data = dt_tst, type = 'scatter', mode = 'lines', x=~DATE,y=~macd_signal,line = list(color = 'red', width = 1), legendgroup = "副图指标")
y2 <- list(tickfont = list(color = "#ff7f0e"),titlefont = list(color = "#ff7f0e"),overlaying = "y",side = "left", anchor="free",    position=0.15,  title = "RSI")
v_plot_sec2 <- v_plot_sec2 %>% add_trace(name = 'RSI', type = 'scatter', mode = 'lines', x=~dt_tst$DATE,y=~dt_tst$RSI, yaxis = "y2",  line = list(color = 'black', width = 1), legendgroup = "副图指标")

y3 <- list(tickfont = list(color = "#d62728"),titlefont = list(color = "#d62728"),overlaying = "y",side = "right",title = "成交量")
v_plot_sec2      <- v_plot_sec2%>% add_trace(name = '成交量', data = dt_tst, type = 'bar', x=~DATE, y=~VOLUME, yaxis = "y3",marker = list(color = ~toRGB(Color, alpha = 0.5)), legendgroup = "副图指标")

# 调整副图布局,优化轴标题
v_plot_sec2 <- v_plot_sec2 %>% layout(yaxis2 = y2, yaxis3 = y3, xaxis = list(title = '日期'),
                                      yaxis = list(title="MACD", tickfont = list(color = "#1f77b4"),titlefont = list(color = "#1f77b4")) )%>%
    layout(plot_bgcolor='#e5ecf6',xaxis = list(zerolinecolor = '#ffff',zerolinewidth = 2,gridcolor = 'ffff'),yaxis = list(zerolinecolor = '#ffff',zerolinewidth = 2,gridcolor = 'ffff'))

# 合并子图并配置图例分组交互
v_plot_fnl      <- subplot(v_plot_sec1,v_plot_sec2,heights = c(0.6,0.3), nrows= 2, shareX = TRUE, titleY = TRUE) %>%
  layout(
    title = "AAPL 技术指标组合图",
    legend = list(
      tracegroupgap = 20, # 分组之间的间距
      itemclick = "toggleitem", # 点击切换单个指标显示
      itemdoubleclick = "togglegroup" # 双击切换整组指标显示
    )
  )

# 查看最终图表
v_plot_fnl

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 01:20:41