rggplot2scalefigureggsave

Save multiple ggplot figures as the same scale using ggsave, despite x axis text having different lengths


I am trying to create a set of multiple figures that are the same scale. I have set the scale as the same for all figures, but when I save using ggsave, the figures save as different sizes because of the x-axis text lengths, making the scales not the same (i.e. while both go from 0-5, they are different sizes in the exported figure). I've tried assigning width and height in ggsave to counteract this, but the figures still export with different scale heights. I cannot use facet_wrap or something similar because I am exporting these as transparent to overlay on a map.

Here is an example of my data:

table <- "Year Width_mm   Length_mm  Colour
1  1990     1.68 3.19 Blue
2  1990     1.47 2.88 Blue
3  1990     1.64 2.90 Blue
4  1990     1.80 3.20 Blue
5  2001     1.76 3.12 Blue
6  2001     1.61 3.11 Blue
7  2001     1.57 3.51 Blue
8  2001     1.48 3.54 Blue
9  2002     1.46 4.05 Green
10 2002     1.83 4.03 Green
11 2003-2004     1.83 4.11 Green
12 2003-2004     1.83 4.51 Green
13 2003-2004     1.83 4.12 Green
14 2005     1.83 3.55 Green
15 2005     1.83 3.57 Green
16 2005     1.83 3.55 Green"

#Create a dataframe with the above table
df <- read.table(text=table, header = TRUE)
df

Here is the code to create and export the figures:

# Plot of length for blue
length.blue <- ggplot(df %>% filter(Colour=="Blue"), aes(x = Year, y = Length_mm)) + 
  geom_bar(stat="identity", position="dodge", fill = "#000000") +
  xlab("") + 
  ylab("") +
  scale_y_continuous(limits = c(0,5)) +
  #labs(fill = "") +
  theme_classic() +
  theme(legend.position = "") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        axis.text.x = element_text(size = 40, angle = 90),
        axis.text.y = element_text(size = 40),
        axis.line = element_line(size = 2),
        panel.background = element_rect(fill = "transparent", colour = NA),
        plot.background = element_rect(fill = "transparent", colour = NA)) 

length.blue

# Plot of length for green
length.green <- ggplot(df %>% filter(Colour=="Green"), aes(x = Year, y = Length_mm)) + 
  geom_bar(stat="identity", position="dodge", fill = "#000000") +
  xlab("") + 
  ylab("") +
  scale_y_continuous(limits = c(0,5)) +
  #labs(fill = "") +
  theme_classic() +
  theme(legend.position = "") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        axis.text.x = element_text(size = 40, angle = 90),
        axis.text.y = element_text(size = 40),
        axis.line = element_line(size = 2),
        panel.background = element_rect(fill = "transparent", colour = NA),
        plot.background = element_rect(fill = "transparent", colour = NA)) 

length.green

# Save figures
ggsave("length.blue.png", plot = length.blue, dpi=90, width = 5, height = 7)
ggsave("length.green.png", plot = length.green, dpi=90, width = 5, height = 7)

Edit:

Right now, this exports as: Current output

But I want it to export to something like this: Desired output


Solution

  • In ggplot, the panel size is determined by how much space is left after the titles and axes are drawn. To get the panel sizes to match, you can build both plots, then copy the dimensions of the resulting gtable over from the green to the blue plot:

    blue_plot <- ggplot_gtable(ggplot_build(length.blue))
    blue_plot$heights <- ggplot_gtable(ggplot_build(length.green))$heights
    
    ggsave("length.blue.png", plot = blue_plot, dpi=90, width = 5, height = 7)
    ggsave("length.green.png", plot = length.green, dpi=90, width = 5, height = 7)
    

    This results in

    length.blue.png                                                             length.green.png

    enter image description here