Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing manually on a figure

I have generated a graph:

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
  }
  ")

Which produces:

enter image description here

Now I would like to draw a box with dotted lines around the nodes A, B, and C.

How can I accomplish this in R? A key requirement of the solution is that it is reproducible, i.e. that I can run the script multiple times and get the same result.

like image 840
histelheim Avatar asked Aug 03 '15 15:08

histelheim


People also ask

What is a figure drawing in art?

Figure drawing is the art of sketching the human figure, often done live with a nude model who is standing or sitting in a pose that emphasize the figure. This process helps the artist capture the essence of the human body's musculature, texture and postures.


1 Answers

Here's another approach based on igraph. It is inspired by this igraph code sample.

I'm assuming that using igraph instead of DiagrammeR is an option - maybe that is not the case...

We leave positioning of the vertices to a standard layout algorithm and query it for the resulting vertex positions. These positions are then used to draw a dotted rectangle around an arbitrary set of "selected" vertices. No user interaction is needed.

We start with the graph topology.

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)

The size of the vertices and arrows in the graph can be set freely, according to taste.

vertexsize <- 50
arrowsize <- 0.2

We ask the Fruchterman-Reingold layout engine to calculate the coordinates of the vertices.

coords <- layout_with_fr(g)

Then plot the graph.

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

If we like to see what's going on, we can add coordinate axes and print the vertex coordinates:

axis(1)
axis(2)

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

We now figure out the bounding box of the vertices that we want a rectangle around.

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

Almost there. We already have the coordinates of the vertex centers in coords[], but we also need the size of the vertices in the coordinate system of plot(). From the plot.igraph source code we can see that the vertex.size option for plot() gets divided by 200 and then used as radius for drawing the vertex. We use a 50% bigger value as the margin around the bounding box of the vertex coordinates when drawing the dotted rectangle.

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

This is the result we get:

enter image description here

like image 189
WhiteViking Avatar answered Oct 02 '22 09:10

WhiteViking