【问题标题】:How to dodge overlapping segments to keep them parallel如何躲避重叠的线段以保持它们平行
【发布时间】:2020-03-04 07:26:50
【问题描述】:

我有一个这样的数据框:

structure(list(x = c(65.11, 65.11, 65.11, 43.72, 43.72, 43.72, 
43.72, 43.72, 43.72, 43.72, 43.72, 59.89, 59.89, 59.89, 59.89, 
36.24, 36.24, 36.24, 36.24, 67.88, 37.89, 37.89, 37.89, 56.05, 
56.05, 56.05, 60.16, 60.16, 60.16, 30.92, 30.92, 30.92, 47.55, 
47.55, 47.55), y = c(32.17, 32.17, 32.17, 56.09, 56.09, 56.09, 
56.09, 56.09, 56.09, 56.09, 56.09, 15.64, 15.64, 15.64, 15.64, 
81.61, 81.61, 81.61, 81.61, 56.96, 21.69, 21.69, 21.69, 86.47, 
86.47, 86.47, 68.31, 68.31, 68.31, 51.56, 51.56, 51.56, 43.44, 
43.44, 43.44), xend = c(59.89, 60.16, 43.72, 59.89, 37.89, 56.05, 
60.16, 65.11, 36.24, 30.92, 47.55, 37.89, 65.11, 67.88, 30.92, 
37.89, 56.05, 30.92, 47.55, 60.16, 43.72, 59.89, 30.92, 43.72, 
36.24, 60.16, 43.72, 67.88, 47.55, 43.72, 36.24, 37.89, 59.89, 
37.89, 43.72), yend = c(15.64, 68.31, 56.09, 15.64, 21.69, 86.47, 
68.31, 32.17, 81.61, 51.56, 43.44, 21.69, 32.17, 56.96, 51.56, 
21.69, 86.47, 51.56, 43.44, 68.31, 56.09, 15.64, 51.56, 56.09, 
81.61, 68.31, 56.09, 56.96, 43.44, 56.09, 81.61, 21.69, 15.64, 
21.69, 56.09), node = c("484", "484", "484", "309", "309", "309", 
"309", "309", "309", "309", "309", "740", "740", "740", "740", 
"151", "151", "151", "151", "11", "26", "26", "26", "991", "991", 
"991", "731", "731", "731", "714", "714", "714", "99", "99", 
"99")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-35L))

我可以绘制如下图:

df %>% 
  ggplot() +
  geom_point(aes(x, y), shape = 21, size = 5, stroke = 1, colour = 'black', fill = 'blue') +
  geom_segment(aes(x = x, y = y, xend = xend, yend = yend),
               colour = 'red')

但这实际上是有向图,所以每个段都有两个有向分量重叠。我尝试使用position_dodge2 修复它,但以下尝试并不像需要的那样简洁:

df %>% 
  ggplot() +
  geom_point(aes(x, y), shape = 21, size = 5, stroke = 1, colour = 'black', fill = 'blue') +
  geom_segment(aes(x = x, y = y, xend = xend, yend = yend),
               colour = 'red',
               position = position_dodge2(width = 3))

我想让重叠的部分平行,可能会从节点位置稍微避开它们的末端。我怎样才能做到这一点?

【问题讨论】:

标签: r ggplot2


【解决方案1】:

如果您不介意一些数据争吵,您可以使用“ggraph”包来制作 ggplot2 图表。下面的方法假设一个节点可以由 x 或 xend 位置唯一标识。

library(ggraph)
library(igraph)

nodes <- unique(df$x, df$xend)

elist <- cbind(df$node[match(df$x, nodes)],
               df$node[match(df$xend, nodes)])


gra <- graph_from_edgelist(elist)

lay <- create_layout(gra, "auto")
lay$x <- df$x[match(lay$name, df$node)]
lay$y <- df$y[match(lay$name, df$node)]


ggraph(lay) +
  geom_edge_parallel(end_cap = circle(.5), start_cap = circle(.5),
                     colour = "red",
                     arrow = arrow(length = unit(2, 'mm'), type = 'closed')) +
  geom_node_point(shape = 21, size = 5, stroke = 1, colour = 'black', fill = 'blue')

编辑:我发现在图形阶段最容易操纵边缘美学,而在布局阶段可以轻松操纵节点美学。示例:

gra <- graph_from_edgelist(elist)
E(gra)$size <- sample(1:10, length(E(gra)), replace = T)

lay <- create_layout(gra, "auto")
lay$x <- df$x[match(lay$name, df$node)]
lay$y <- df$y[match(lay$name, df$node)]
lay$size <- sample(1:10, nrow(lay), replace = T)


ggraph(lay) +
  geom_edge_parallel(end_cap = circle(.5), start_cap = circle(.5),
                     colour = "red", aes(edge_width = size),
                     arrow = arrow(length = unit(2, 'mm'), type = 'closed')) +
  geom_node_point(shape = 21, aes(size = size), stroke = 1, colour = 'black', fill = 'blue') 

【讨论】:

  • 爱它!但是是否有可能通过 ggplot2 aes(size = col) 改变 sizealpha 边缘或节点的美学?我的意思是当我们有额外的列df %&gt;% mutate(node_size = sample(1:100, 35), edge_size = sample(1:20, 35, replace = TRUE)) 时,我们可以将node_size 映射到节点大小并将edge_size 映射到边缘大小和alpha 吗?我应该如何构造数据?我将这些列添加到lay df 并尝试在geom_node_point 中使用aes(size = node_size),但它不起作用(使用tree 作为默认布局 FUN 中的错误(X[[i]],...) :找不到对象'node_size'``
  • 是的,您可以,但由于工作单元是图形而不是 data.frame,因此可能需要一些不熟悉的步骤。有关大小的示例,请参阅编辑。
【解决方案2】:

我不知道有什么方法可以自动执行此操作,但显而易见的解决方案是使用一点三角函数来移动每条线的位置。

但是,“足够好”的解决方案可能是在粗红线上过度绘制细灰线?

df %>% 
  ggplot() +
  geom_segment(aes(x = x, y = y, xend = xend, yend = yend), size = 3,
               colour = 'red') +
    geom_segment(aes(x = x, y = y, xend = xend, yend = yend), size = 1,
               colour = 'lightgray') +
  geom_point(aes(x, y), shape = 21, size = 5, stroke = 1, colour = 'black', fill = 'blue') 

【讨论】:

    【解决方案3】:

    也许使用曲线

    ggplot(data = df) +
      geom_point(aes(x, y), shape = 21, size = 5, stroke = 1, colour = 'black', fill = 'blue') +
      geom_curve(aes(x = x, y = y, xend = xend, yend = yend),
                   colour = 'red')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-06
      • 1970-01-01
      • 2020-11-06
      • 1970-01-01
      • 1970-01-01
      • 2020-10-11
      相关资源
      最近更新 更多