7

I am trying to plot several boxplots in one chart using ggplot2. I have 1 continuous variable and several factors. I would like to have a single Y axis and each pair of boxplots to have their own x axis with their own factor levels. So far, I tried to use cowplot::plot_grid to join together charts that I made separately with an empty chart that I use for the Y axis. I tried to make the charts blend nicely by hiding margins and resizing the charts but I still cannot get reasonable results and this method involves too much manual tweaking. This is what I want to get and what I came up so far: charts

And this is my script:

library(ggplot2)
library(cowplot)
library(dplyr)

# make a dataset:
DF <- mtcars
DF$cyl <- as.factor(DF$cyl)
DF$vs <- as.factor(DF$vs)
DF$am <- as.factor(DF$am)
DF$gear <- as.factor(DF$gear)
DF$carb <- as.factor(DF$carb)
#str(DF)

# fisrt boxplot
p1 <- DF %>% ggplot() + theme_grey() + aes(x=cyl, y=mpg, fill=cyl) +
  geom_boxplot() +
  theme(legend.position = "none",
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank()) +
  theme(plot.margin = margin(t=0.1, r=0, b=0, l=0, unit="cm"))

# second boxplot
p2 <- DF %>% ggplot() + theme_grey() + aes(x=vs, y=mpg, fill=vs) +
  geom_boxplot() +
  theme(legend.position = "none",
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank()) +
  theme(plot.margin = margin(t=0.1, r=0, b=0, l=0, unit="cm"))

# empty boxplot used only for the y axis
y_axis <- DF %>% ggplot() + theme_grey() + aes(x=mpg, y=mpg) +
  geom_point() +
  theme(axis.title.y = element_text(),
        axis.text.y = element_text(),
        axis.title.x = element_text(),
        axis.text.x = element_text()) +
  theme(plot.margin = margin(t=0.1, r=0, b=0, l=0, unit="cm"))+
  scale_x_continuous(limits = c(0, 0), breaks=c(0), labels = c(""), name="")

# join all charts toghether
p_all <- plot_grid(y_axis, p1, p2,
                   align="v", axis="l", 
                   nrow=1, rel_widths = c(0.2, 1, 1))

ggdraw(p_all)
zx8754
  • 52,746
  • 12
  • 114
  • 209
user2053921
  • 73
  • 1
  • 4
  • what u r expecting on x axis and on y axis? generally it can be done in ggplot with `gacet_grid / facet_wrap` – sai saran Nov 09 '18 at 10:47

2 Answers2

7

This is how it looks like with several variables, some color and using tidyr. You can add the border between the plots with panel.border and should specify the number of rows to be 1 in the facet_wrap:

library(ggplot2)
library(dplyr)
library(tidyr)

# Only select variables meaningful as factor
DF <- select(mtcars, mpg, cyl, vs, am, gear, carb) 

DF %>% 
  gather(variable, value, -mpg) %>%
  ggplot(aes(factor(value), mpg, fill = factor(value))) +
  geom_boxplot() +
  facet_wrap(~variable, scales = "free_x", nrow = 1, strip.position = "bottom") +
  theme(panel.spacing = unit(0, "lines"),
        panel.border = element_rect(fill = NA),
        strip.background = element_blank(),
        axis.title.x = element_blank(),
        legend.position = "none",
        strip.placement = "outside")

enter image description here

kath
  • 7,624
  • 17
  • 32
  • Thanks. This is almost the same as alex_555's solution, only with tidyr::gather rather than reshape2::melt. I'll probably import tidyr for other functions as well so this may end up more useful eventually. – user2053921 Nov 09 '18 at 12:32
2

Is this what you want?

x <- DF
x$cars <- rownames(x)
x <- melt(x[,c("cars", "cyl", "mpg", "vs")], id.vars=c("cars", "mpg"))

ggplot(x, aes(x=value,y=mpg))+
  geom_boxplot()+
  facet_wrap(~variable, strip.position = "bottom", scales = "free_x")+
  theme(panel.spacing = unit(0, "lines"),
        strip.background = element_blank(),
        strip.placement = "outside")

I first converted your data-format with melt() so that faceting is possible. I suppose you can go from here and do the rest of the formatting by yourself.

enter image description here

alex_555
  • 1,092
  • 1
  • 14
  • 27