I need to reliably and repeatably visualize a system which is like pipes that can pass a certain amount of fluid per unit of time. The real system is a therapy department with several interventions that can provide service to a certain number of people per year, given the capacity of working therapists. Visualization is needed because people respond poorly to just numbers and we are stuck trying to match demand with capacity.
Say there are 3 therapy pathways (assessment, MBT and SCM - in fact there are more, but 3 is a good number for an example). Each has a waiting list, that could be represented by an appropriate size circle before the "pipe" opening. Working therapists represent capacity of a pipe - say 24 people per year or 45 people per year. Patients currently in treatment represent the filling level of the pipe - it can be either saturated or below saturation (by x%).
Question: What could be a good visualization for this kind of problem and what R packages could help achieve that?
Many thanks for your advice to busy clinicians. (I have a fair amount of experience with R though)
CodePudding user response:
You could do all of this in ggplot
if you are prepared to manipulate your data to get it into the right shape for plotting. The following took me about 15 minutes.
Let's say your data is like this:
data <- data.frame(service = c('Assessment', 'MBT', 'SCM'),
therapists = c(32, 45, 20),
current_patients = c(130, 212, 35),
maximum_patients = c(143, 212, 50),
queue = c(35, 52, 7))
Then you could rearrange it into a plotting format like so:
library(tidyverse)
library(ggforce)
plot_df <- data %>%
mutate(left_edge = 10 c(0, cumsum(head(therapists, -1) 10)),
right_edge = cumsum(therapists 10),
upper_edge = 80 * current_patients / maximum_patients,
mid = (left_edge right_edge) / 2)
And draw something like the plot you want using ggplot:
ggplot(plot_df)
geom_rect(aes(xmin = left_edge, ymin = 0,
xmax = right_edge, ymax = upper_edge), fill = 'lightblue')
geom_segment(aes(x = left_edge, y = 0, xend = left_edge, yend = 80),
size = 1, color = 'gray20')
geom_segment(aes(x = right_edge, y = 0, xend = right_edge, yend = 80),
size = 1, color = 'gray20')
geom_segment(aes(x = left_edge, y = 0, xend = right_edge, yend = 0),
size = 1, color = 'gray20')
geom_circle(aes(x0 = mid, y0 = 100, r = 2 * sqrt(queue)), fill = '#3070B1',
color = NA)
geom_text(aes(x = mid, y = 100, label = queue),
colour = 'white', size = 6, fontface = 2)
geom_text(aes(x = mid, y = 40, label = current_patients),
size = 6, fontface = 2)
geom_text(data = data.frame(x = -30, y = c(10, 40, 100),
label = c('Therapists', 'Patients\nIn treatment',
'Patients\nWaiting')),
aes(x, y, label = label), hjust = 0, size = 6, fontface = 1,
color = '#202040')
geom_segment(aes(x = mid, y = 10, xend = left_edge, yend = 10),
arrow = arrow(length = unit(0.1, 'inches')))
geom_segment(aes(x = mid, y = 10, xend = right_edge, yend = 10),
arrow = arrow(length = unit(0.1, 'inches')))
geom_label(aes(x = mid, y = 10, label = therapists), fontface = 2)
scale_x_continuous(breaks = plot_df$mid, labels = plot_df$service,
limits = c(-30, 140))
coord_equal()
theme_void()
theme(axis.text.x = element_text(size = 18, color = '#202040'),
plot.background = element_rect(fill = '#f3f9ff'),
plot.margin = margin(50, 20, 50, 20))