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 plotopenplotmat()# create the coordinatespos <- 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.1class(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 armsegmentarrow (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 drawnsegmentarrow (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.3my_edge_length <- 0.08for(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.1ry <- 0.05pos <- coordinates(c(1, 1, 1, 1, 1, 1, 1,1 ), mx = -0.2)postextdiamond(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.5postext(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.