alittleboy
alittleboy

Reputation: 10956

3D waterfall plot in ggplot2

I'd like to create a 3D waterfall plot using ggplot2, with the x-/y-axis showing as the ordinary (2D) waterfall plot, and the z-axis as the third dimension of "days on treatment" (bar plot). One example from the paper (Source: doi:10.1093/annonc/mdw656) is shown below (Figure 1 (D)), where the 3D plot is just a combination of the 2D plot (Figure 1 (B)) and the horizontal bar plot (Figure 1 (C)).

enter image description here

Here are some reproducible R codes to create the 2D waterfall plot:

library(ggplot2)

# Mock Data Simulation
subjid = seq(1, 9)
tumor.type = c("CCR", "CCR", "Gastric", "Ovarian", "Ovarian", "CCR", "Breast", "CCR", "Gastric")
per.change = c(42, 26, 20, 10, 5, -5, -10, -20, -50)
days.on.trt = c(20, 40, 60, 45, 70, 80, 100, 90, 120)

dat = data.frame(subjid, tumor.type, per.change, days.on.trt)
dat

# Waterfall Plot
b = ggplot(dat, aes(x=reorder(subjid, -per.change, median), y=per.change, fill=tumor.type)) +
  scale_fill_manual(values = c("red3", "gray60", "green4", "dodgerblue3"),
                    name="Tumor Type") + 
  labs(x = "Subject ID", y = "Best % Change from Baseline in Tumor Size") +
  theme_bw() %+replace%
  theme(axis.text.x = element_text(angle=90, hjust = 1), 
        axis.ticks.x=element_blank(),
        axis.title.x = element_text(face="bold", angle=0, size=8),
        axis.title.y = element_text(face="bold",angle=90, size=8),
        panel.grid.major.x = element_blank(),
        legend.justification=c(0.95,0.99), legend.position=c(0.95,0.99),
        legend.key = element_rect(fill = "white", 0.1)) +
  scale_y_continuous(limits=c(-80, 60), breaks=seq(-80, 60, by=20)) +
  coord_cartesian(ylim = c(-80, 60)) +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = -30, linetype="dashed", size=1, color="gray30") +
  geom_hline(yintercept = 20, linetype="dashed", size=1, color="gray30")

b + geom_bar(stat="identity", width=0.7, position = position_dodge(width=0.4))

And here are some codes (for the same subjects) for the horizontal bar plot:

# Swimmer Plot
ggplot(dat, aes(x=reorder(subjid, per.change), y=days.on.trt)) +
  geom_bar(stat='identity') + 
  labs(x = "Days on Treatment", y = "Subject ID") +
  coord_flip()

I appreciate if someone could share some thoughts on how to create the 3D plot as shown in Figure 1 (D) above. Much appreciated!

Upvotes: 2

Views: 2423

Answers (1)

Godwin Yung
Godwin Yung

Reputation: 26

Second Axeman about ggplot2 not supporting 3D graphics. If you look closely at the article's 3D plot, the color is different from the 2D waterfall plot; tumor size change was crudely drawn on, with visible gaps between the bottom of the bars and the x-axis; and days on treatment do not seem to be physically spaced apart correctly.

This doesn't address your request, but I also gave simulating the dataset and creating the 2D waterfall plot a shot. I prefer if the color theme respects the ordinality of the dosages. Also, this adds the correct x-axis tick labels.

###
# Libraries
###

library(tidyverse)
library(ggplot2)

###
# Simulate data
###

dose.categories <- paste(c(1,5,10,15,20,25), "mg")
disease.categories <- c("CCR", "Gastric", "Ovarian", "Breast")

data <- tibble(
  id=sample(20,20),
  tchange=sort(runif(n=20,min=-100,max=60), decreasing=T),
  dose=dose.categories[c(1,4,2,3,4,1,5,1,5,5,2,3,2,4,3,5,6,5,5,5)],
  disease=disease.categories[c(1,1,2,3,3,1,4,4,4,1,4,1,3,2,2,2,4,1,2,2)],
  duration=jitter(sort(runif(n=20,min=30,max=120)), amount=30)
) %>%
  arrange(id) %>%
  mutate(dose=factor(dose, levels=paste(c(1,5,10,15,20,25), "mg")))

###
# 2D waterfall
###

ggplot(data, aes(x=reorder(id, -tchange), y=tchange)) + 
  geom_bar(aes(fill=dose), stat="identity") +
  scale_x_discrete(labels=data$disease[as.numeric(levels(reorder(data$id, -data$tchange)))]) +
  scale_fill_brewer(palette="YlGn") +
  labs(x="",
       y="Tumor size change (%)",
       fill="Dose") +
  theme(axis.text.x = element_text(angle=90, vjust=0.5, hjust=1),
        axis.ticks.x=element_blank(),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        legend.position="bottom")

Upvotes: 1

Related Questions