I'm trying to create a ggplot2 graph showing a bar graph and a line graph overlaying each other. In excel this would be done by adding a second axis.
The x axis represents product type, the y values of the bar graph should represent revenue, and the line graph I want to represent profit margin as a percentage. The value of the line graph and the bar chart should be independent of each other, i.e. there is no such relationship.
require(ggplot2)
df <- data.frame(x = c(1:5), y = abs(rnorm(5)*100))
df$y2 <- abs(rnorm(5))
ggplot(df, mapping= aes(x=as.factor(`x`), y = `y`)) +
geom_col(aes(x=as.factor(`x`), y = `y`),fill = 'blue')+
geom_line(mapping= aes(x=as.factor(`x`), y = `y`),group=1) +
geom_label(aes(label= round(y2,2))) +
scale_y_continuous() +
theme_bw() +
theme(axis.text.x = element_text(angle = 20,hjust=1))

The image above produces almost what I want. However, the scaling is incorrect - I would need the 1.38 and 0.23 value to be ordered by magnitude, i.e. the point 0.23 should show below 1.38. I am also not sure how to add another axsis on the right hand side.
Starting with version 2.2.0 of ggplot2, it is possible to add a secondary axis - see this detailed demo. Also, some already answered questions with this approach: here, here, here or here. An interesting discussion about adding a second OY axis here.
The main idea is that one needs to apply a transformation for the second OY axis. In the example below, the transformation factor is the ratio between the max values of each OY axis.
# Prepare data
library(ggplot2)
set.seed(2018)
df <- data.frame(x = c(1:5), y = abs(rnorm(5)*100))
df$y2 <- abs(rnorm(5))
# The transformation factor
transf_fact <- max(df$y)/max(df$y2)
# Plot
ggplot(data = df,
mapping = aes(x = as.factor(x),
y = y)) +
geom_col(fill = 'blue') +
# Apply the factor on values appearing on second OY axis
geom_line(aes(y = transf_fact * y2), group = 1) +
# Add second OY axis; note the transformation back (division)
scale_y_continuous(sec.axis = sec_axis(trans = ~ . / transf_fact,
name = "Second axis")) +
geom_label(aes(y = transf_fact * y2,
label = round(y2, 2))) +
theme_bw() +
theme(axis.text.x = element_text(angle = 20, hjust = 1))

But if you have a particular wish for the one-to-one transformation, like, say value 100 from Y1 should correspond to value 1 from Y2 (200 to 2 and so on), then change the transformation (multiplication) factor to 100 (100/1): transf_fact <- 100/1 and you get this:

The advantage of transf_fact <- max(df$y)/max(df$y2) is using the plotting area in a optimum way when using two different scales - try something like transf_fact <- 1000/1 and I think you'll get the idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With