The purpose of this data visualization is to assess if there is an adverse impact on the growth of these children due to taking the drug (exploratory). Explanatory examples are welcome too (once you know the answer).
This is a snapshot from a two-year clinical trial assessing the impact of a drug on growth measurements (stature, weight and BMI) in children as part of a regulatory commitment for a marketed drug. There is a placebo comparator arm that converts to active drug at 6 months and additional rescue medication is allowed.
The challenge is to use visualizations to assess if there is an adverse impact on children’s growth due to taking a drug. To do so, participants had to display effects on development over time. Although the topic led to more exploratory visualizations, the organizers also encouraged participants to develop explanatory graphs.
The first entry encoded the change from baseline in stature’s distribution with color. The area graph used contours and shades of green to highlight the percentages of patients that had a specific shift from baseline over time.
The panelists liked the descriptive title. They also made a few suggestions to improve the chart:
The second entry was an animated scatterplot and density plot: an exploratory visualization that showed the data over time and let viewers draw their conclusions.
The graph had four panels:
The third entry is a dot plot with whiskers showing confidence intervals and trendlines connecting treatment values. The visualization displayed a lot of data and how the treatments deviated.
The panelists made a few suggestions on how to improve the graph:
Another point that was mentioned was to make the textual elements more descriptive. Having the abbreviations meaning, or writing down the unit of the time axis, would have helped viewers understand the chart.
The fourth entry showed distributions over time. In this challenge, the expectation was that most of the changes from baseline should be 0, which is what this visualization highlights.
It’s an especially useful graph that lets you see the distributions over time. It helps you see differences and find extreme values. It also includes the quartiles that facilitate making comparisons between the two groups.
high resolution image 1
high resolution image 2
high resolution image 3
high resolution image 4
The last visualization is box plots over time. A shaded area highlights the band [1, -1], which should fit around 50% of the data. The width of the box plots is also proportional to the number of participants in each treatment group. The X-Axis is also relative to the time points.
The panel liked all the little additions to make the box plots more understandable and representative. They would have liked more separation between the treatment groups to help make comparisons between them.
library(haven)
library(dplyr)
library(tidyr)
library(ggplot2)
library(grid)
library(gridExtra)
library(readxl)
library(cowplot)
hgb1 <- read_excel("/.../growth.xlsx") %>%
filter(MEASURE == "STATURE" & TRT == "Rx" & TIME != 0)
quant1 <- hgb1 %>% group_by(TIME) %>%
do(quant = quantile(.$CFB, probs = seq(0.2,0.8,.05)), probs = seq(0.2,0.8,.05)) %>%
unnest(cols=c(quant, probs)) %>%
mutate(delta = 2*round(abs(.5-probs)*100)) %>%
group_by(TIME, delta) %>%
summarize(quantmin = min(quant), quantmax= max(quant)) %>%
filter(delta > 0)
# Derive median Hgb
hgb_med1 <- hgb1 %>%
group_by(TIME) %>%
summarise(hgb.median = median(CFB))
# Produce plot for group E
plot01 <- ggplot() +
geom_ribbon(data = quant1, aes(x = TIME, ymin = quantmin, ymax = quantmax,
group = reorder(delta, -delta), fill = factor(delta)),
alpha = .5) +
geom_line(data = hgb_med1, aes(x = TIME, y = hgb.median, color = "#00441b"), size = 2 ) +
scale_x_continuous("Time (days)",
breaks=c(16, 28, 40, 52, 64, 76),
limits=c(16, 76)) +
scale_y_continuous(" ",
breaks=c(-1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5),
limits=c(-1.5, 1.5),
) +
scale_fill_manual("% Patients in band", values=c("#e5f5e0","#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#006d2c")) +
scale_color_identity(name = " ",
guide=legend,
labels = " ") +
theme_minimal() +
theme(legend.position="none",
axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
axis.text.y.left = element_text(color = 'black'),
plot.title = element_text(hjust = 0.5, size = 25),
text = element_text(size = 15),
axis.text = element_text(size = 20),
axis.title = element_text(size = 25),
panel.border = element_rect(colour = "black", fill=NA, size=1),
plot.margin=unit(c(1,0,0,0),"cm")) +
ggtitle(label = "Treatment")
hgb2 <- read_excel("/.../growth.xlsx") %>%
filter(MEASURE == "STATURE" & TRT == "Placebo" & TIME != 0)
quant2 <- hgb2 %>% group_by(TIME) %>%
do(quant = quantile(.$CFB, probs = seq(0.2,0.8,.05)), probs = seq(0.2,0.8,.05)) %>%
unnest(cols=c(quant, probs)) %>%
mutate(delta = 2*round(abs(.5-probs)*100)) %>%
group_by(TIME, delta) %>%
summarize(quantmin = min(quant), quantmax= max(quant)) %>%
filter(delta > 0)
hgb_med2 <- hgb2 %>%
group_by(TIME) %>%
summarise(hgb.median = median(CFB))
plot02 <- ggplot() +
geom_ribbon(data = quant2, aes(x = TIME, ymin = quantmin, ymax = quantmax,
group = reorder(delta, -delta), fill = factor(delta)),
alpha = .5) +
geom_line(data = hgb_med2, aes(x = TIME, y = hgb.median, color = "#00441b"), size = 2) +
geom_segment(x=17, y=1, xend=75, yend=1, color="black") +
scale_x_continuous("Time (days)",
breaks=c(16, 28, 40, 52, 64, 76),
limits=c(16, 76)) +
scale_y_continuous(" ",
breaks=c(-1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5),
limits=c(-1.5, 1.5),
) +
scale_fill_manual("% Patients in band", values=c("#e5f5e0","#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#006d2c")) +
scale_color_identity(name = "Median",
guide=legend,
labels = " ") +
labs(fill = "Hgb (% patients in band)") +
theme_minimal() +
theme(legend.position="bottom",
plot.title = element_text(hjust = 0.5, size = 25),
text = element_text(size = 15),
axis.text = element_text(size = 20),
axis.title = element_text(size = 25),
axis.text.y.left = element_text(color = 'black'),
legend.text=element_text(size=14),
legend.title=element_text(size=20),
legend.key.size = unit(1.2, "cm"),
panel.border = element_rect(colour = "black", fill=NA, size=1)) +
guides(colour = guide_legend(override.aes = list(size=3))) +
ggtitle(label = "Control")
p <- grid.arrange(arrangeGrob(plot01, ncol=1, nrow=1),
arrangeGrob(plot02, ncol=1, nrow=1),
heights = c(1,1.32))
title <- ggdraw() + draw_label("Change from Baseline in Stature (cm) Over Time\nNo Evidence of a Treatment Effect", size = 24)
p2 <- plot_grid(title, p, ncol=1, rel_heights = c(1, 10))
gsave("/.../growth.png", p2, width=12, height=12, dpi=300)
No code has been submitted.
No code has been submitted.
No code has been submitted.
The rmd file for the graphs 1 and 3 can be found here.
The rmd file for the graphs 2 and 4 can be found here.
For attribution, please cite this work as
Arenas (2022, June 8). VIS-SIG Blog: Wonderful Wednesdays June 2022. Retrieved from https://graphicsprinciples.github.io/posts/2022-06-12-wonderful-wednesdays-june-2022/
BibTeX citation
@misc{arenas2022wonderful, author = {Arenas, Irene de la Torre}, title = {VIS-SIG Blog: Wonderful Wednesdays June 2022}, url = {https://graphicsprinciples.github.io/posts/2022-06-12-wonderful-wednesdays-june-2022/}, year = {2022} }