I'm trying to add a second y-axis to ggplot. One y-axis is a discrete variable and is arbitrary while the other is continuous so no scaling is necessary. This is to visualize temperatures during a specific time in an organism's life.
Sample data and code:
samp.dat <- structure(list(
id = c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"),
julian = c(144, 152, 151, 152, 152, 149, 152,151, 149, 155, 42),
start = c(136, 143, 141, 142, 140, 137, 138, 134, 130, 132, 130),
last = c(144, 152, 151, 152, 152, 149, 152,151, 149, 155, 142)),
class = "data.frame",
row.names = c(NA, -11L))
samp.wx <- structure(list(
julian = c(130L, 131L, 132L, 133L, 134L, 135L, 136L, 137L, 138L, 139L, 140L, 141L, 142L, 143L, 144L, 145L, 146L, 147L, 148L, 149L, 150L, 151L, 152L, 153L, 154L, 155L),
daily.max = c(31.55, 29.25, 29.3, 29.8, 24.7, 17.75, 15.85, 21.2,14.05, 15.85, 21.1, 20, 24.3, 26.45, 26.35, 23.1, 17.3, 22.9, 28.85, 30.85, 28.5, 31.15, 33, 30.85, 32.25, 36)),
row.names = c(NA, -26L),
class = "data.frame")
ggplot(samp.dat, aes(x = julian, y = id)) +
geom_segment(aes(x = start, xend = last, y = id), color = 'red') +
geom_line(samp.wx, mapping = aes(x = julian, y = daily.max)) +
scale_x_continuous(limits = c(130, 155))
When I try it in ggplot it does plot both data sets, but sitting above one another with no second y-axis:
I have also tried keeping ggplot()
empty and coding directly into geom_segment()
and geom_line()
as well as putting the continuous data into ggplot()
instead of the discrete, but neither of those worked.
Is there a way to do this? I know many frown upon dual axes, but for my purpose visually it makes the most sense to have these data in the same figure to see how they line up with one another.
My other thought was to make the figures transparent and just overlap them in a document, but I was hoping for something a little cleaner.
Secondary axes in ggplot2 are a "decoration"; to use them, you effectively need to transform your various data series to work in the same plot space, and then adjust the labels to look like the original data.
In this case, you have 11 categorical variables, which could be converted to the numbers 1:11. And you have temperature data that ranges from 15 to 35. To make them appear in the same space, we either need to map the categorical range to the temperature range (as I've done here), or map the temperatures the the range 1:11. In either case we need to adjust the labels to get back to where we started.
Here's one of many possible variations to have the two plots overlaid in the same space. In this case I convert the categorical data to factor and then to numeric, so a:k become 1:11. Multiplying these by 2 and adding 13 puts them in the same range as the temperatures. You could do it the other way around too.
ggplot(samp.dat, aes(x = julian, y = as.numeric(as.factor(id))*2+13)) +
geom_segment(aes(x = start, xend = last,
yend = as.numeric(as.factor(id))*2+13), color = 'red') +
geom_line(samp.wx, mapping = aes(x = julian, y = daily.max)) +
scale_y_continuous(breaks = seq(15,35, 2), labels = letters[1:11],
minor_breaks = NULL, name = "id",
sec.axis = sec_axis(transform = ~.x, name = "daily max",
breaks = seq(15,35,4))) +
scale_x_continuous(limits = c(130, 155))