Подтвердить что ты не робот

Рисование вручную на фигуре

Я создал граф:

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? Ключевым требованием решения является его воспроизводимость, т.е. Что я могу несколько раз запустить script и получить тот же результат.

4b9b3361

Ответ 1

Здесь другой подход, основанный на igraph. Он вдохновлен этим образцом образцом кода.

Я предполагаю, что использование igraph вместо DiagrammeR является вариантом - возможно, это не так...

Мы оставляем позиционирование вершин стандартным алгоритмом компоновки и запрашиваем его для результирующих позиций вершин. Эти позиции затем используются для рисования точечного прямоугольника вокруг произвольного набора "выбранных" вершин. Не требуется взаимодействие с пользователем.

Начнем с топологии графа.

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

Мы попросим механизм макета Фрухтермана-Рейнгольда вычислить координаты вершин.

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])

Почти там. У нас уже есть координаты центров вершин в коордах [], но нам также нужен размер вершин в системе координат графика(). Из исходного кода plot.igraph видно, что опция vertex.size для plot() делится на 200, а затем используется как радиус для рисования вершины. Мы используем 50% большее значение в качестве поля вокруг ограничивающей рамки координат вершин при рисовании прямоугольника с пунктиром.

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

Это результат:

введите описание изображения здесь

Ответ 2

Вы можете использовать решение @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')

И есть много способов добавить поле к графике; здесь вы можете щелкнуть по графику, чтобы добавить окно, не рассчитывая ничего

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)

Я получаю это

введите описание изображения здесь

Ответ 3

Легким решением с 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
      }

      ")

введите описание изображения здесь