I am trying to plot two lines with ggplot. The second line has a different scale and I would like to have a secondary axis for it, which is completely independent from the first.
I have already looked at other answers (like this one), but I understand that ggplot can only handle the secondary axis if it is a rescaling of the first one. I also understand the limitations and caveats of using a secondary axis, as explained in the linked answer. However, I just need to do it this way.
I need to achieve something like the following graph (which is super easy to do in Excel…):
Also, how do I get the legend entries to be stacked in one column? The legend.box = "vertical"
does not seem to work as desired.
Here is a minimal working version of my data:
dt <- structure(list(time = c(2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), y1 = c(2.31631335338909,
-0.353036222182179, 0.822172487550787, 1.65036005686483, 3.19324989973053,
1.36886369415437, 1.31791693469558, 0.184416719383496, -1.48872180894084,
-0.92173552297502, 3.9135578292683, 0.346256544376589, 1.91127730330776,
0.786333884748602, 1.58411983190534, 1.42796690725975, 1.19061818749784,
1.86907738573789, 2.20102287412618, 0.74258282086539, 0.558112794652055,
0.738532378963908, -1.32864718685318, 1.42498210081179, 2.51616000832833,
1.77839234915598), y2 = c(128.2294422, 124.4007109, 123.4816498,
122.9197759, 127.1120084, 126.7419716, 126.5872646, 126.038439,
127.601628, 128.8175759, 135.1116, 132.4616906, 132.6761827,
132.9141464, 134.0523005, 133.7149933, 133.7150548, 136.17692,
137.6007351, 135.2282579, 136.9279822, 138.9379415, 140.1117915,
131.9687439, 134.7674794, 135.7405411)), row.names = c(NA, -26L
), class = c("data.table", "data.frame"))
p <-
ggplot(data = dt,
aes(x = time)
) +
# Line
geom_line( data = dt,
aes( y = y1,
colour = "% change"
)
) +
geom_line( data = dt,
aes( y = y2,
colour = "Index"
)
) +
theme(
legend.box = "vertical",
legend.position = "bottom",
legend.title = element_blank()
)
1
Scale the y2 values for the secondary axis, then add it to the plot with sec_axis
. Use guides()
to alter the legend.
a <- (max(dt$y1) - min(dt$y1))/(max(dt$y2) - min(dt$y2))
b <- max(dt$y1) - a * max(dt$y2)
dt$y2_new <- a * dt$y2 + b
#y = (y2 - b)/a # reverse transformation
ggplot(data = dt,
aes(x = time)) +
# Line
geom_line( data = dt,
aes( y = y1,
colour = "% change")) +
geom_line( data = dt,
aes( y = y2_new,
colour = "Index")) +
scale_y_continuous(name="% change",
sec.axis = sec_axis(~(. - b)/a, name="Index")) +
theme(
# legend.box = "vertical",
legend.position = "bottom",
legend.title = element_blank()) +
guides(color=guide_legend(ncol=1))
0