Geom_Bar + Geom_Line: with Different Y-Axis Scale

geom_bar + geom_line: with different y-axis scale?

I'm borrowing most of the code from here:

library(ggplot2)
library(gtable)
library(grid)

temp = data.frame(Product=as.factor(c("A","B","C")),
N = c(17100,17533,6756),
n = c(5,13,11),
rate = c(0.0003,0.0007,0.0016),
labels = c(".03%",".07%",".16%"))

p1 = ggplot(data = temp, aes(x=Product,y=N))+
geom_bar(stat="identity",fill="#F8766D") +
geom_text(aes(label=n,col="red",vjust=-0.5))+
theme(legend.position="none",axis.title.y=element_blank(),
axis.text.x = element_text(angle = 90, hjust = 1))
p2 = ggplot(data = temp,aes(x=Product,y=rate))+
geom_line(aes(group=1))+geom_text(aes(label=labels,vjust=0))+
theme(legend.position="none",axis.title.y=element_blank(),
axis.text.x = element_text(angle = 90, hjust = 0),
panel.background = element_rect(fill = NA),
panel.grid = element_blank())+
xlab("Product")

g1 <- ggplot_gtable(ggplot_build(p1))
g2 <- ggplot_gtable(ggplot_build(p2))

# overlap the panel of 2nd plot on that of 1st plot
pp <- c(subset(g1$layout, name == "panel", se = t:r))
g <- gtable_add_grob(g1, g2$grobs[[which(g2$layout$name == "panel")]], pp$t,
pp$l, pp$b, pp$l)

# axis tweaks
ia <- which(g2$layout$name == "axis-l")
ga <- g2$grobs[[ia]]
ax <- ga$children[[2]]
ax$widths <- rev(ax$widths)
ax$grobs <- rev(ax$grobs)
ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)

# draw it
grid.draw(g)

I removed the grid from the second plot (it appears on top and looks messy).

Sample Image

ggplot with 2 y axes on each side and different scales

Sometimes a client wants two y scales. Giving them the "flawed" speech is often pointless. But I do like the ggplot2 insistence on doing things the right way. I am sure that ggplot is in fact educating the average user about proper visualization techniques.

Maybe you can use faceting and scale free to compare the two data series? - e.g. look here: https://github.com/hadley/ggplot2/wiki/Align-two-plots-on-a-page

Plot geom_bar() and geom_line() with double Y axis - Error with geom_line() overwriting geom_bar()

Thanks to Axeman's comment above, I found my error, which was with scaling.

Additionally, I was improperly calling geom_line() and stat_summary().

The corrected code:

ggplot(O2Data %>% filter(year(MeltDate) != 2019), aes(x=factor(months(MeltDate), levels=c("January","February","March","April","May","June","July","August",
"September","October","November","December")))) +
geom_bar(stat="count", fill="antiquewhite3") +
geom_line(stat='summary', aes(y=ScrapWeight/100, group=factor(year(MeltDate)), color=factor(year(MeltDate)))) +
stat_summary(aes(y=ScrapWeight/100), fun.y=sum) +
scale_y_continuous(sec.axis = sec_axis(~.*100, name = "Scrap Weight"), limits = c(0, 48)) +
theme(axis.text.x=element_text(angle=90, hjust=1, vjust=0.5), legend.position="none") +
labs(title = "Count of O2 Scrap Codes by Month (2016-2018)", x = "Month", y = "Count")

Corrected Graph

geom_line with different y-axis scale

dat <- temp %>% gather(y, val, items:visit_time)

ggplot(dat, aes(day, val, colour=y)) +
geom_line(data=dat %>% filter(y=="items")) +
geom_line(data=dat %>% filter(y=="visit_time"), aes(y=val*2)) +
scale_y_continuous(sec.axis= sec_axis(~./2, name="visit_time"))

Sample Image

Add a scale_colour_manual to adjust the colour if you find the default too displeasing.

scale_colour_manual(values = c("darkblue", "darkorange3"))

ggplot with a secondary y axis

That's how you can plot a bar chart and a line chart together, while making them comparable.

Basically, the idea is to change mean and sd of the vector that draws the line based on mean and sd of the vector that draws the bars. The opposite transformation has to be applied on the second y axis so to make it comparable to line you draw.

library(ggplot2)
library(tidyr)

# user defined function:
# apply mean and sd of the second vector to the first one
renormalize <- function(from, to){

from <- scale(from)
to <- scale(to)
from * attr(to, 'scaled:scale') + attr(to, 'scaled:center')

}

# reshape
df <- df %>%
pivot_wider(names_from = Key, values_from = Value)

ggplot(df, aes(x = Date)) +
geom_col(aes(y = `Reserves (NAD)`), fill = "steelblue") +
geom_line(aes(y = renormalize(`Reserves (USD)`, `Reserves (NAD)`)), colour = "coral", size = 2) +
scale_y_continuous(sec.axis = sec_axis(~renormalize(., df$`Reserves (USD)`), name = "Reserves (USD)")) +
theme_light()

Sample Image

Line plot with bars in secondary axis with different scales in ggplot2

Try this approach with scaling factor. It is better if you work with a scaling factor between your variables and then you use it for the second y-axis. I have made slight changes to your code:

library(tidyverse)
#Data
Month <- c("J","F","M","A")
Line <- c(2.5,2,0.5,3.4)
Bar <- c(30,33,21,40)
df <- data.frame(Month,Line,Bar)
#Scale factor
sfactor <- max(df$Line)/max(df$Bar)
#Plot
ggplot(df, aes(x=Month)) +
geom_line(aes(y = Line,group = 1)) +
geom_col(aes(y=Bar*sfactor))+
scale_y_continuous("Line",
sec.axis = sec_axis(trans= ~. /sfactor, name = "Bar"))

Output:

Sample Image



Related Topics



Leave a reply



Submit