1

I am using ggplot2 to produce a plot that has 3 facets. Because I am comparing two different data sets, I would like to then be able to plot a second data set using the same y scale for the facets as in the first plot. However, I cannot find a simple way to save the settings of the first plot to then re-use them with the second plot. Since each facet has its own y scale, it will be a pain to specify them by hand for the second plot. Does anyone know of a quick way of re-using scales? To make this concrete, here is how I am generating first my plot:

p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p + facet_wrap(~ cyl, scales = "free_y")

enter image description here

EDIT

When applying one of the suggestions below, I found out that my problem was more specific than described in the original post, and it had to do specifically with scaling of the error bars. Concretely, the error bars look weird when I rescale the second plot as suggested. Does anyone have any suggestions on how to keep the same scale for both plots and dtill display the error bars correctly? I am attaching example below for concreteness:

#Create sample data
d1 <- data.frame(fixtype=c('ff','ff','fp','fp'), detype=c('det','pro','det','pro'),
             diffscore=c(-1,-15,3,-17),se=c(2,3,1,2))
d2 <- data.frame(fixtype=c('ff','ff','fp','fp'), detype=c('det','pro','det','pro'),
             diffscore=c(-1,-3,-2,-1),se=c(4,3,5,3))

#Plot for data frame 1, this is the scale I want to keep
lim_d1 <- aes(ymax = diffscore + se, ymin=diffscore - se)
ggplot(d1, aes(colour=detype, y=diffscore, x=detype)) + 
geom_point(aes(size=1), shape=15) +
geom_errorbar(lim_d1, width=0.2,size=1) +
facet_wrap(~fixtype, nrow=2, ncol=2, scales = "free_y")

Plot for data frame 1

#Plot for data frame 2 original scale
lim_d2 <- aes(ymax = diffscore + se, ymin=diffscore - se)
ggplot(d2, aes(colour=detype, y=diffscore, x=detype)) + 
  geom_point(aes(size=1), shape=15) +
  geom_errorbar(lim_d2, width=0.2,size=1) +
  facet_wrap(~fixtype, nrow=2, ncol=2, scales = "free_y")

Plot for data frame 2

#Plot for data frame 2 adjusted scale. This is where things go wrong!
#As suggested below, first I plot the first plot, then I draw a blank screen and try
#to plot the second data frame on top. 
lim_d2 <- aes(ymax = diffscore + se, ymin=diffscore - se)
ggplot(d1, aes(colour=detype, y=diffscore, x=detype)) + 
  geom_blank() +
  geom_point(data=d2, aes(size=1), shape=15) +
  geom_errorbar(lim_d2, width=0.2,size=1) +
  facet_wrap(~fixtype, nrow=2, ncol=2, scales = "free_y")

Plot for data frame 2, messed up error bars

#If the error bars are fixed, by adding data=d2 to geom_errorbar(), then
#the error bars are displayed correctly but the scale gets distorted again
lim_d2 <- aes(ymax = diffscore + se, ymin=diffscore - se)
ggplot(d1, aes(colour=detype, y=diffscore, x=detype)) + 
  geom_blank() +
  geom_point(data=d2, aes(size=1), shape=15) +
  geom_errorbar(data=d2,lim_d2, width=0.2,size=1) +
  facet_wrap(~fixtype, nrow=2, ncol=2, scales = "free_y")

enter image description here

Sol
  • 724
  • 1
  • 5
  • 18
  • 1
    Because you don't use the `data` argument in `geom_errorbar`, `ggplot` makes its 'best guess' and picks the data used in the `ggplot` call (i.e. d1). Which is not what you want. Try to add `data = the-relevant-dataset` in `geom_errorbar`, just as you used the `data` argument in `geom_point`. – Henrik May 15 '14 at 13:48
  • Thanks Henrik. But when I add `data=d2` to `geom_errorbar` in the example above, the scale gets distorted again. Don't you get that as well? – Sol May 15 '14 at 14:57
  • The interestingly weird thing is that the scale gets distorted such that is is neither the scale used in `d1` nor in `d2`(?!) – Sol May 15 '14 at 15:03
  • 1
    If you know that the 'first' data set used in `geom_blank` not necessarily has the largest range, you might need to set up a dummy data frame which accounts for the range of your data _across_ data sets, as described [**here**](http://stackoverflow.com/questions/18046051/setting-individual-axis-limits-with-facet-wrap-and-scales-free-in-ggplot2/21585521#21585521) – Henrik May 15 '14 at 17:55
  • Thanks Henrik! I think that it should be ok, as I chose the first data set so that it is the one with the largest range. I still can't figure out the problem with `geom_errorbar` so I am just going to use `geom_pointrange` instead for the time being – Sol May 15 '14 at 18:11
  • 1
    I doubt the problem is `geom_errorbar` itself. In d1 the largest value is (-1 + 2) for ff, while in d2 it is (-1 + 4). You set up the plot according to `x` and `y` in d1, _not_ `ymax` and `ymin` (you may wish to move them to `aes` in `ggplot`). So the scale needs to be adjusted when you plot the larger `ymax` value in d2. – Henrik May 15 '14 at 18:20

2 Answers2

3

You may first call ggplot on your original data where you add a geom_blank as a first layer. This sets up a plot area, with axes and legends based on the data provided in ggplot.

Then add geoms which use data other than the original data. In the example, I use a simple subset of the original data.

From ?geom_blank: "The blank geom draws nothing, but can be a useful way of ensuring common scales between different plots.".

ggplot(data = mtcars, aes(mpg, wt)) +
  geom_blank() +
  geom_point(data = subset(mtcars, wt < 3)) +
  facet_wrap(~ cyl, scales = "free_y")
Henrik
  • 65,555
  • 14
  • 143
  • 159
  • This looks like exactly like what I need! However, when I tried to apply this strategy to my data I found out that the problem was still occurring because I had error bars. I updated my description of the problem above. Would it be possible for you take a look if you have some time? Thanks a lot! – Sol May 15 '14 at 13:34
1

Here is an ugly hack that assumes you have an identical facetting layout in both plots. It replaces the panel element of the ggplot build.

p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p1 <- p + facet_wrap(~ cyl, scales = "free_y") + labs(title = 'original')
# create "other" data.frame
n <- nrow(mtcars)
set.seed(201405)
mtcars2 <- mtcars[sample(seq_len(n ),n-15),]
# create this second plot
p2 <- p1 %+% mtcars2 + labs(title = 'new data')
# and a copy so we can attempt to fix
p3 <- p2 + labs(title = 'new data original scale')
# use ggplot_build to construct the plots for rendering
p1b <- ggplot_build(p1)
p3b <- ggplot_build(p3)
# replace the 'panel' information in plot 2 with that
# from plot 1
p3b[['panel']] <- p1b[['panel']]
# render the revised plot

# for comparison
library(gridExtra)

grid.arrange(p1 , p2, ggplot_gtable(p3b))

enter image description here

mnel
  • 113,303
  • 27
  • 265
  • 254