Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R - creating a bar and line on same chart, how to add a second y axis

Tags:

r

ggplot2

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)) 

enter image description here

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.

like image 922
user33484 Avatar asked Feb 01 '26 13:02

user33484


1 Answers

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))

enter image description here

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:

enter image description here

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.

like image 176
Valentin Avatar answered Feb 03 '26 05:02

Valentin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!