Creating Dual Axis plot (bar and line) - r

I want to create a dual axis plot in ggplot R with a dual bar and line plot, like this one created in excel.
The y axis scales are different.
my data is as follows;
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.

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

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

Related

ggplot2 increase font size of output labels

I am working with ggplot2 to create plots and I want to increase the size of the labels from the output, so not the labels added manually.
I tried to use cex put this works only partially as it only increases the count size in the plot but not the x or y labels
ggplot(dat, aes(x = Gender, fill = gen))+
geom_bar(position = "dodge")+
scale_fill_manual(values = c("#40E0D0","#DE3163"))+
labs(y="All", fill ="Gender:")+
scale_y_continuous(breaks = seq(0,550,50))+
ggtitle("Gender")+
theme(axis.title.x = element_text(size =20, face = "bold"))+
theme(axis.title.y = element_text(size = 20, face = "bold", angle = 90))+
theme(plot.title = element_text(size = 30, face="bold"), legend.position = "bottom")+
geom_text(aes(label=stat(count), cex = 6), stat = "count",
position=position_dodge(width = 1),vjust= -0.2, cex = 6)+
theme(legend.title = element_text(size = 20))+
theme(legend.text = element_text(size = 20))
``

How to order of tiles in geom_tile ggplot by using only part of the numeric variables

I'm trying to plot the a data in pivot_long form to present as a heatmap using geom_tile.
However I'm having trouble for ordering the tiles in the figure.
sample data https://drive.google.com/file/d/1WIjbN9-xP-1Wgc2Nx3GlterV8XhtnGyu/view?usp=sharing
Here is the figure I generated:
The problem is I want the y axis labels, aka "Drug.dose" ranked by numeric values high to low in the "none" part of the Combination added (factors set to have levels none, I30, I300.... I300_V100)
My code for plotting as below: By using reorder() on my y axis(How to preserve the order of tiles in geom_tile ggplot), it ranked from high to low by everything in the Combined added, thus you see my highest one in the none is TN 0.1 but it goes to the bottom of the figure because of all the zeros in I30, I300 etc. And there are other inconsistencies in the list.
How I can reorder just by the none section of the Combination added?
library(ggplot2)
m <- ggplot(data)+
geom_tile(aes(x=Combination, y=reorder(Drug.dose,Avg.percent), fill=Avg.percent))+
geom_text(aes(x=Combination, y=reorder(Drug.dose,Avg.percent), label=Avg.percent), size=3)+
scale_fill_gradientn(colors=pal)+
theme(legend.text = element_text(size=10, face="bold", color = "black"))+
theme(axis.text.x = element_text(size = 15, face="bold", color = "black")) +
theme(axis.text.y = element_text(size = 9, face="bold", color = "black")) +
theme(axis.title.x = element_text(size = 15, face="bold", color = "black", vjust = 3))+
theme(axis.title.y = element_text(size = 15, face="bold", color = "black", hjust = 0.5))+
theme(plot.title = element_text(size = 16))+
theme(strip.text.y = element_text(size = 10, face = "bold", color = "black"))+
scale_x_discrete(position ="top") +
xlab("Combination added")+
ylab("Treatments in the screen")+
ggtitle("Cluster 1 Enriched in TN response")
print(m)
Something like this? Just create a static variable that manages the colour gradient for ya.
library(tidyverse)
levels <- c("none","I30","I300","I30_V10","I300_V100","V10","V100" )
# Data directory %>%
read_csv %>%
pivot_wider(names_from = Combination,
values_from = Avg.percent) %>%
mutate(color = none) %>%
pivot_longer(cols = c("none", starts_with(c(c("I","V"), ignore.case = F))),
names_to = "Combination",
values_to = "Avg.percent") %>%
mutate(Combination = factor(Combination,
levels = levels))-> data
m <- ggplot(data)+
geom_tile(aes(x=Combination, y=reorder(Drug.dose, color), fill=Avg.percent)) +
geom_text(aes(x=Combination, y=reorder(Drug.dose, color), label=Avg.percent), size=3)+
# scale_fill_gradientn(colors=pal)+
ggsci::scale_fill_material("red") +
theme(legend.text = element_text(size=10, face="bold", color = "black"))+
theme(axis.text.x = element_text(size = 15, face="bold", color = "black")) +
theme(axis.text.y = element_text(size = 9, face="bold", color = "black")) +
theme(axis.title.x = element_text(size = 15, face="bold", color = "black", vjust = 3))+
theme(axis.title.y = element_text(size = 15, face="bold", color = "black", hjust = 0.5))+
theme(plot.title = element_text(size = 16))+
theme(strip.text.y = element_text(size = 10, face = "bold", color = "black"))+
scale_x_discrete(position ="top") +
xlab("Combination added")+
ylab("Treatments in the screen")+
ggtitle("Cluster 1 Enriched in TN response")
print(m)
I think that the best way to do it is order your data before placing it in ggplot. There's probably a solution using tidyr or something else but i don't know much about it.
Get the paired values when Combination=="none", and order it by Avg.percent:
index = data[data$Combination=="none", c("Drug.dose", "Avg.percent")]
index = index[order(index$Avg.percent),]
Create a variable order that gives the value on index for each level in Drug.dose:
for(i in unique(data$Drug.dose)){
data$order[data$Drug.dose==i] = index[index$Drug.dose==i,2]}
Then use order on the place of Avg.percent in reorder(). Output (on you order of levels "none" should be the first row):

