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

如何仅用plotly替代Shiny实现关联热图与散点图联动?

用Plotly + Crosstalk替代Shiny实现热图与散点图联动

没问题!完全可以用Plotly搭配Crosstalk来实现你要的热图点击联动散点图的功能,完全不需要依赖Shiny。这样生成的是纯静态HTML文件,直接就能在浏览器打开,完美绕开shinyapps.io的额度限制,也不用折腾RInno这类打包工具。我给你整理了完整的实现方案:

核心逻辑

  • 用crosstalk的消息订阅/发布机制实现两个Plotly图表的通信,不需要服务器端支持
  • 给热图的每个单元格绑定对应的变量对信息,点击时把变量名传递给散点图
  • 散点图监听消息,动态切换x/y变量并重新计算回归线

完整代码实现

library(plotly)
library(crosstalk)
library(htmltools)

# 准备数据,替换成你的大型数据集即可
correlation <- round(cor(mtcars), 3)
nms <- names(mtcars)

# 创建共享数据对象,用于传递点击选择的变量
shared_data <- SharedData$new(data.frame(selected_x = character(), selected_y = character()))

# 绘制关联热图
heatmap_plot <- plot_ly(
  x = nms, y = nms, z = correlation,
  type = "heatmap",
  # 为每个单元格绑定对应的变量对,用分隔符区分
  customdata = outer(nms, nms, paste, sep = "|")
) %>%
  layout(xaxis = list(title = ""), yaxis = list(title = "")) %>%
  # 添加点击事件的JavaScript逻辑,发布选中的变量对
  onRender("
    function(el) {
      el.addEventListener('plotly_click', function(event) {
        const point = event.points[0];
        const [xVar, yVar] = point.customdata.split('|');
        // 通过Crosstalk发布消息,传递选中的变量
        Crosstalk.publish('selected_vars', {x: xVar, y: yVar});
      });
    }
  ")

# 绘制响应式散点图(含回归线)
scatter_plot <- plot_ly(
  data = mtcars,
  x = ~mpg, y = ~mpg, # 初始占位值
  type = "scatter", mode = "markers",
  # 保留原始数据用于后续计算
  source = mtcars
) %>%
  add_lines(y = ~fitted(lm(mpg ~ mpg, data = mtcars))) %>%
  layout(showlegend = FALSE) %>%
  # 监听Crosstalk的消息,动态更新图表
  onRender("
    function(el) {
      // 监听选中变量的消息
      Crosstalk.subscribe('selected_vars', function(vars) {
        const xVar = vars.x;
        const yVar = vars.y;
        const rawData = Plotly.d3.select(el).data()[0].raw;
        
        // 更新散点图数据
        const scatterTrace = el.data[0];
        scatterTrace.x = rawData[xVar];
        scatterTrace.y = rawData[yVar];
        
        // 计算并更新回归线
        const x = rawData[xVar];
        const y = rawData[yVar];
        const xMean = x.reduce((a, b) => a + b, 0) / x.length;
        const yMean = y.reduce((a, b) => a + b, 0) / y.length;
        const slope = x.reduce((sum, xi, i) => sum + (xi - xMean) * (y[i] - yMean), 0) / 
                      x.reduce((sum, xi) => sum + (xi - xMean) ** 2, 0);
        const intercept = yMean - slope * xMean;
        const yhat = x.map(xi => slope * xi + intercept);
        
        const lineTrace = el.data[1];
        lineTrace.x = x;
        lineTrace.y = yhat;
        
        // 更新坐标轴标题
        Plotly.update(el, [scatterTrace, lineTrace], {
          xaxis: {title: xVar},
          yaxis: {title: yVar}
        });
      });
    }
  ")

# 组合图表并生成可浏览的HTML页面
final_page <- tagList(
  crosstalkLibs(), # 加载Crosstalk依赖
  div(
    style = "display: flex; gap: 2rem; padding: 1rem;",
    div(heatmap_plot, style = "flex: 1;"),
    div(scatter_plot, style = "flex: 1;")
  )
)

# 直接在浏览器打开页面
browsable(final_page)

# 或者保存为独立HTML文件,方便分享
# saveWidget(final_page, "linked_heatmap_scatter.html", selfcontained = TRUE)

使用说明

  1. 把代码里的mtcars替换成你的大型数据集,确保变量名正确
  2. 运行代码后会自动在浏览器打开联动页面,点击热图的任意单元格,右侧散点图会自动切换为对应变量的散点图+回归线
  3. 如果需要分享给其他人,取消最后一行的注释,运行saveWidget()生成独立的HTML文件,这个文件可以直接发给同事或者放在公司内网,不需要任何服务器支持

效果展示

关联热图与散点图联动示例

内容的提问来源于stack exchange,提问作者J.Con

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:36:30