Hernando Casas
Hernando Casas

Reputation: 3017

prevent a second aes() to override the range of the axes (ylim, xlim) in ggplot2

I have prices over time for different types of products. I want to visualize the evolution of different prices in one single sheet, so I am using a faceted ggplot. Here's my toy example:

df1 <- data.frame(time = rep(1:100, times = 5), 
                  type = rep(c("A", "B", "C", "D", "E"), each = 100), 
                  price = rnorm(n = 500, mean = 100))

gp <- ggplot(data = df1, aes(x = time, y = price))
# scales free because the price level of each product may be different
gp <- gp + facet_wrap(~type, nrow = 3, ncol = 2, scales = "free")
gp <- gp + geom_point() + geom_line()
gp

This produces the plot I want:

enter image description here

I also have reference prices for each type of product (in a different data set), and I want to indicate those prices in the plot. So I am using geom_hline() as follows:

df2 <- data.frame(type = c("A", "B", "C", "D", "E"), 
                  refprice = c(100, 105, 95, 50, 40))
gp <- gp + geom_hline(data = df2, aes(yintercept = refprice), facets = ~type)

enter image description here

It works, but it can substantially change the range of the y-axis, and I do not want that. I'd like to keep the ylim as automatically generated by the first part, so as to properly visualize the evolution of the prices regardless of the reference price (it is ok not to see the reference price if it is not relatively close to the actual prices).

I know I can use scale_y_continuous(), coord_cartesian() or the short-hand ylim() to manually set the limits as I want, but I dislike this alternative because either requires hard-coding the limits or too much coding to calculate the appropriate limits. So I thought there must be a simpler and more elegant way in ggplot to avoid the second call to override ylims and instead take advantage of the ylims generated in the first call.

I have been searching (I think, thoroughly) for solutions to this issue (SO, google, rseek, ), and all I find involves the solutions I've just said I dislike. So I decided to post it here to see if someone knows some hidden (or not so hidden) feature in ggplot2 to make this easier and more elegant. Many thanks.

Upvotes: 2

Views: 354

Answers (1)

Roland
Roland

Reputation: 132706

yrange <- sapply(ggplot_build(gp)$panel$ranges, function(x) x$y.range)
#order df2 correctly (the same order as the panels) if it isn't

gp + geom_hline(data = df2[df2$refprice >= yrange[1,] & df2$refprice <= yrange[2,],], 
                aes(yintercept = refprice))

resulting plot

Upvotes: 1

Related Questions