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

R语言Plotly多Y轴堆叠折线图:多X位置悬停显示与Y轴刻度范围调整问题

R语言Plotly多Y轴堆叠折线图:多X位置悬停显示与Y轴刻度范围调整问题

嘿,我来帮你搞定这两个Plotly堆叠折线图的问题,咱们一步步捋清楚~

一、实现多个X位置同时保留悬停信息

你当前的JS代码只能同步单个X位置的悬停效果,要实现新悬停X点时不清除旧悬停信息,我们需要修改JavaScript逻辑,用集合来存储所有需要显示悬停的X值,每次新hover时把X值加入集合,再对所有已记录的X值触发悬停。

修改后的JS代码及调用逻辑

注意要让labels的数量和子图数量完全匹配(你的例子里有3个Y变量,所以对应3个子图):

# 匹配子图数量的标签数组
labels <- c("xy", "xy2", "xy3") 
labels_json <- jsonlite::toJSON(labels)

js_code <- sprintf(
  'function(el, x){
    // 用集合存储所有需要显示悬停的X值(自动去重)
    let hoverXs = new Set();
    el.on("plotly_hover", function(d) {
      const currentX = d.xvals[0];
      hoverXs.add(currentX);
      // 对每个子图,触发所有已记录X值的悬停
      hoverXs.forEach(xVal => {
        Plotly.Fx.hover(el.id, {xval: xVal}, %s);
      });
    });
    // 可选:点击图表空白处清空所有悬停
    el.on("plotly_click", function() {
      hoverXs.clear();
      Plotly.Fx.unhover(el.id);
    });
  }',
  labels_json
)

这样修改后,每次hover新的Time值,之前的悬停信息会保留;如果需要清除所有悬停点,点击图表空白处即可。

二、调整Y轴刻度,显示更多ticks

你的堆叠图用了subplot生成独立Y轴,要增加刻度数量,有两种灵活的实现方式:

方法1:在plotly_stacked函数内自动设置所有Y轴

修改函数,在生成子图后遍历每个Y轴,指定刻度数量或间隔:

plotly_stacked <- function(df, x_colName, cols){
      
      DF <- df[, cols] %>%
        tidyr::gather(variable, value, -x_colName ) %>%
        transform(id = as.integer(factor(variable)))
    
      DF$variable<- factor( DF$variable, levels = unique( DF$variable))
      
      p <- plot_ly(data = DF, x = ~get(names(DF[1])) , y = ~value, color = ~variable, colors = "Dark2",
                   yaxis = ~paste0( "y",sort(id, decreasing = F))) %>%
        
        add_lines() %>%
        layout(
         xaxis = list(title = ""), 
          legend = list(
                  orientation = "h",   
                  xanchor = "center",  
                  x = 0.5)) %>%
        plotly::subplot(nrows = length(unique(DF$variable)), shareX = TRUE)
      
      # 新增:给每个Y轴设置刻度数量,同时添加变量名作为Y轴标题
      y_axis_list <- list()
      for(i in 1:length(unique(DF$variable))){
        y_axis_name <- paste0("yaxis", i)
        y_axis_list[[y_axis_name]] <- list(
          nticks = 10, # 指定刻度数量,可根据数据调整
          # 也可以用dtick指定固定间隔,比如dtick = 0.02
          title = unique(DF$variable)[i]
        )
      }
      p <- p %>% layout(!!!y_axis_list)
      
      return(p)
    }

方法2:调用函数后手动单独设置Y轴

如果不想修改原函数,也可以在生成图表后,通过layout单独调整每个Y轴:

p <- plotly_stacked(df, "Time",  c( "Time" ,"a", "b", "c")) %>%
  layout(
    yaxis = list(nticks = 10), # 对应变量a的Y轴
    yaxis2 = list(nticks = 10), # 对应变量b的Y轴
    yaxis3 = list(nticks = 10) # 对应变量c的Y轴
  ) %>%
  layout(hovermode = "x") %>%
  htmlwidgets::onRender(js_code)

完整可运行测试代码

把所有修改整合后的完整代码如下,直接运行就能看到效果:

library(plotly)
library(tidyr)
library(dplyr)
library(htmlwidgets)
library(jsonlite)

# 修改后的堆叠图函数
plotly_stacked <- function(df, x_colName, cols){
      
      DF <- df[, cols] %>%
        tidyr::gather(variable, value, -x_colName ) %>%
        transform(id = as.integer(factor(variable)))
    
      DF$variable<- factor( DF$variable, levels = unique( DF$variable))
      
      p <- plot_ly(data = DF, x = ~get(names(DF[1])) , y = ~value, color = ~variable, colors = "Dark2",
                   yaxis = ~paste0( "y",sort(id, decreasing = F))) %>%
        
        add_lines() %>%
        layout(
         xaxis = list(title = ""), 
          legend = list(
                  orientation = "h",   
                  xanchor = "center",  
                  x = 0.5)) %>%
        plotly::subplot(nrows = length(unique(DF$variable)), shareX = TRUE)
      
      # 自动设置每个Y轴的刻度与标题
      y_axis_list <- list()
      for(i in 1:length(unique(DF$variable))){
        y_axis_name <- paste0("yaxis", i)
        y_axis_list[[y_axis_name]] <- list(
          nticks = 10,
          title = unique(DF$variable)[i]
        )
      }
      p <- p %>% layout(!!!y_axis_list)
      
      return(p)
    }

# 创建测试数据框
df <- data.frame(
      Time = c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,
               1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2),
      a = c(0.01,0.02,0.03,0.04,0.05,0.06,0.07,
            0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,
            0.19,0.2),
      b = c(0.001,0.002,0.003,0.004,0.005,0.006,
            0.007,0.008,0.009,0.01,0.011,0.012,0.013,0.014,0.015,
            0.016,0.017,0.018,0.019,0.02),
      c = c(1e-04,2e-04,3e-04,4e-04,5e-04,6e-04,
            7e-04,8e-04,9e-04,0.001,0.0011,0.0012,0.0013,0.0014,
            0.0015,0.0016,0.0017,0.0018,0.0019,0.002)
    )

# 多X悬停的JS代码
labels <- c("xy", "xy2", "xy3") # 对应3个子图
labels_json <- jsonlite::toJSON(labels)

js_code <- sprintf(
  'function(el, x){
    let hoverXs = new Set();
    el.on("plotly_hover", function(d) {
      const currentX = d.xvals[0];
      hoverXs.add(currentX);
      hoverXs.forEach(xVal => {
        Plotly.Fx.hover(el.id, {xval: xVal}, %s);
      });
    });
    // 点击空白处清除所有悬停
    el.on("plotly_click", function() {
      hoverXs.clear();
      Plotly.Fx.unhover(el.id);
    });
  }',
  labels_json
)

# 生成并渲染图表
p <- plotly_stacked(df, "Time",  c( "Time" ,"a", "b", "c")) %>%
  layout(hovermode = "x") %>%
  htmlwidgets::onRender(js_code)

p

运行后你会看到:

  1. 每次hover不同的Time值,之前的悬停信息会保留,所有hover过的点都会在每个子图显示对应数值;
  2. 每个Y轴的刻度数量增加,数据细节展示更清晰。

备注:内容来源于stack exchange,提问作者ACE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 09:08:01