Using gganimate with geom_point and geom_line

working with nfl data here.. trying gganimate for the first time... trying to use geom_point and geom_line but geom_line will not appear..
data frame here..
week = c(1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17)
plays= c(9,10,5,3,4,4,3,5,6,5,11,12,6,11,7,3)
mean_epa= c(.67, .27, -.5, -1.09, -.3, .68, -.72, -.32, 1.03, 1.05, .56, .17, -.61, -.05, -.14, 1.5)
CLEdrive1b <- data.frame(week,plays,mean_epa)
within week variable, 7 is missing (because browns did not have game week 7)... not sure if that is causing issues?
my first attempt below
p <- ggplot(CLEdrive1b, aes(x=as.factor(week),y=mean_epa)) +
theme_minimal() +
geom_point(aes(group = seq_along(week)), color = "orange", size = 4) +
geom_line(alpha = 0.5)+
transition_reveal(week)+
geom_text(aes(label = mean_epa))+
xlab("Week") +
ylab("EPA/Play") +
labs(title="Browns Opening Drives",
subtitle = "EPA/Drive by Week",
caption="Data from nflscrapR")+
theme(axis.title = element_text(size = 10),
axis.text = element_text(size = 9),
plot.title = element_text(size = 15),
plot.subtitle = element_text(size = 10),
plot.caption = element_text(size = 8))
animate(p)
alternative method I tried..
pi <- ggplot(CLEdrive1b, aes(week,y=mean_epa)) +
theme_minimal() +
geom_point(aes(group = seq_along(week)), color = "orange", size = 4) +
geom_line(alpha = 0.5)+
transition_reveal(week)+
geom_text(aes(label = mean_epa))+
xlab("Week") +
ylab("EPA/Play") +
labs(title="Browns Opening Drives",
subtitle = "EPA/Drive by Week",
caption="Data from nflscrapR")+
theme(axis.title = element_text(size = 10),
axis.text = element_text(size = 9),
plot.title = element_text(size = 15),
plot.subtitle = element_text(size = 10),
plot.caption = element_text(size = 8))
animate(pi)
removed as.factor from x variable (week).. and geom_line appears! but x-axis loses labels I am seeking and geom_text stops performing how it was above..
thank you for spending time to help...
The problem is that when converting it to factors, ggplot doesn't "know" any more how to group the week variable, and does not connect the observations any more. Adding aes(group = 1) to your geom_line is all you need.
library(gganimate)
#> Loading required package: ggplot2
library(ggplot2)
week = c(1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17)
plays= c(9,10,5,3,4,4,3,5,6,5,11,12,6,11,7,3)
mean_epa= c(.67, .27, -.5, -1.09, -.3, .68, -.72, -.32, 1.03, 1.05, .56, .17, -.61, -.05, -.14, 1.5)
CLEdrive1b <- data.frame(week,plays,mean_epa)
p <- ggplot(CLEdrive1b, aes(x=as.factor(week),y=mean_epa)) +
geom_point(aes(group = seq_along(week)), color = "orange", size = 4) +
geom_line(alpha = 0.5, aes(group = 1))+
transition_reveal(week)+
geom_text(aes(label = mean_epa))
animate(p)
Created on 2020-02-03 by the reprex package (v0.3.0)

overlay geom_point with position=dodge and facet grid in ggplot2

