0

I want to create a dual axis plot in ggplot R with a dual bar and line plot, like this one created in excel.

enter image description here

The y axis scales are different.

my data is as follows;

enter image description here

I've created a bar plot and line plot. But unsure on how to put them together (I've tried man various ways and they don't seem to work).

Here is my code for the bar plot.

inf_conc <- ggplot(data=data, aes(x=Day, y=inf)) + geom_bar(stat="identity", width=0.4, color="red3", fill="red3") + ggtitle("Influent Microplastic Concentration \n and Flow Rate") + # \n splits long titles into multiple lines xlab("Day") + ylab("Microplastic Concentration (MPs/L)") + scale_y_continuous(limits =c(0, 50), breaks = seq(0, 50, 5)) inf_conc + theme(axis.text = element_text(size = 20, colour = "black"), plot.title = element_text(size =25, hjust = 0.5, face = "bold"), axis.title = element_text(size = 20, face = "bold", margin = 5)) inf_conc + theme(axis.text = element_text(size = 20, colour = "black"), plot.title = element_text (size =25, hjust = 0.5, face = "bold"), axis.title = element_text(size = 20, face = "bold", margin = 20)) 

and here is the code for the line plot:

inf_flow <- ggplot(data=data, aes(x=Day, y=flow, group = 1)) + geom_line(stat = "identity", colour ="blue4") + geom_point(colour ="blue4") + ylab("Inlet flow L/s")+ xlab("Day")+ scale_y_continuous(limits=c(0,800), breaks = seq(0, 800, 100)) inf_flow + theme(axis.text = element_text(size = 20, colour = "black"), plot.title = element_text (size =25, hjust = 0.5, face = "bold"), axis.title = element_text(size = 20, face = "bold", margin = 5)) inf_flow + theme(axis.text = element_text(size = 20, colour = "black"), plot.title = element_text (size =25, hjust = 0.5, face = "bold"), axis.title = element_text(size = 20, face = "bold", margin = 20)) 

Can anyone help with how I can get these onto one dual axis graph please.

3
  • Long story short: ggplot won't let you do that. See stackoverflow.com/questions/3099219/… Commented Jan 17, 2023 at 13:15
  • @Claudio that's simply not true. It used to be the case, but ggplot has had the facility to add a secondary axis for several years now. (see below) Commented Jan 17, 2023 at 13:30
  • I was sidetracked by the mention to different scales, what I meant is that you can't have dual axis unless the secondary axis is a transformation of the main one. Sorry for that. Commented Jan 17, 2023 at 13:35

2 Answers 2

1

GGplot doesn't make it especially easy, but you can do it:

library(ggplot2) my_dat <- data.frame( Day = paste("Day",rep(1:3, each=3), rep(c("(AM)", "(Midday)", "(PM)"), 3), sep= " "), day_num = 1:9, inf = seq(from = 13,to = 45, length=9), flow = runif(9, 580, 740) ) ggplot() + geom_bar(data=my_dat, aes(x=day_num, y=inf, fill = "Influent Concentration"), stat="identity", width=.6) + geom_line(data=my_dat, aes(x=day_num, y=flow*(50/800), colour="FLow Rate. L/s")) + scale_fill_manual(values="red") + scale_colour_manual(values="blue") + scale_x_continuous(breaks=1:9, labels=my_dat$Day) + scale_y_continuous(sec.axis = sec_axis(trans = ~.x*800/50, name = "Flow Rate L/S"), limits = c(0,50), name = "Influent. MPs/L") + labs(fill="", colour="", x="") + theme(legend.position="bottom", axis.text.x = element_text(angle=45, hjust=1)) 

Created on 2023-01-17 by the reprex package (v2.0.1)

The main things you have to do are to

  1. Transform the second-axis series to have the same range(ish) as the first-series axis. In your case, the excel graph had the second y-axis going from 0-800 and the first y-axis going from 0-50, so the transformation is simple, you multiply the second series values by 50/800.

  2. In the scale_y_continuou() function there is an argument sec.axis which allows you to plot a second axis on the right-hand side of the plot. Here, you need to specify the trans argument to transform the values you're plotting back into the original values. That's what trans = ~.x*800/50 does.


