Creating a flowchart using R

The diagram package makes it easy to create flowcharts in R. In this post I'll show an example of creating a simple flowchart. The most important part is to understand how the coordinate systems works; once you understand that, it's just a matter of placing your arrows and boxes accordingly to create your flowchart. To get started, install the package if you haven't already.

install.packages('diagram')

The flowchart I want to create has 13 steps and I want the boxes arranged in the formation 1, 3, 3, 3, and 3. Imagine a football/soccer formation with 1 person at the top, followed by 3, and another 3 and so on. The coordinates() function helps me create this.

library(diagram)

# creates an empty plot
openplotmat()

# create the coordinates
pos <- coordinates(c(1,3,3,3,3))
pos
           [,1] [,2]
 [1,] 0.5000000  0.9
 [2,] 0.1666667  0.7
 [3,] 0.5000000  0.7
 [4,] 0.8333333  0.7
 [5,] 0.1666667  0.5
 [6,] 0.5000000  0.5
 [7,] 0.8333333  0.5
 [8,] 0.1666667  0.3
 [9,] 0.5000000  0.3
[10,] 0.8333333  0.3
[11,] 0.1666667  0.1
[12,] 0.5000000  0.1
[13,] 0.8333333  0.1

class(pos)
[1] "matrix"

plot(pos, type = 'n')
text(pos)

The coordinate system ranges from 0 to 1 on both the x and y axes. The coordinates stored in the matrix pos are used to specify connections for arrows and to place boxes. The order in which you draw the objects matters; if you place the boxes first, the arrows will be placed on top of the boxes.

I will use two types of arrows: straightarrow() and segmentarrow(). They are straightforward to use; you just need to specify the start and end points. The segmentarrow() requires a little bit of tinkering for aesthetic purposes.

par(mar = rep(1, 4))
openplotmat()
pos <- coordinates(c(1,3,3,3,3))
# the dd parameter was used to move the segment arm
segmentarrow (from = pos[1, ], to = pos[2, ], dd = 0.45)
straightarrow(from = pos[2, ], to = pos[3, ])
straightarrow(from = pos[3, ], to = pos[4, ])
straightarrow(from = pos[7, ], to = pos[6, ])
straightarrow(from = pos[6, ], to = pos[5, ])
straightarrow(from = pos[10, ], to = pos[9, ])
straightarrow(from = pos[9, ], to = pos[8, ])
straightarrow(from = pos[13, ], to = pos[12, ])
straightarrow(from = pos[12, ], to = pos[11, ])
# the path parameter was used to change the direction
# arr.pos was used to position the arrow
# arr.side was used to specific where the arrow should be drawn
segmentarrow (from = pos[4, ], to = pos[7, ], dd = 0.15, path = 'RVL', arr.pos = 0.24, arr.side = 3)
segmentarrow (from = pos[4, ], to = pos[10, ], dd = 0.15, path = 'RVL', arr.pos = 0.24, arr.side = 3)
segmentarrow (from = pos[4, ], to = pos[13, ], dd = 0.15, path = 'RVL', arr.pos = 0.24, arr.side = 3)

Now we can draw the boxes on top of the arrows. I've added some conditionals just to change the colour of the boxes.

my_label <- c(1, 2, 3, 4, 7, 6, 5, 10, 9, 8, 13, 12, 11)
my_text_size <- 1.3
my_edge_length <- 0.08
for(i in 1:length(my_label)){
  if (i %in% 5:7){
    textrect(mid = pos[i,], radx = my_edge_length, rady = my_edge_length, lab = my_label[i], cex = my_text_size, box.col = "#0072B2")
  } else if (i %in% 8:10){
    textrect(mid = pos[i,], radx = my_edge_length, rady = my_edge_length, lab = my_label[i], cex = my_text_size, box.col = "#009E73")
  } else if (i %in% 11:13){
    textrect(mid = pos[i,], radx = my_edge_length, rady = my_edge_length, lab = my_label[i], cex = my_text_size, box.col = "#D55E00")
  } else {
    textrect(mid = pos[i,], radx = my_edge_length, rady = my_edge_length, lab = my_label[i], cex = my_text_size, box.col = "#999999")
  }
}

Functions for flowcharts

In the example above I only used two types of arrows and one type of textbox. Below is a full list of the arrows and textboxes that can be used for creating flowcharts.

