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).
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")
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"))
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()
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:
Related Topics
Standard Eval with Ggplot2 Without 'Aes_String()'
Convert an Integer Column to Time Hh:Mm
Twitter Throws Forbidden Error After Entering Twitter API Pin
R Bnlearn Eval Inside Function
Non-Equi-Joins in R with Data.Table - Backticked Column Name Trouble
How to Select Dropdown Box Using Rselenium
Error: Could Not Find Build Tools Necessary to Build Dplyr
How to Avoid Density Curve Getting Cut Off in Plot
Transform One Column from Categoric to Binary, Keep the Rest
Test If Element Is in a List and Return 0 or 1
Accessing Functions with a Dot in Their Name (Eg. "As.Vector") Using Rpy2
R - Random Forest and More Than 53 Categories
How to Manage Parallel Processing with Animated Ggplot2-Plot
Replace Na with Mode Based on Id Attribute
Equivalent of Which in Scraping