4

I would like to automatically adjust the ggplot graphs while plotting side-by-side.

library(ggplot2)
library(gridExtra)

set.seed(123)
freq <- sample(1:10, 7, replace = T)
labels <- c('AUS', 'NZ', 'ENG', 'SOC', 'PAK', 'SRI', 'IND')
value <- paste("i",1:10,sep='')

lab <- rep(unlist(lapply(1:length(freq), function(x) rep(labels[x],freq[x]))),2)
ival <- rep(unlist(lapply(1:length(freq), function(x) value[1:freq[x]])),2)

df <- data.frame(lab, ival, type=c(rep('Type1',42),rep('Type2',42)),val=runif(84,0,1))

Plotting the data generated using the random process above.

plotUng <- ggplot(df, aes(x=ival, y=val, col = type, group = type)) + 
  geom_line() + 
  geom_point(aes(x=ival, y=val)) +
  facet_wrap( ~lab, ncol=3) + 
  theme(axis.text.x=element_text(angle=45, vjust=0.3)) + 
  scale_x_discrete(limits=paste('i',1:10,sep=''))

Now grouping the data in lab based on some condition. Now I would like to generate new plot based on the grouped data.

dfGrp <- df %>% mutate(lab = recode(lab, 'AUS' = 'A', 'NZ' = 'A', 'ENG' = 'A', 
                                    'SOC' = 'A', 'PAK' = 'B', 'SRI' = 'B')) %>% 
  group_by(lab, ival, type) %>% mutate(val = mean(val)-0.2) %>% ungroup() %>% distinct()

plotG <- ggplot(dfGrp, aes(x=ival, y=val, col = type, group = type)) + 
  geom_line() + 
  geom_point(aes(x=ival, y=val)) +
  facet_wrap( ~lab, ncol=3) + 
  theme(axis.text.x=element_text(angle=45, vjust=0.3)) + 
  scale_x_discrete(limits=paste('i',1:10,sep=''))

Plotting the above two plots side-by-side for comparison using grid.arrange.

grid.arrange(plotUng, plotG, ncol=2)

enter image description here

Adjusting the y-axis limits after manual inspection of the above plot that plotUng has wider limits than plotG. So, adjusted the limits of plotG with the limits of plotUng as coord_cartesian(ylim = ggplot_build(plotUng)$layout$panel_ranges[[1]]$y.range).

grid.arrange(plotUng, plotG + coord_cartesian(ylim = ggplot_build(plotUng)$layout$panel_ranges[[1]]$y.range), ncol=2)

enter image description here

The above plot is as expected. Is there any way to do this automatically(just with the plot objects) without manual inspection, as it is not always possible to manually inspect all the plots and adjust the axis limits accordingly?

Prradep
  • 5,506
  • 5
  • 43
  • 84
  • Were you able to get addressed? I'm looking for a similar way to do this too. I am looking to expand the y axis only for certain graphs (where a value is greater than 100 for example), but the rest of the graphs would be a max y axis of 75. – Scott R Feb 22 '21 at 20:20
  • 1
    @ScottR Nope, I haven't found an automated way. If you find a better way, please share it with me. Thanks! – Prradep Feb 23 '21 at 09:30
  • I went ahead and posted my question about this. It's not quite the same as yours, but hopefully could offer some inspiration of sorts. https://stackoverflow.com/questions/66335729/for-graphing-a-time-series-r-how-do-i-set-a-variable-minimum-and-maximum-y-axis – Scott R Feb 23 '21 at 15:09

1 Answers1

2

What you did with ggplot_build() can be automated. But for me the simplest way to compare several plots is to find the minimum and maximum values for all objects to be compared, and then put these values as coord_cartesian() of every objects. For example here :

lim_y <- c( min(df$val, dfGrp$val), max(df$val, dfGrp$val) )

plotUng <- plotUng + coord_cartesian(ylim = lim_y)
plotG <- plotG + coord_cartesian(ylim = lim_y)

grid.arrange(plotUng, plotG, ncol=2)

enter image description here

Since finding the extreme values of several columns is straightforward, this is the most "automated" way I've found.

Note that the coordinate problems only happens for y-limits in ggplot

  • 1
    Thanks for another approach of identifying the limits of y-axis and adjusting the plots according to the new limits. I was requesting for suggestions where the existence of the automatic methods would do the needful. I meant only with plot objects the arrangement would be done automatically by adjusting the limits. – Prradep Oct 17 '17 at 10:53
  • Sorry but I do not really get it; what do you mean by "automatic" ? – Antoine Pissoort Oct 17 '17 at 13:17
  • 1
    Apologies for replying you late. I meant without calculating the `lim_y` after the plots have been generated. Instead input: a set of plots(more than 1); output: arrangement of the input plots with adjusted limits. Here the code changes when the input changes. I am asking if there are any approaches where output only changes when the input is changed. Hope it is clear now. – Prradep Oct 20 '17 at 14:04
  • I don't understand because `lim_y` is computed before the plots have been generated. So, an automate solution is straightforward from what I've given above : for any inputs, you calculate the maximum and the minimum and then you adjust the limits. You just have to create a function to do this with the example above. Is it more clear or do you want me to clarify this ? – Antoine Pissoort Oct 20 '17 at 15:20