9
votes

Say I have a data frame and want to make a plot

df <- melt(iris)

p <- ggplot(data = df, aes(x = Species, y = value)) + 
       geom_boxplot() + theme(aspect.ratio = 1)

I then want to use ggsave() to save a pdf of this plot

ggsave(plot = p, width = 3, height = 3, dpi = 300, filename = "not squished axis.pdf")

enter image description here

The problem is that I want to specify the dimensions of the plot itself but independently of the axis labels so that the plot specified below will have the same size and dimensions in terms of the absolute length of the axes.

q <- ggplot(data = df, aes(x = Species, y = (value)*10000000)) +
       geom_boxplot() + theme(aspect.ratio = 1)

ggsave(plot = q, width = 3, height = 3, dpi = 300, filename = "squished axis.pdf")

enter image description here

Is there a way to do this easily?

Here is an example of a plot closer to what I would like in terms of the axis lengths:

enter image description here

the only problem is that by changing the aspect ratio, I end up squishing the y axis to make the x axis closer to even in length...

5
I don't understand the question. "Independent of axis labels" meaning what? If you specify height and width in ggsave the plot will have the same dimensions (in pixels/inches) and (depending on the data) different axis ranges. Can you include a mockup/sample figure of what you'd like to achieve? - Maurits Evers
the absolute length of the axes is different in the two plots above because the y axis break labels are longer in the second plot than in the first plot. I would like to be able to have different length axis labels but maintain the same x axis and y axis lengths. I have updated the question with a third plot that looks closer to what I would like to achieve - John Gagnon
@MauritsEvers I'm having trouble making a representative plot of what I want but essentialy I want the size of the graphing area (i.e., the length in inches of the x and y axes) to be consistent between plots that have longer labels for the y axis as a result of the numbering being in a longer format - John Gagnon
I'm sorry but I have no idea what you mean/want. You say that "the only problem is that by changing the aspect ratio, I end up squishing the y axis to make the x axis closer to even in length". I don't understand what that means. Do you want to have the same scale for two plots having different ranges? If so, you can use facet_wrap to plot both datasets on the same scale. See my example below. - Maurits Evers

5 Answers

4
votes

Use ggplotGrob. Something like this:

g1 <- ggplot(...)
g2 <- ggplot(...)

g1grob <- ggplotGrob(g1)
g2grob <- ggplotGrob(g2)

grid.arrange(g1grob, g2grob)
4
votes

I don't really understand what you're after, so this is a bit of a stab in the dark.

You can show two plots using the same scale using facet_wrap:

# Your sample data
df <- list(
    one = melt(iris),
    two = with(melt(iris), cbind.data.frame(Species, variable, value * 1000)));
df <- melt(df);

ggplot(df, aes(x = Species, y = value)) + 
    geom_boxplot() + theme(aspect.ratio = 1) + 
    facet_wrap(~ L1);

enter image description here

Or allow the y-scale to vary freely for every facet.

ggplot(df, aes(x = Species, y = value)) + 
    geom_boxplot() + theme(aspect.ratio = 1) + 
    facet_wrap(~ L1, scales = "free_y");

enter image description here

You can tune the grid layout of the facets, by specifying the number of columns or rows using nrow and ncol.

So for example, for vertical placement of both plots you can do

ggplot(df, aes(x = Species, y = value)) + 
    geom_boxplot() + theme(aspect.ratio = 1) + 
    facet_wrap(~ L1, ncol = 1, scales = "free_y");

enter image description here

3
votes

I observed the same behavior which is magnified when using vertical labels on the x-axis.

Using the following code the area of the plot will vary due to the differences in the label lengths.

library(ggplot2)
library(gridExtra)


df1 <- data.frame(x_label=c(rep("one", 10), rep("two", 20), rep("three", 30))) 

plt1 <- ggplot(data.frame(df1), aes(x=x_label)) +
  ggtitle("My test data percentages") + 
  labs(x="", y="Percentage" ) + 
  geom_bar(aes(y = ( (..count..)/sum(..count..) * 100.0) ), width=1) +
  expand_limits(y=c(0.0, 50.0)) +
  theme_light() +
  theme(plot.title = element_text(hjust = 0.5), axis.text.x=element_text(angle=90, hjust=1, size=8), panel.spacing.x=unit(0.5, "lines")) 

df2 <- data.frame(x_label=c(rep("very long label one", 10), rep("very long label two", 20), rep("very long label three", 30))) 

plt2 <- ggplot(data.frame(df2), aes(x=x_label)) +
  ggtitle("My test data percentages") + 
  labs(x="", y="Percentage" ) + 
  geom_bar(aes(y = ( (..count..)/sum(..count..) * 100.0) ), width=1) +
  expand_limits(y=c(0.0, 50.0)) +
  theme_light() +
  theme(plot.title = element_text(hjust = 0.5), axis.text.x=element_text(angle=90, hjust=1, size=8), panel.spacing.x=unit(0.5, "lines")) 

gridExtra::grid.arrange(plt1, plt2, nrow=1)

Plot area changes as a function of label length

1
votes

This is a bit late to answer your question, but I think this post may help: ggplot2, arrange multiple plots, all the same size, no gaps in between

So basically you want the plotting area (area inside the x and y axis) to be the same for multiple graphs. This is an issue I have found with using ggplot2 as well. One solution is to pass each plot through the align_plots() function in the cowplot package:

`allplotslist <- align_plots(plot1, plot2, plot3, align = "hv")`

This makes the plot area of all the plots the same size. Then you can use ggdraw() (also from cowplot) to place the plots into the same figure, specifying the co-ordinates for each plot, and the size as (x co-ord, y co-ord, width, height):

`final_figure <- ggdraw() + draw_plot(allplotslist[[1]], 0,0,0.3,0.3) + 
draw_plot(allplotslist[[2]], 0,0.3,0.3,0.3) + draw_plot(allplotslist[[3]], 0,0,0.6,0.3)`

you could also use other functions like plot_grid() (from cowplot) or grid.arrange() (from gridExtra package) to plot the new plots that are all the same size:

`grid.arrange(allplotslist[[1]], allplotslist[[2]], allplotslist[[3]])`

Hope that helps, Cheers

0
votes

I think it is a bit late, but I solved this problem by fixing the nchar of the labels. It's not a very general solution, I know. I needed 30 (or more) separates plots. The number of observations where in a separate underlying grob, so the x-axis has to be fixed in size. Hope this will helps someone