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

在R的networkD3包中为网络图箭头添加交互式提示框

问题描述

我正在使用R语言的networkD3包开展网络图可视化项目,节点与边信息分别存储于node_df和edge_df两个data frame中。node_df包含节点ID、标签、分组、颜色等数据,edge_df包含源节点、目标节点及边标签等信息。目前已实现节点悬停提示,但鼠标悬停在箭头上时无法显示提示框,目标是让用户悬停节点时查看额外信息,悬停边(含箭头)时显示边标签。


数据示例

边数据(edge_df)

> head(edge_df, 10)
   id from to  rel label penwidth       color fontname fontsize weight constraint
1   1    2 16 <NA>   183 5.000000 dodgerblue4    Arial       10      1       TRUE
2   2    3  6 <NA>     1 1.021858 dodgerblue4    Arial       10      1       TRUE
3   3    3 11 <NA>    10 1.218579 dodgerblue4    Arial       10      1       TRUE
4   4    3 17 <NA>     5 1.109290 dodgerblue4    Arial       10      1       TRUE
5   5    3 19 <NA>     2 1.043716 dodgerblue4    Arial       10      1       TRUE
6   6    4  4 <NA>     2 1.043716 dodgerblue4    Arial       10      1       TRUE
7   7    4 21 <NA>     1 1.021858 dodgerblue4    Arial       10      1       TRUE
8   8    5 17 <NA>    17 1.371585 dodgerblue4    Arial       10      1       TRUE
9   9    6  6 <NA>     1 1.021858 dodgerblue4    Arial       10      1       TRUE
10 10    6 10 <NA>     5 1.109290 dodgerblue4    Arial       10      1       TRUE

节点数据(node_df)

> head(node_df, 10)
   id type                     label     shape color_level          style   fontcolor       color                   tooltip
1   1 <NA>                       End    circle         Inf rounded,filled      brown4      brown4       ARTIFICIAL_END\n183
2   2 <NA>                     Start    circle         Inf rounded,filled chartreuse4 chartreuse4     ARTIFICIAL_START\n183
3   3 <NA>          Analyze Done\n18 rectangle  0.08333333 rounded,filled       black        grey          Analyze Done\n18
4   4 <NA>               Approved\n3 rectangle  0.01388889 rounded,filled       black        grey               Approved\n3
5   5 <NA> Back from Development\n17 rectangle  0.07870370 rounded,filled       black        grey Back from Development\n17
6   6 <NA>                Backlog\n9 rectangle  0.04166667 rounded,filled       black        grey                Backlog\n9
7   7 <NA>              Cancelled\n1 rectangle  0.00462963 rounded,filled       black        grey              Cancelled\n1
8   8 <NA>               Closed\n138 rectangle  0.63888889 rounded,filled       white        grey               Closed\n138
9   9 <NA>           Dispatched\n166 rectangle  0.76851852 rounded,filled       white        grey           Dispatched\n166
10 10 <NA>                 Done\n216 rectangle  1.00000000 rounded,filled       white        grey                 Done\n216
   penwidth fixedsize fontname fontsize fillcolor                     Group
1       1.5     FALSE    Arial       10     white                       End
2       1.5     FALSE    Arial       10     white                     Start
3       1.5     FALSE    Arial       10   #ECE7F2          Analyze Done\n18
4       1.5     FALSE    Arial       10   #FFF7FB               Approved\n3
5       1.5     FALSE    Arial       10   #ECE7F2 Back from Development\n17
6       1.5     FALSE    Arial       10   #FFF7FB                Backlog\n9
7       1.5     FALSE    Arial       10   #FFF7FB              Cancelled\n1
8       1.5     FALSE    Arial       10   #74A9CF               Closed\n138
9       1.5     FALSE    Arial       10   #3690C0           Dispatched\n166
10      1.5     FALSE    Arial       10   #034E7B                 Done\n216

已尝试的代码

# 添加分组列
node_df$Group <- node_df$label

