Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a table to ggplot with gridExtra and annotation_custom() changes y-axis limits

I tried adding a little summary table to a plot which I created with ggplot2::ggplot(). The table is added via gridExtra::tableGrob() to the saved ggplot object.

My problem is that this seems to change the y-limits of my original plot. Is there a way to avoid that without having to specify the limits again via ylim()?

Here is a minimal example for the problem using the ChickWeight dataset:

# load packages
require(ggplot2)
require(gridExtra)

# create plot
plot1 = ggplot(data = ChickWeight, aes(x = Time, y = weight, color = Diet)) +
        stat_summary(fun.data = "mean_cl_boot", size = 1, alpha = .5) 
plot1
# create table to add to the plot
sum_table = aggregate(ChickWeight$weight, 
                      by=list(ChickWeight$Diet), 
                      FUN = mean)
names(sum_table) = c('Diet', 'Mean')
sum_table = tableGrob(sum_table)

# insert table into plot
plot1 + annotation_custom(sum_table)

ylim problem with annotation_custom()

EDIT: I just figured out that it seems to be an issue with stat_summary(). When I use another geom/layer, then the limits stay as they were in the original plot. Another example for that:

plot2 = ggplot(data = ChickWeight, aes(x = Time, y = weight, color = Diet)) +
        geom_jitter() 
plot2
plot2 + annotation_custom(sum_table)

ylim problem with annotation_custom()

like image 294
abel Avatar asked Jan 13 '16 15:01

abel


1 Answers

The y-range for plot1 is different from plot2, the reason being that annotation_custom takes its aesthetics from the original aes statement, not the modified data frame used by stat_summary(). To get the y-ranges for the two plots to be the same (or roughly the same - see below), stop annotation_custom getting its aesthetics from the original data. That is, move aes() inside the stat_summary().

# load packages
require(ggplot2)
require(gridExtra)

# create plot
plot1 = ggplot(data = ChickWeight) +
        stat_summary(aes(x = Time, y = weight, color = Diet), fun.data = "mean_cl_boot", size = 1, alpha = .5) 
plot1

# create table to add to the plot
sum_table = aggregate(ChickWeight$weight, 
                      by=list(ChickWeight$Diet), 
                      FUN = mean)
names(sum_table) = c('Diet', 'Mean')
sum_table = tableGrob(sum_table)

# insert table into plot
plot2 = plot1 + annotation_custom(sum_table, xmin = 10, xmax = 10, ymin = 200, ymax = 200) 
plot2

enter image description here

By the way, the reason the two plots will not give the exact same y-range is because of the bootstrap function in stat_summary(). Indeed, plot p1 repeatedly, and you might notice slight changes in the y-range. Or check the y-ranges in the build data.

Edit Updating to ggplot2 ver 3.0.0

ggplot_build(plot1)$layout$panel_params[[1]]$y.range
ggplot_build(plot2)$layout$panel_params[[1]]$y.range

Recall that ggplot does not evaluate functions until drawing time - each time p1 or p2 is drawn, a new bootstrap sample is selected.

like image 154
Sandy Muspratt Avatar answered Sep 26 '22 11:09

Sandy Muspratt