Yves
Yves

Reputation: 556

Add a second y-axis to ggplot

I have the following data set:

structure(list(Jahr = 2005:2019, Fahrrad = c(275208L, 296105L, 
308336L, 313363L, 326017L, 311756L, 302193L, 295702L, 268773L, 
268295L, 256726L, 248916L, 250242L, 233652L, 230464L), E.Bike = c(1792L, 
3181L, 5825L, 12600L, 23886L, 39247L, 49615L, 52941L, 49362L, 
57613L, 66332L, 75665L, 87987L, 111661L, 133032L), gesamt = c(277000L, 
299286L, 314161L, 325963L, 349903L, 351003L, 351808L, 348643L, 
318135L, 325908L, 323058L, 324581L, 338229L, 345313L, 363496L
)), class = "data.frame", row.names = c(NA, -15L))

My goal is to create a graph that shows on the left y-axis the absolute purchases of different bike types. On the right y-axis id like to show the ratio of "E-Bike" purchases over "Fahrrad" purchases to emphasize the trend (if both are sold equally the desired value is 100, if e-bike is less than below 100). Something like this:

desired output

Is that even possible? I know ggplot doesn't allow some second y-axis.

Here is the code to produce the plot below (without the MS paint edits)

dfm <- melt(df, id="Jahr")

dfm$variable <- factor(dfm$variable, levels = c("gesamt", "Fahrrad", "E.Bike"))
dfm$variable <- revalue(dfm$variable, c("E.Bike"="E-Bike"))
dfm$value <- dfm$value/1000

ggplot(data=dfm) +
  geom_line(aes(x=dfm$Jahr, y=dfm$value, colour=dfm$variable),  lineend = "round", lwd=1.5)+
  scale_x_continuous(limits = c(2013,2019), breaks = c(2013, 2014, 2015,2016,  2017,2018,  2019))+
  scale_y_continuous(limits = c(0, 400))+
  labs(title = "Verkäufe in Tausend")+
  theme_minimal()+
  scale_colour_manual(name="Mode",
                      labels=c("Total", "Fahrrad","E-Bike"),
                      values = c( "#8c8c8c", "#256bc2","#7ea9de"),
                      guide="none")+
  geom_text(x = 2013.5, y = 350, label="Total" , hjust = "inward", size=3) + 
  geom_text(x = 2013.5, y = 290, label="Fahrrad" , hjust = "inward", size=3) + 
  geom_text(x = 2013.5, y = 80, label = "E-Bike", hjust = "inward", size=3)+
  theme(legend.title = element_blank(),
        axis.title.y=element_blank(),
        axis.title.x=element_blank(),
        panel.grid.minor.x=element_blank(),
        panel.grid.major.x=element_blank(),
        axis.text=element_text(size=8.5),
        plot.title = element_text(hjust = -0.06, size=9),
        plot.caption = element_text(hjust = -0.08, size=6,color="#BFBFBF"))

Upvotes: 3

Views: 4789

Answers (1)

teunbrand
teunbrand

Reputation: 38053

The way that secondary axes work in ggplot are as follows. At the position scale, add a sec.axis argument for a secondary axis that is a linear transformation of the first axis, specified in trans. Since both the primary and secondary axes can start at 0, this means a simple scaling factor will do. You need to manually transform the input data and specify the reverse transformation as the trans argument. Simplified example below (assuming df is your provided data):

library(ggplot2)
library(scales)

dfm <- reshape2::melt(df, id="Jahr")

# Scale factor for utilising whole y-axis range
scalef <- max(df$gesamt) / max(df$E.Bike / df$gesamt)

# Scale factor for using 0-100%
# scalef <- max(df$gesamt)

ggplot(dfm, aes(Jahr, value)) +
  geom_line(aes(colour = variable)) +
  geom_line(aes(y = E.Bike / gesamt * scalef),
            data = df, linetype = 2) +
  scale_y_continuous(
    labels = number_format(scale = 1e-3),
    sec.axis = sec_axis(trans = ~ .x / scalef,
                        labels = percent_format(),
                        name = "Percentage E-bike")
  )

Created on 2021-01-04 by the reprex package (v0.3.0)

Upvotes: 4

Related Questions