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.

kjetil b halvorsen
  • 1,206
  • 2
  • 18
  • 28
D.dot
  • 3
  • 2
  • Long story short: ggplot won't let you do that. See https://stackoverflow.com/questions/3099219/ggplot-with-2-y-axes-on-each-side-and-different-scales – Claudio Jan 17 '23 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) – Allan Cameron Jan 17 '23 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. – Claudio Jan 17 '23 at 13:35

2 Answers2

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")
DaveArmstrong
  • 18,377
  • 2
  • 13
  • 25
  • Thank you for this. I was struggling on how to trasnform the data. – D.dot Jan 17 '23 at 18:07
  • 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 – D.dot Jan 17 '23 at 18:36
  • 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)+ – D.dot Jan 17 '23 at 18:36
  • 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") – D.dot Jan 17 '23 at 18:36
  • 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. – DaveArmstrong Jan 17 '23 at 21:16
  • Thank you for your help. Still cant get the legend to appear. Not sure why. My code is below. – D.dot Jan 17 '23 at 21:32
  • Without your data, I can’t help make your plot. – DaveArmstrong Jan 17 '23 at 23:24
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

D.dot
  • 3
  • 2
  • 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](/help/how-to-answer). – Community Jan 17 '23 at 21:03
  • 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. – DaveArmstrong Jan 18 '23 at 11:04