Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Align discrete and continuous axes with ggplot2 and grid

I'm attempting to display a grid figure of summarized weekly data of several variables. The two components of this graph that are most pertinent are a distributional summary graph (so box plot or violin plot) of the values that a certain variables took over a given week and a cumulative count graph of an integer variable accumulating over weeks (so a step plot). I would like to plot these two graphs in on an aligned x-axis using grid. I'll be using ggplot2 to make the individual graphs, because I've got a crush on Hadley Wickham (j/k, ggplot is just really, really nice).

The problem is that geom_boxplot only takes factors for x-axis and the geom_step only takes continuous data for the x-axis. These don't necessarily align even if you force similar x-limits with coord_cartesian or scale_x_....

I've cobbled together a hack using geom_rect that will work for this specific application, but that will be a pain to adapt if, for example, I have some other factor that results in multiple boxes for a single week.

The obligatory reproducible:

library(ggplot2)
library(grid)

var1 <- data.frame(val = rnorm(300),
                   week = c(rep(25, 100), 
                        rep(26, 100), 
                        rep(27, 100))
                  )

var2 <- data.frame(cumul = cumsum(c(0, rpois(2, 15))),
                   week = c(25, 26, 27)
                  )


g1   <- ggplot(var1, aes(x = factor(week), y = val)) + 
  geom_boxplot()

g2   <- ggplot(var2, aes(x = week, y = cumul)) + 
  geom_step() + scale_x_continuous(breaks = 25:27)

grid.newpage()
grid.draw(rbind(ggplotGrob(g1),
                ggplotGrob(g2),
                size = "last"))

Example of non-aligned continuous and discrete axes

And the kludge:

library(dplyr)

chiggity_check <- var1 %>% 
  group_by(week) %>% 
  summarise(week.avg = mean(val),
            week.25  = quantile(val)[2],
            week.75  = quantile(val)[4],
            week.05  = quantile(val)[1],
            week.95  = quantile(val)[5])

riggity_rect <- ggplot(chiggity_check) +
  geom_rect(aes(xmin = week - 0.25, xmax = week + 0.25,
                ymin = week.25,
                ymax = week.75)) +
  geom_segment(aes(x = week - 0.25, xend = week + 0.25,
                   y = week.avg, yend=week.avg),
               color = "white") +
  geom_segment(aes(x = week, xend = week ,
                   y = week.25, yend=week.05)) +
  geom_segment(aes(x = week, xend = week ,
                   y = week.75, yend=week.95)) +
  coord_cartesian(c(24.5,27.5)) +
  scale_x_continuous(breaks = 25:27)

grid.newpage()
grid.draw(rbind(ggplotGrob(riggity_rect),
                ggplotGrob(g2 + coord_cartesian(c(24.5,27.5))),
                size = "last"))

Example of kludged together grid graph

So the question(s) is/are: is there a way to force geom_boxplot to a continuous axis or geom_step to a factor axis? Or is there some other implementation, perhaps stat_summary that will be a bit more flexible so that I can align axes and also potentially easily add in things like grouping color variables?

like image 255
Dalton Hance Avatar asked Jul 08 '15 17:07

Dalton Hance


1 Answers

One approach is to plot the two charts on an x-axis set up with factor(week), but in the g2 plot (the step plot) do so in geom_blank() so that the scale is set up. Then in geom_step(), plot on a numeric scale: as.numeric(factor(week))

library(ggplot2)
library(grid)

# Your data
var1 <- data.frame(val = rnorm(300),
                   week = c(rep(25, 100), 
                        rep(26, 100), 
                        rep(27, 100))
                  )

var2 <- data.frame(cumul = cumsum(c(0, rpois(2, 15))),
                   week = c(25, 26, 27)
                  )

# Your g1
g1   <- ggplot(var1, aes(x = factor(week), y = val)) + 
  geom_boxplot()

# Modified g2
g2   <- ggplot(var2) + geom_blank(aes(x = factor(week), y = cumul)) +
geom_step(aes(x = as.numeric(as.factor(week)), y = cumul)) 

grid.newpage()
grid.draw(gridExtra::rbind.gtable(ggplotGrob(g1),
                ggplotGrob(g2),
                size = "last"))

enter image description here

like image 123
Sandy Muspratt Avatar answered Oct 19 '22 19:10

Sandy Muspratt