在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; }); } ' )
说明
- 箭头是边的子元素,通过
this.parentNode获取对应边元素,再调用datum()获取边数据,确保箭头提示与对应边内容一致。 - 边的
value对应传入的title字段(即edge_df中的label),直接用于显示边标签。 - 节点提示直接调用
node_df中的tooltip字段,可按需拼接其他节点信息。
内容的提问来源于stack exchange,提问作者AndCh
相关产品推荐
相关产品推荐

