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

Я построил график:

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


person histelheim    schedule 03.08.2015    source источник
comment
вы хотите, чтобы это был виджет или просто изображение   -  person rawr    schedule 03.08.2015
comment
@rawr: какая разница? В конце концов мне нужно вывести изображение, чтобы поместить его в документ Word.   -  person histelheim    schedule 03.08.2015
comment
@histelheim Может быть, вы могли бы попытаться вручную расположить прямоугольник как узел, используя engine = "neato" (вместо circo) и атрибут pos: a [pos = '-3,4!', width = 3.5, height = 0.5, shape = rectangle, label = '']. Взгляните на graphviz.org/content/attrs#dpos stackoverflow.com/questions/5343899 и stackoverflow.com/questions /29208525   -  person Steven Beaupré    schedule 03.08.2015
comment
Для вашего исходного вопроса вы можете добавить рамку вокруг узлов, используя subgraph, но я не уверен, что это то, что вам нужно, поскольку текст в вашей награде предполагает, что вы хотите что-то для разных типов фигур (например, не конкретно для вашего проблема с вопросами?).   -  person user20650    schedule 04.09.2015


Ответы (3)


Вот еще один подход, основанный на igraph. Он вдохновлен этим примером кода 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])

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

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

Вот такой результат мы получаем:

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

person WhiteViking    schedule 01.09.2015

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

я понимаю это

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

person rawr    schedule 03.08.2015
comment
Есть ли способ сделать это воспроизводимым, то есть не требующим ручного нажатия? - person histelheim; 31.08.2015
comment
@histelheim Я не могу придумать хороший способ. igraph имеет несколько встроенных макетов ?igraph::layout, которые определяют, куда все идет, а не случайным образом. можно было указать матрицу для макета, чтобы заранее знать координаты - person rawr; 31.08.2015
comment
Я могу указать, куда идут узлы, я просто не могу указать, куда идет прямоугольник... - person histelheim; 31.08.2015
comment
@histelheim, вы можете задать новый вопрос с кодом? - person rawr; 31.08.2015
comment
Разве суть вопроса не та же? Ваше решение хорошее, оно просто не соответствует (на тот момент не сформулированному) предположению о воспроизводимости. - person histelheim; 31.08.2015

Простым решением с DiagrammR было бы использовать точку, а не обернуть. В основном вы теряете возможность вручную позиционировать узлы (атрибут 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
      }

      ")

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

person scoa    schedule 05.09.2015
comment
если вы используете макет fdp, вы можете использовать pos, но позиции являются локальными для кластера (я думаю). Вероятно, вы можете настроить позиции, добавив невидимые узлы/ребра. - person user20650; 06.09.2015