Last active
November 4, 2022 03:14
-
-
Save AlbertRapp/438102c458fc8fbdffcb6feb76ff93f7 to your computer and use it in GitHub Desktop.
ggplot flowchart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
output: html_document | |
editor_options: | |
chunk_output_type: console | |
--- | |
This is based on Nicola Rennie's blog post https://nrennie.rbind.io/blog/2022-06-06-creating-flowcharts-with-ggplot2/ | |
The flowchart is taken from https://imgur.com/gallery/79VHL | |
```{r} | |
library(tidyverse) | |
library(igraph) | |
library(showtext) | |
setwd(here::here('flowchart_ggplot/')) | |
camcorder::gg_record( | |
dir = 'img', | |
height = 16, | |
width = 16, | |
units = 'cm' | |
) | |
font_add_google('Fira Sans', 'firasans') | |
font_add_google('Oleo Script', 'oleo_heading') | |
showtext_auto() | |
showtext_opts(dpi = 300) | |
``` | |
Initial data set containing columns `from` and `to`. | |
```{r} | |
dat <- tribble( | |
~from, ~to, | |
'Are you a horse?', 'No', | |
'Are you a horse?', 'Yes', | |
'Are you a horse?', 'Maybe', | |
'Maybe', 'How many legs\ndo you walk on?', | |
'Yes', 'How many legs\ndo you walk on?', | |
'No', 'You\'re not a horse', | |
'How many legs\ndo you walk on?', 'Two', | |
'How many legs\ndo you walk on?', 'Four', | |
'Two', 'You\'re not a horse_2', | |
'Four', 'Really?', | |
'Really?', 'No_2', | |
'Really?', 'Yes_2', | |
'No_2', 'Can you read\nand write?', | |
'Yes_2', 'Can you read\nand write?', | |
'Can you read\nand write?', 'Yes_3', | |
'Can you read\nand write?', 'No_3', | |
'Yes_3', 'You\'re not a horse_3', | |
'No_3', 'You\'re reading this,\naren\'t you?', | |
'You\'re reading this,\naren\'t you?', 'Yes_4', | |
'Yes_4', 'You\'re not a horse_4' | |
) | |
``` | |
Create graph and layout | |
```{r} | |
graph <- graph_from_data_frame(dat, directed = TRUE) | |
coords <- graph %>% | |
layout_as_tree() %>% | |
as_tibble(.name_repair = ~c('x', 'y')) | |
output <- coords %>% | |
mutate( | |
step = vertex_attr(graph, 'name'), | |
label = str_remove(step, '\\_.+'), | |
x = -2.5 * x, | |
y = 5 * y, | |
type = case_when( | |
str_detect(label, '\\?') ~ "Question", | |
str_detect(step, 'You\'re not a horse') ~ 'Outcome', | |
T ~ 'Answer' | |
) | |
) | |
``` | |
Make boxes | |
```{r} | |
box_width <- 1.2 | |
box_height <- 1.25 | |
boxes <- output %>% | |
mutate( | |
xmin = x - box_width, | |
xmax = x + box_width, | |
# Adjusted Nicola's code here to make a couple of boxes larger | |
ymin = case_when( | |
str_detect(step, '(legs|reading|write)') ~ y - 1.5 * box_height, | |
T ~ y - box_height | |
), | |
ymax = case_when( | |
str_detect(step, '(legs|reading|write)') ~ y + 1.5 * box_height, | |
T ~ y + box_height | |
) | |
) | |
``` | |
Make edges | |
```{r} | |
# This is the hard part in this plot. | |
# I only copy-and-pasted this from Nicola's post | |
edges <- dat %>% | |
mutate(id = row_number()) %>% | |
pivot_longer(cols = c("from", "to"), | |
names_to = "s_e", | |
values_to = "step") %>% | |
left_join(boxes, by = "step") %>% | |
select(-c(label, type, y, xmin, xmax)) %>% | |
mutate(y = ifelse(s_e == "from", ymin, ymax)) %>% | |
select(-c(ymin, ymax)) %>% | |
# Adjusted Nicola's code here to redirect two arrows | |
mutate( | |
x = case_when( | |
s_e == 'to' & id %in% c(5, 14) ~ x - box_width, | |
T ~ x | |
) | |
) | |
``` | |
Plotting | |
```{r} | |
base_colors <- thematic::okabe_ito(2) | |
ggplot() + | |
geom_path( | |
data = edges, | |
aes(x, y, group = id), | |
arrow = arrow(length = unit(0.25, 'cm')) | |
) + | |
geom_rect( | |
data = boxes, | |
aes( | |
xmin = xmin, | |
xmax = xmax, | |
ymin = ymin, | |
ymax = ymax, | |
fill = type | |
) | |
) + | |
geom_text( | |
data = boxes, | |
aes( | |
x = x, | |
y = y, | |
label = label | |
), | |
lineheight = 1, | |
family = 'firasans' | |
) + | |
theme_void() + | |
theme( | |
legend.position = 'none', | |
plot.background = element_rect(fill = 'white', colour = NA) | |
) + | |
scale_fill_manual(values = c( | |
'Question' = base_colors[1], | |
'Answer' = colorspace::lighten(base_colors[1], 0.5), | |
'Outcome' = colorspace::lighten(base_colors[2], 0.1) | |
)) + | |
annotate( | |
'text', | |
x = -1.75, | |
y = min(boxes$ymin), | |
family = 'firasans', | |
hjust = 0, | |
vjust = 0, | |
lineheight = 1.25, | |
label = 'imgur 79VHL\n@rappa753\n@nrennie35' | |
) + | |
annotate( | |
'text', | |
x = -2, | |
y = min(boxes$ymin), | |
family = 'firasans', | |
fontface = 'bold', | |
hjust = 1, | |
vjust = 0, | |
lineheight = 1.25, | |
label = 'Inspiration:\nGraphic:\nCode template:' | |
) + | |
annotate( | |
'text', | |
x = -0.3, | |
y = min(boxes$ymin) + 11, | |
size = 10, | |
family = 'oleo_heading', | |
hjust = 1, | |
vjust = 0, | |
lineheight = 1.5, | |
label = 'Are you a horse?' | |
) + | |
annotate( | |
'text', | |
x = -0.3, | |
y = min(boxes$ymin) + 8.5, | |
size = 5.5, | |
family = 'oleo_heading', | |
hjust = 1, | |
vjust = 0, | |
lineheight = 1.5, | |
label = 'Find out via this flow chart.' | |
) + | |
coord_cartesian( | |
xlim = c(-4.5, 5) | |
) | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment