手动绘制图形

Drawing manually on a figure

我生成了一个图表:

library(DiagrammeR)
grViz("
digraph boxes_and_circles {

  # a 'graph' statement
  graph [layout = neato, overlap = true, fontsize = 10, outputorder = edgesfirst]

  # several 'node' statements
  node [shape = circle,
  fontname = Helvetica]
  A [pos = '1,1!']; 
  B [pos = '0,2!']; 
  C [pos = '1.5,3!']; 
  D [pos = '2.5,1!']; 
  E [pos = '4,1!']; 
  F [pos = '4,2!']; 
  G [pos = '5,1!']; 
  H [pos = '6,2!']; 
  I [pos = '1.5,-0.1!'];

  # several 'edge' statements
  A->B B->C
  D->E D->F E->F E->G F->G G->H F->H
  }
  ")

产生:

现在我想用虚线围绕节点 A、B 和 C 绘制一个框。

我如何在 R 中完成此操作?该解决方案的一个关键要求是它是可重现的,即我可以多次 运行 脚本并获得相同的结果。

您可以为小部件使用@StevenBeaupre 的解决方案,但是有一些包使用 R 的图形绘制网络。如果您愿意使用其他解决方案,一种是 igraph

这将使图表

library('igraph')
set.seed(11)
g <- data.frame(from = c('A', 'B', 'I', 'D', 'D', 'E', 'E', 'F', 'F', 'G'),
                to = c('B', 'C', 'I', 'E', 'F', 'G', 'F', 'H', 'G', 'H'))
(gg <- graph.data.frame(g, directed = TRUE))
plot(gg, vertex.color = 'white')

并且有很多方法可以将方框添加到 r 图形中;这是一个您可以单击绘图添加框而无需计算任何东西的地方

rekt <- function(...) {
  coords <- c(unlist(locator(1)), unlist(locator(1)))
  rect(coords[1], coords[2], coords[3], coords[4], ..., xpd = NA)
}

rekt(border = 'red', lty = 'dotted', lwd = 2)

我明白了

这是另一种基于 igraph 的方法。它的灵感来自这个 igraph code sample.

我假设使用 igraph 而不是 DiagrammeR 是一种选择 - 也许事实并非如此......

我们将顶点的定位留给标准布局算法,并向其查询生成的顶点位置。然后使用这些位置在任意一组 "selected" 顶点周围绘制一个虚线矩形。不需要用户交互。

我们从图形拓扑开始。

library(igraph)

set.seed(42)

df <- data.frame(from = c('A', 'B', 'I', 'D', 'D', 'E', 'E', 'F', 'F', 'G'),
                 to = c('B', 'C', 'I', 'E', 'F', 'G', 'F', 'H', 'G', 'H'))

g <- graph.data.frame(df, directed = TRUE)

图中顶点和箭头的大小可以根据喜好自由设置。

vertexsize <- 50
arrowsize <- 0.2

我们要求 Fruchterman-Reingold 布局引擎计算顶点的坐标。

coords <- layout_with_fr(g)

然后绘制图表。

plot(g,
     layout = coords,
     vertex.size = vertexsize,
     edge.arrow.size = arrowsize,
     rescale = FALSE,
     xlim = range(coords[,1]),
     ylim = range(coords[,2]))

如果我们想看看发生了什么,我们可以添加坐标轴并打印顶点坐标:

axis(1)
axis(2)

V(g) # ordered vertex list
coords # coordinates of the vertices (in the same coordinate system as our dotted rectangle)

我们现在找出我们想要矩形围绕的顶点的边界框。

selectedVertices = c("A", "B", "C")
vertexIndices <- sapply(selectedVertices, FUN = function(x) { return(as.numeric(V(g)[x])) } )
llx <- min(coords[vertexIndices, 1])
lly <- min(coords[vertexIndices, 2])
urx <- max(coords[vertexIndices, 1])
ury <- max(coords[vertexIndices, 2])

快到了。我们在coords[]中已经有了顶点centers的坐标,但是我们还需要plot坐标系中顶点的size( ).从 plot.igraph 源代码我们可以看到 plot() 的 vertex.size 选项除以 200,然后用作绘制顶点的半径。绘制虚线矩形时,我们使用大 50% 的值作为顶点坐标边界框周围的边距。

margin <- (vertexsize / 200) * 1.5
rect(llx - margin, lly - margin, urx + margin, ury + margin, lty = 'dotted')

这是我们得到的结果:

DiagrammR 的一个简单解决方案是使用点而不是 neato。您基本上失去了手动定位节点的能力(属性 pos 不再起作用),但您获得了使用集群和子图在节点集周围画线的能力。

library(DiagrammeR)
grViz("
      digraph boxes_and_circles {

      # a 'graph' statement
      graph [ fontsize = 10,rankdir=LR]

      # several 'node' statements
      node [shape = circle,
      fontname = Helvetica]

      # several 'edge' statements

      subgraph cluster_1 {
            style=dotted
            A->B->C
        }

      D->E D->F E->F E->G F->G G->H F->H
      I
      }

      ")