Considering the following data, I am able to generate a plot which describes how the risk of a react over a time interval changes.
risk_1 <- c(0.121,0.226,0.333,0.167,0.200,0.273,0.138,0.323,0.394,0.250,0.200,0.545,0.190,0.355,0.515,0.333,0.300,0.818)
risk_minus_SE <- c(0.060,0.114,0.198,0.047,0.057,0.097,0.072,0.186,0.247,0.089,0.057,0.280,0.109,0.211,0.352,0.138,0.108,0.523)
risk_plus_SE <- c(0.229,0.398,0.504,0.448,0.510,0.566,0.249,0.499,0.563,0.532,0.510,0.787,0.309,0.531,0.675,0.609,0.603,0.949)
Status <- rep(c(rep('With placebo',3),rep('With drug',3)),3)
durtn <- rep(c('(3-15]','(15-30]','(30-46]'),6)
react <- c(rep("x\u226516",6),rep("x\u226509",6),rep("x\u226504",6))
df1 <- data.frame(risk_1, risk_minus_SE, risk_plus_SE, Status, durtn, react)
dodge <- position_dodge(width=0.45)
ggplot(df1,aes(colour=react, y=risk_1, x=durtn)) +
geom_point(aes(shape=durtn), shape=16, size = 5, position=dodge) +
geom_errorbar(aes(ymin=risk_minus_SE, ymax=risk_plus_SE), position = dodge, width=0.5, size=1, lty=1) +
scale_colour_manual(values = c('black','red','blue')) +
facet_grid(~Status) +
scale_shape_manual(values = c(8,19))+
theme_bw() +
scale_x_discrete(limits=c('(3-15]','(15-30]','(30-46]')) +
coord_cartesian(ylim = c(0, 0.8)) +
theme(legend.position = c(.1, .85), legend.background = element_rect(colour = "black"),
plot.title = element_text(lineheight=1.5, face="bold", size=rel(1.5), hjust = 0.5),
panel.grid.major.x = element_blank(),
axis.text.x = element_text(vjust=0.5, size=16),
axis.text.y = element_text(vjust=0.5, size=16),
axis.title.y = element_text(size=20),
axis.title.x = element_text(size=20),
legend.text = element_text(size = 16, face = "bold"),
strip.text = element_text(size=25)) +
xlab("\ntime (min)") + ylab("Risk")
What I want to do is overlay a series of points at given x and y coordinates.
That being at With drug & durtn==(3,15], manually insert points at.....
Risk==0.5 for react=x≥04 in black
Risk==0.2 for react=x≥09 in red
Risk==0.0 for react=x≥16 in blue
Such that the desired output should look like
How does one use the geom_point() in combination with a facet_grid and dodge
First, you have to create a separate data frame that contains the data for the additional points.
dat <- data.frame(risk_1 = c(0.5, 0.2, 0),
react = levels(df1$react),
durtn = '(3-15]',
Status = 'With drug')
This new data frame dat can be used with geom_point to add an additional layer to the existing plot.
+ geom_point(data = dat, position = dodge, shape = 4, size = 5, show.legend = FALSE)

how to get and modify size legend in ggplot2

I am having some trouble displaying the size legend in my plot and changing the name of my size legend.
My data is corp already has a size column which is either of the values 5, 10, 20
I am using ggplot2 I already have a legend for the color
I want to add one for the size and manually change the size labels..
How do I increase the the font of the legend ? It's super tiny (FIN, IND UTIL)
also the 15 for the size shouldnt be there i want to just omit it and display both legends side by side.
p <- ggplot(corp, aes(x=annRisk, y=annRet, color = corp$subsector1, face = "bold"))
p<- p + geom_point(aes(size = corp$Colsize), alpha = 0.55)
p<-p + scale_size(range = c(8, 20))
p<-p + scale_colour_manual("", values = c("UTIL" = "#fdcc8b", "IND" = "#fc8d59", "FIN" = "#d7301f",
"ABS" = "#74a9cf", "CMBS" = "#0570b0", "LA" = "#8c96c6", "SOV"= "#88419d", "SUPRA" = "#b3cde3"))
p<-p+labs(title = "SOME TITLE")
print(p)
p<-p+theme(plot.title = element_text(face = "bold", size = 20))
p<-p+theme(axis.title.x = element_text(size = 20), axis.text.x = element_text(size = 13))
p<-p+theme(axis.title.y = element_text(size = 20), axis.text.y = element_text(size = 13))
p<-p+geom_text(aes(label=ifelse(Colsize>=10,subsector2,"")), size=5,color = "black", face = "bold", hjust=-0.1, vjust = 0.1)
p<-p+scale_x_continuous(labels = percent, name = "Annualized Risk", limits = c(0.05, 0.09))
p<-p+scale_y_continuous(labels = percent, name = "Annualized Return", limits = c(0.04, 0.08))
p<-p+ theme(legend.position = "bottom")
print(p)
Although I can't use your data yet, you can try adding the following code:
p <- p + theme(legend.position = "bottom",
legend.title = element_blank(),
legend.text = element_text(size=14),
legend.box = "horizontal")
p <- p + scale_size_manual(values=c(5,10,20), labels = c("5","10","20"))

Resources