# 整理边和节点数据
edges_net <- edge_df[, c("from", "to", "label")]
colnames(edges_net) <- c("from", "to", "title")

nodes_net <- node_df[, c("id", "label", "Group", "fillcolor")]
colnames(nodes_net) <- c("id", "node_label", "Group", "nodes_color")

# 转换为0索引
edges_net$from <- edges_net$from - 1
edges_net$to <- edges_net$to - 1

# 设置节点大小
nodes_net$NodeSize <- 20

# 节点点击提示JS
clickJS <- "
d3.selectAll('.xtooltip').remove(); 
d3.select('body').append('div')
  .attr('class', 'xtooltip')
  .style('position', 'absolute')
  .style('border', '1px solid #999')
  .style('border-radius', '3px')
  .style('padding', '5px')
  .style('opacity', '0.85')
  .style('background-color', '#fff')
  .style('box-shadow', '2px 2px 6px #888888')
  .html('name: ' + d.name + '<br>' + 'group: ' + d.group)
  .style('left', (d3.event.pageX) + 'px')
  .style('top', (d3.event.pageY - 28) + 'px');
"

# 生成网络图
my_network<- networkD3::forceNetwork(
  Links = edges_net,
  Nodes = nodes_net,
  Source = "from",
  Target = "to", 
  Value = "title", 
  NodeID = "node_label",
  Group = "Group",
  colourScale = networkD3::JS("d3.scaleOrdinal(d3.schemeCategory20);"),
  linkDistance = 300,
  linkWidth = networkD3::JS("function(d) { return Math.sqrt(d.value);}"),
  radiusCalculation = networkD3::JS(" Math.sqrt(d.nodesize)+6"),
  Nodesize = "NodeSize",
  charge = -30,
  linkColour = "black",
  opacity = 0.8,
  zoom = T,
  legend = T,
  arrows = T,
  bounded = T, 
  opacityNoHover = 1.5,
  fontSize = 12,
  clickAction = clickJS
)

# 调整画布大小
my_network$x$width <- '1200px'
my_network$x$height <- '800px'

# 尝试添加边提示
fnrender <- htmlwidgets::onRender(
  my_network,
  '
  function(el, x) {
    d3.selectAll(".link").append("svg:title")
      .text(function(d) { return d.source.name + " -> " + d.target.name; })
  }
  '
)

# 显示图形
fnrender

解决方案

问题核心:当arrows = TRUE时,networkD3会为箭头创建独立的.arrowhead元素,原代码仅给.link类的边添加了提示,未覆盖箭头部分。需同时为边和箭头绑定提示,并让箭头关联对应边的数据。

修改后的onRender代码如下:

fnrender <- htmlwidgets::onRender(
  my_network,
  '
  function(el, x) {
    // 为边添加提示,显示节点关系和边标签
    d3.selectAll(".link").append("svg:title")
      .text(function(d) { 
        return d.source.name + " -> " + d.target.name + "\\n边标签: " + d.value; 
      });
    
    // 为箭头添加提示,通过父元素获取对应边的数据
    d3.selectAll(".arrowhead").each(function() {
      var link = d3.select(this.parentNode);
      var data = link.datum();
      d3.select(this).append("svg:title")
        .text(data.source.name + " -> " + data.target.name + "\\n边标签: " + data.value);
    });
    
    // 为节点添加悬停提示,显示节点详情
    d3.selectAll(".node").append("svg:title")
      .text(function(d) { 
        return d.name + "\\n分组: " + d.group + "\\n" + d.tooltip; 
      });
  }
  '
)

说明

  1. 箭头是边的子元素,通过this.parentNode获取对应边元素,再调用datum()获取边数据,确保箭头提示与对应边内容一致。
  2. 边的value对应传入的title字段(即edge_df中的label),直接用于显示边标签。
  3. 节点提示直接调用node_df中的tooltip字段,可按需拼接其他节点信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:29:53