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

R语言Plotly:如何为桑基图的连接线添加文本?

R Plotly桑基图:为连接线添加随节点移动的文本标注

问题描述

我用R的Plotly库制作了一个三列数据的桑基图,想要在连接线上直接显示数值(无需悬停),并且当拖动节点改变位置时,文本能始终附着在对应连接线上。尝试用annotations实现但失败了,核心问题是无法获取连接线的正确坐标,原代码如下:

# Create data.table with counts
dt <- dt[, .N, by=c("column_a", "column_b", "column_c")]

# Create nodes
nodes <- c(unique(dt$column_a), unique(dt$column_b), unique(dt$column_c))
    
# Create links
links <- data.table(
  source=c(match(dt$column_a, nodes)-1, match(dt$column_b, nodes)-1),
  target=c(match(dt$column_b, nodes)-1, match(dt$column_c, nodes)-1),
  value=c(dt$N, dt$N)
)

# Collapse links
links <- links[, .("value" = sum(value)), by=c("source", "target")]

# Plot Sankey diagram
fig <- plot_ly(
  type="sankey",
  orientation="h",
      
  node=list(
    label=nodes
  ),
      
  link = links)

# create annotations for flows
annotations <- list()
for (i in 1:nrow(links)) {
  source_x <- # x-coordinate of source node
  source_y <- # y-coordinate of midpoint of source node
  target_x <- # x-coordinate of target node
  target_y <- # y-coordinate of midpoint of target node
  label <- links$value[i] # create label
  annotations[[i]] <- list(
    x = (source_x + target_x) / 2, # x-coordinate of annotation
    y = (source_y + target_y) / 2, # y-coordinate of annotation
    text = label, # set text to label
    showarrow = FALSE # hide arrow
  )
}

# add annotations to plot
fig <- fig |> layout(
  annotations = annotations
)

解决方案

Plotly桑基图的节点和连接线坐标是在客户端浏览器中渲染的,R端无法直接获取实时位置。我们需要借助JavaScript监听图表的节点拖动事件,动态计算连接线中点并更新文本标注。

修改后的完整代码如下:

library(plotly)
library(data.table)
library(htmlwidgets)

# 模拟数据(如果没有实际dt数据可以用这段)
dt <- data.table(
  column_a = sample(c("A1", "A2", "A3"), 100, replace = TRUE),
  column_b = sample(c("B1", "B2"), 100, replace = TRUE),
  column_c = sample(c("C1", "C2", "C3"), 100, replace = TRUE)
)

# Create data.table with counts
dt <- dt[, .N, by=c("column_a", "column_b", "column_c")]

# Create nodes
nodes <- c(unique(dt$column_a), unique(dt$column_b), unique(dt$column_c))
    
# Create links
links <- data.table(
  source=c(match(dt$column_a, nodes)-1, match(dt$column_b, nodes)-1),
  target=c(match(dt$column_b, nodes)-1, match(dt$column_c, nodes)-1),
  value=c(dt$N, dt$N)
)

# Collapse links
links <- links[, .("value" = sum(value)), by=c("source", "target")]

# Plot Sankey diagram
fig <- plot_ly(
  type="sankey",
  orientation="h",
  node=list(
    label=nodes,
    pad = 15,
    thickness = 20
  ),
  link = links
)

# 注入JavaScript动态更新注释
fig <- fig |> onRender("
  function(el, x) {
    // 定义更新注释的核心函数
    function updateAnnotations() {
      var gd = el;
      // 获取当前图表的节点和连接线数据(包含实时位置)
      var nodes = gd._fullData[0].node;
      var links = gd._fullData[0].link;
      
      var annotations = [];
      
      // 遍历每条连接线计算中点并生成注释
      for (var i = 0; i < links.length; i++) {
        var sourceIdx = links.source[i];
        var targetIdx = links.target[i];
        
        // 获取源节点和目标节点的实时坐标
        var sourceX = nodes.x[sourceIdx];
        var sourceY = nodes.y[sourceIdx];
        var targetX = nodes.x[targetIdx];
        var targetY = nodes.y[targetIdx];
        
        // 计算连接线中点坐标
        var midX = (sourceX + targetX) / 2;
        var midY = (sourceY + targetY) / 2;
        
        // 添加注释配置
        annotations.push({
          x: midX,
          y: midY,
          text: links.value[i].toString(),
          showarrow: false,
          xanchor: 'center',
          yanchor: 'middle',
          font: {
            color: 'white',
            size: 12
          }
        });
      }
      
      // 更新图表的注释
      Plotly.relayout(gd, 'annotations', annotations);
    }
    
    // 页面加载完成后初始化注释
    updateAnnotations();
    
    // 监听节点拖动事件(relayout事件),实时更新注释
    el.on('plotly_relayout', function() {
      // 延迟执行确保节点位置已更新
      setTimeout(updateAnnotations, 100);
    });
  }
")

# 显示图表
fig

关键说明

  1. 获取实时坐标:通过gd._fullData[0].node和gd._fullData[0].link可以获取图表渲染后的实时节点位置和连接线数据,这是R端无法直接拿到的客户端数据。
  2. 动态更新逻辑:定义updateAnnotations函数计算每条连接线的中点,生成对应的注释配置,再通过Plotly.relayout更新图表的annotations。
  3. 事件监听:监听plotly_relayout事件(节点拖动后会触发),延迟执行更新函数,确保节点位置已完成更新,避免获取到旧坐标。
  4. 可读性优化:设置注释字体为白色,配合桑基图的深色连接线,提升文本辨识度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 18:35:06