Function Description
openplotmat creates an empty plot
coordinates calculates coordinates of elements, neatly arranged in rows/columns
bentarrow adds 2-segmented arrow between two points
curvedarrow adds curved arrow between two points
segmentarrow adds 3-segmented arrow between two points
selfarrow adds a circular self-pointing arrow
splitarrow adds a branched arrow between several points
straightarrow adds straight arrow between two points
treearrow adds dendrogram-like branched arrow between several points
shadowbox adds a box with a shadow to a plot
textdiamond adds lines of text in a diamond-shaped box to a plot
textellipse adds lines of text in a ellipse-shaped box to a plot
textempty adds lines of text on a colored background to a plot
texthexa adds lines of text in a hexagonal box to a plot
textmulti adds lines of text in a multigonal box to a plot
textparallel adds lines of text in a parallelogram to a plot
textplain adds lines of text to a plot
textrect adds lines of text in a rectangular-shaped box to a plot
textround adds lines of text in a rounded box to a plot

The vignette contains code to visualise all the different types of textboxes.

openplotmat(main = "textbox shapes")
rx <- 0.1
ry <- 0.05
pos <- coordinates(c(1, 1, 1, 1, 1, 1, 1,1 ), mx = -0.2)
pos
textdiamond(mid = pos[1,], radx = rx, rady = ry, lab = LETTERS[1], cex = 2, shadow.col = "lightblue")
textellipse(mid = pos[2,], radx = rx, rady = ry, lab = LETTERS[2], cex = 2, shadow.col = "blue")
texthexa(mid = pos[3,], radx = rx, rady = ry, lab = LETTERS[3], cex = 2, shadow.col = "darkblue")
textmulti(mid = pos[4,], nr = 7, radx = rx, rady = ry, lab = LETTERS[4], cex = 2, shadow.col = "red")
textrect(mid = pos[5,], radx = rx, rady = ry, lab = LETTERS[5], cex = 2, shadow.col = "darkred")
textround(mid = pos[6,], radx = rx, rady = ry, lab = LETTERS[6], cex = 2, shadow.col = "black")
textparallel(mid = pos[7,], radx = rx, rady = ry, lab = LETTERS[7], cex = 2, theta = 40, shadow.col = "black")
textempty(mid = pos[8,], lab = LETTERS[8], cex = 2, box.col = "yellow")
pos[ ,1] <- pos[ ,1] + 0.5
pos
text(pos[ ,1],pos[ ,2], c("textdiamond", "textellipse", "texthexa",
                          "textmulti", "textrect", "textround",
                          "textparallel", "textempty"))

And all the different arrows.

par(mar = c(1, 1, 1, 1))
openplotmat(main = "Arrowtypes")
elpos <- coordinates (c(1, 2, 1), mx = 0.1, my = -0.1)
curvedarrow(from = elpos[1, ], to = elpos[2, ], curve = -0.5, lty = 2, lcol = 2)
straightarrow(from = elpos[1, ], to = elpos[2, ], lty = 3, lcol = 3)
segmentarrow (from = elpos[1, ], to = elpos[2, ], lty = 1, lcol = 1)
treearrow (from = elpos[2:3, ], to = elpos[4, ], lty = 4, lcol = 4)
bentarrow (from = elpos[3, ], to = elpos[3, ]-c(0.1, 0.1),arr.pos=1,lty=5,lcol=5)
bentarrow(from = elpos[1, ], to = elpos[3, ], lty = 5, lcol = 5)
selfarrow(pos = elpos[3, ], path = "R",lty = 6, curve = 0.075, lcol = 6)
splitarrow(from = elpos[1, ], to = elpos[2:3, ], lty = 1, lwd = 1, dd = 0.7, arr.side = 1:2, lcol = 7)
for ( i in 1:4){
  textrect (elpos[i, ], 0.05, 0.05, lab = i, cex = 1.5)
}
legend("topright", lty = 1:7, legend = c("segmentarrow","curvedarrow", "straightarrow", "treearrow", "bentarrow",
                                         "selfarrow", "splitarrow"), lwd = c(rep(2, 6), 1), col = 1:7)

Summary

I thought the diagram package was quite easy to use for creating a flowchart in R. I needed to tinker a bit with the placement of lines and arrows but all in all it didn't take long to create the flowchart.

Print Friendly



Creative Commons License
This work is licensed under a Creative Commons
Attribution 4.0 International License
.

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.