EDIT: Modifying OP's code

I modified your code as much as I can without actually having the data. The picture of the data that you provided does not give enough information about the data, if you use dput(data) and post the results, I could likely help more. For now, try this:

inf_plot <- ggplot(data=data, aes(x=Day))+ geom_bar(aes(y=inf, fill="Influent conc"), stat = "identity", width=0.4)+ geom_line(aes(y=flow*(50/800), colour="flow rate"), size = 1.4, group=1)+ ggtitle("Influent Microplastic Concentration \n and Influent Flow Rate")+ xlab("\n\nDay") + ylab("Microplastic Concentration (MPs/L)\n\n")+ scale_fill_manual(values="red4") + scale_colour_manual(values="blue4") + scale_y_continuous(sec.axis = sec_axis(~.*800/50, name = "Inlet flow rate (L/s)\n\n"), limits = c(0,50)) inf_plot + theme(axis.text = element_text( size = 20, colour = "black"), plot.title = element_text (size =25, hjust = 0.5, vjust = 5, face = "bold"), axis.title = element_text (size = 20, face = "bold"), plot.margin =unit(c(1.5, 1.5, 1.5, 1.5), "cm"), legend.position = "bottom") 
Sign up to request clarification or add additional context in comments.

7 Comments

Thank you for this. I was struggling on how to trasnform the data.
I've transformed the data how you've done it. and it's great. But I cant get the legend to appear. Do you know how to get the legend? Here is my code
inf_plot <- ggplot(data=data, aes(x=Day))+ geom_bar(aes(y=inf, fill="Influent conc"), stat = "identity", width=0.4, colour="red4", fill = "red4")+ ggtitle("Influent Microplastic Concentration \n and Flow Rate")+ xlab("\n\nDay") + ylab("Microplastic Concentration (MPs/L)\n\n")+ geom_line(aes(y=flow*(50/800), colour="flow rate"), size = 1.4, colour ="blue4", group = 1)+
scale_y_continuous(sec.axis = sec_axis(~.*800/50, name = "Inlet flow rate (L/s)\n\n"), limits = c(0,50)) inf_plot + theme(axis.text = element_text( size = 20, colour = "black"), plot.title = element_text (size =25, hjust = 0.5, vjust = 5, face = "bold"), axis.title = element_text (size = 20, face = "bold"), plot.margin =unit(c(1.5, 1.5, 1.5, 1.5), "cm"), legend.position = "bottom")
Notice in the answer that fill is specified in the aes() of geom_bar() and colour is specified in the aes() of geom_line(). That is what generates the legend.
|
0

The answer was a great help in how to transform my axis.

Initially produced the graph a slightly different way, but incorporated the same transformation of axis.

However, I can't seem to get the legend to appear at the bottom of the graph with the following code.

inf_plot <- ggplot(data=data, aes(x=Day))+ geom_bar(aes(y=inf, fill="Influent conc"), stat = "identity", width=0.4, colour="red4", fill = "red4")+ ggtitle("Influent Microplastic Concentration \n and Influent Flow Rate")+ xlab("\n\nDay") + ylab("Microplastic Concentration (MPs/L)\n\n")+ geom_line(aes(y=flow*(50/800), colour="flow rate"), size = 1.4, colour ="blue4", group = 1)+ scale_fill_manual(values="red4") + scale_colour_manual(values="blue4") + scale_y_continuous(sec.axis = sec_axis(~.*800/50, name = "Inlet flow rate (L/s)\n\n"), limits = c(0,50)) inf_plot + theme(axis.text = element_text( size = 20, colour = "black"), plot.title = element_text (size =25, hjust = 0.5, vjust = 5, face = "bold"), axis.title = element_text (size = 20, face = "bold"), plot.margin =unit(c(1.5, 1.5, 1.5, 1.5), "cm"), legend.position = "bottom") 

enter image description here

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
I updated my answer above to include an attempt to fix the code. I think the problem is that you did put the fill and colour in the appropriate aes() places, but you still have them outside the aes() as well and that overrides the aesthetic specification.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.