Reilstein
Reilstein

Reputation: 1252

ggplot: align multiple faceted plots - facets all different sizes

I am trying to align multiple plots with facets. My problem is somewhat minor but irratating: I can make a plot so that the plot areas are aligned and the facets themselves are aligned, but the facet strips are not all the same width. If the labels of the facets are different lengths, then the facet strips are sized so that the text can fit within the facets. I am unable so far to find a way to make all facet strips the same width when aligning multiple plots.

Here is an example of the type of plots I want to align and my efforts to align them:

library(data.table)
library(ggplot2)
library(foreach)
library(stringr)
library(cowplot)

# example data to show how aligning faceted plots is not quite right
plotvars = c(paste0("plot1_var", 1:7), paste0("plot2_var",1:5), paste0("plot3_var",1:10))
data = 
  foreach(p=plotvars,.combine = "rbind") %do% {
    d = data.table(plot = rep(str_extract(p,pattern = "plot[[:digit:]]"),2),
               plot_variables = rep(p,2),
               fill_categories = c("fill1","fill2"),
               number = sample(1:1000, size = 2))
    d[, facet_variables := ifelse(plot=="plot1", 
                                  rep(sample(paste0("facet",1:3),size=1),2),
                                  ifelse(plot=="plot2",
                                         rep(sample(paste0("facet_title",1:3),size=1),2),
                                         ifelse(plot=="plot3",
                                                rep(sample(paste0("facet_title_longer",1:3),size=1),2),
                                                NA)))]
    d
  }

# function to make stacked barplots with facets + coord_flip
make_plot = function(data, plot_var) {
  ggplot(data[plot==plot_var],
         aes(x=plot_variables,
             y=number,
             fill=fill_categories))+
    geom_bar(stat="identity")+
    coord_flip()+
    facet_grid(facet_variables ~ ., 
               space="free",
               scales="free")+
    theme(strip.text.y = element_text(angle=0),
          legend.position = "none")
}
p1 = make_plot(data=data,plot_var="plot1")
p1

p1

p2 = make_plot(data=data,plot_var="plot2")
p2

enter image description here

p3 = make_plot(data=data,plot_var = "plot3")
p3

enter image description here

# using 'cowplot::plot_grid' gives strange re-sizing of individual bars
cowplot::plot_grid(p1,p2,p3, ncol=1,nrow=3,align = "hv")

enter image description here

# try gtable_rbind version
g1=ggplotGrob(p1)
g2=ggplotGrob(p2)
g3=ggplotGrob(p3)

# this plot keeps the bar widths the correct size, but the facets are still incorrectly different widths.
ggdraw(gridExtra::gtable_rbind(g1,g2,g3))

enter image description here

How can I make the facet strips the same width across plots?

Upvotes: 5

Views: 2898

Answers (3)

Claus Wilke
Claus Wilke

Reputation: 17790

The facet strips are wrapped inside another table, and you need to adjust the widths there. The following seems to work.

g1 <- ggplotGrob(p1)
g2 <- ggplotGrob(p2)
g3 <- ggplotGrob(p3)

# g3 has the widest strips, so get the width from there and copy over
# to the other plots
stripwidth <- g3$grobs[[13]]$widths 
g1$grobs[[13]]$widths <- stripwidth
g1$grobs[[14]]$widths <- stripwidth
g1$grobs[[15]]$widths <- stripwidth

g2$grobs[[13]]$widths <- stripwidth
g2$grobs[[14]]$widths <- stripwidth
g2$grobs[[15]]$widths <- stripwidth

ggdraw(gridExtra::gtable_rbind(g1,g2,g3))

enter image description here

Upvotes: 1

Andrew Gustar
Andrew Gustar

Reputation: 18425

You can achieve something like this with a labeller function that inserts a second row of blank spaces of whatever length you want. Using mtcars...

#define a function to add a second line of spaces after a given label 
#and a blank line before to maintain the centre vertical alignment
#you might need to play with the appropriate value to get the width right
widen <- function(x) paste(" \n", x, "\n", paste0(rep(" ", 20), collapse=""))

mtcars %>% ggplot(aes(x = mpg)) +
  geom_histogram() +
  facet_grid(cyl ~ ., labeller = labeller(cyl = widen)) +
  coord_flip() +
  theme(strip.text.y = element_text(angle = 0))

enter image description here

Upvotes: 2

Nathan Werth
Nathan Werth

Reputation: 5263

Change this part

facet_grid(facet_variables ~ ., 
           space="free",
           scales="free")+

to

facet_grid(facet_variables ~ ., 
           space="fixed",    # This is the difference
           scales="free")+

Upvotes: -1

Related Questions