如何在ggraph的边的指定相对位置绘制箭头?
自定义边箭头位置可视化所有权分配(基于ggraph)
我有一个图,每条边代表节点间的所有权分配情况。例如节点"A"与"B"之间的边,"A"拥有90%的所有权,"B"仅拥有10%。希望通过在边的对应相对位置放置箭头来可视化该分配,优先使用ggraph实现,也接受其他方案。
默认情况下,箭头会放置在边的末端,如下方代码生成的图所示:
library(ggraph) library(ggplot2) # 构建边数据 edges = data.frame(from = c("A", "B", "C"), to = c("C","A", "B"), relative_position = c(.6,.1, .4)) # 创建图对象 graph <- as_tbl_graph(edges) # 使用ggraph绘图 ggraph(graph) + geom_edge_link( arrow = arrow() ) + geom_node_label(aes(label = name))

我想要的效果如下方图所示。之前找到过讨论将箭头移到边中间的文章,但该方法无法设置自定义相对位置。
解决方案:拆分边实现自定义箭头位置
ggraph的geom_edge_link本身不支持直接设置箭头的自定义位置,但可以通过将每条边拆分为两段的方式实现:一段从起点到箭头位置(带箭头),另一段从箭头位置到终点(无箭头)。以下是完整实现代码:
library(ggraph) library(ggplot2) library(tidygraph) # 原始边数据 edges <- data.frame( from = c("A", "B", "C"), to = c("C", "A", "B"), relative_position = c(.6, .1, .4) ) # 创建图对象并生成布局(这里用圆形布局匹配示例) graph <- as_tbl_graph(edges) layout <- create_layout(graph, layout = "circle") # 提取节点的坐标信息 node_coords <- layout$nodes[, c("x", "y", "name")] names(node_coords) <- c("x_from", "y_from", "name") # 合并边数据与起点、终点的坐标 edge_coords <- edges %>% left_join(node_coords, by = c("from" = "name")) %>% left_join(node_coords, by = c("to" = "name"), suffix = c("_from", "_to")) # 计算箭头位置的坐标(基于相对位置) edge_coords <- edge_coords %>% mutate( x_arrow = x_from + relative_position * (x_to - x_from), y_arrow = y_from + relative_position * (y_to - y_from) ) # 拆分边为两段:起点→箭头位置,箭头位置→终点 edges_segment1 <- edge_coords %>% select(from = from, to = "arrow_pos", x_from, y_from, x_to = x_arrow, y_to = y_arrow) %>% mutate(segment = "to_arrow") edges_segment2 <- edge_coords %>% select(from = "arrow_pos", to = to, x_from = x_arrow, y_from = y_arrow, x_to, y_to) %>% mutate(segment = "from_arrow") # 合并两段边并添加唯一ID(避免ggraph绘图报错) all_edges <- bind_rows(edges_segment1, edges_segment2) %>% mutate(id = row_number()) # 创建包含拆分边的图对象 graph_custom <- tbl_graph( nodes = bind_rows(node_coords, data.frame(name = "arrow_pos", x = NA, y = NA)), # 临时节点,不显示 edges = all_edges, directed = FALSE ) # 绘制最终图形 ggraph(graph_custom, layout = "manual", x = x, y = y) + # 绘制箭头到终点的线段(无箭头) geom_edge_link( data = function(x) filter(x, segment == "from_arrow"), color = "black" ) + # 绘制起点到箭头位置的线段(带箭头) geom_edge_link( data = function(x) filter(x, segment == "to_arrow"), arrow = arrow(length = unit(4, "mm")), color = "black" ) + # 绘制原始节点标签,隐藏临时节点 geom_node_label( data = function(x) filter(x, name != "arrow_pos"), aes(label = name), size = 5 ) + theme_void()
说明
- 代码中通过
relative_position参数(0对应起点,1对应终点)精准控制箭头的位置,完全匹配你的需求 - 示例用了圆形布局,你可以根据需要替换为其他布局(比如
layout = "kk") - 拆分边的方式兼容性强,适用于大多数ggraph支持的布局类型
内容的提问来源于stack exchange,提问作者jhfodr76
相关产品推荐
相关产品推荐

