CptNemo
CptNemo

Reputation: 6755

Horizontally align bars and facets

I have this two data.frames

df1 <- 
  data.frame(unit = factor(1:20, levels = 20:1),
             value = sample(1:10, 20, replace = T))

df2 <- 
  data.frame(unit = 
               factor(as.vector(sapply(1:20, FUN = function(x) rep(x, 10))).
                      levels = 1:20),
             time = rep(1:10, 20), 
             value = sample(1:100, 10*20, replace = T))

Which I want to plot side by side like this:

library(ggplot2)
library(cowplot)
plot_grid(ggplot(df1, aes(x=value,y=unit)) +
            geom_bar(stat = 'identity') +
            scale_x_continuous(position = "top"),
          ggplot(df2, aes(x=time,y=value)) +
                   geom_line() +
                   facet_grid(rows = vars(unit), scales = "free_y") +
            scale_x_continuous(position = "top") +
            theme(axis.text.y = element_text(size=6)),
          ncol = 2)

which results in this output

enter image description here

Still, the rows from the two plots, mapping variables from the same unit are not perfectly aligned:

enter image description here

What's the easiest way to align them programmatically (so that it will also work with a different number of units)? The solution doesn't need to involve the cowplot package.

Upvotes: 1

Views: 257

Answers (2)

Allan Cameron
Allan Cameron

Reputation: 173793

If we look at the way the plots are aligned, it seems clear that to have the bars matching the corresponding facets, we have to get rid of the space at either end of the bars' y axis. We can do this with scale_y_discrete(expand = c(0, 0)). We can also scale the width of the bars so that it is equal to the proportion that each of the facet panels takes up in their allotted viewports. Unfortunately this is somewhat dependent on device dimensions. However, a width of 0.8 or 0.9 will get you pretty close.

plot_grid(ggplot(df1, aes(x=value,y=unit)) +
            geom_bar(stat = 'identity', width = 0.8) +
            scale_x_continuous(position = "top") +
            scale_y_discrete(expand = c(0, 0)),
          ggplot(df2, aes(x=time,y=value)) +
                   geom_line() +
                   facet_grid(rows = vars(unit), scales = "free_y") +
            scale_x_continuous(position = "top") +
            theme(axis.text.y = element_text(size=6)),
          ncol = 2) 

enter image description here

Upvotes: 2

stefan
stefan

Reputation: 124013

A simple solution to achieve this is by using facets for the bar plot, too. As long as the spacing between the panels is the same in both plots this should ensure that the bars and the line plots for each group are aligned. Try this:

df1 <- 
  data.frame(unit = factor(1:20, levels = 20:1),
             value = sample(1:10, 20, replace = T))

df2 <- 
  data.frame(unit = factor(as.vector(sapply(1:20, FUN = function(x) rep(x, 10))), levels = 1:20),
             time = rep(1:10, 20), 
             value = sample(1:100, 10*20, replace = T))

library(ggplot2)
library(cowplot)

plot_grid(ggplot(df1, aes(x=value,y=unit)) +
            geom_bar(stat = 'identity') +
            facet_grid(rows = vars(unit), scales = "free_y") +
            scale_x_continuous(position = "top") +
            theme(panel.spacing.y = unit(1, "pt"), strip.text = element_blank()),
          ggplot(df2, aes(x=time,y=value)) +
            geom_line() +
            facet_grid(rows = vars(unit), scales = "free_y") +
            scale_x_continuous(position = "top") +
            theme(axis.text.y = element_text(size=6), panel.spacing.y = unit(1, "pt")),
          ncol = 2)

Upvotes: 2

Related Questions