Multiple y axis for bar plot and line graph using ggplot
As described with nice examples here or here starting with version 2.2.0 of ggplot2
, is possible to add a secondary axis.
One could try this:
Prepare the provided data for ggplot
:
# Read data from OP's DropBox links
am_means <- read.csv("https://www.dropbox.com/s/z4dl0jfslhqccb8/am_means.csv?dl=1")
rainfall <- read.csv("https://www.dropbox.com/s/vkv9vm5o93ttk1i/Rainfall.csv?dl=1")
am_means$dates <- as.Date(am_means$dates, format = "%d/%m/%Y")
rainfall$DATE <- as.Date(rainfall$DATE,format = "%d/%m/%Y")
# join the two tables
my_data_all <- merge(x = am_means,
y = rainfall,
by.x = "dates",
by.y = "DATE",
all = TRUE)
# use data between desired date interval (rainfall had some extra dates)
require(data.table)
setDT(my_data_all)
my_data <- my_data_all[dates %between% c("2017-01-31", "2017-04-06")]
Plot with secondary OY axis:
Is important to transform the data appearing on 2nd OY (right-hand side). Since the max value is approx 2 times smaller that the one of the data from first OY axis (left-hand side), one can multiply by 2.
my_factor <- 2
my_plot <- ggplot(my_data,
aes(x = dates,
group = Treatment)) +
geom_errorbar(aes(ymin = cond - err,
ymax = cond + err,
colour = Treatment),
width = 0.5,
size = 0.5) +
geom_line(aes(y = cond, colour = Treatment)) +
geom_point(aes(y = cond, colour = Treatment)) +
# here the factor is applied
geom_bar(aes(y = daily.rainfall * my_factor),
fill = "light blue",
stat = "identity")
my_plot
Adding the 2nd OY axis with scale_y_continuous
. Note the transformation back. If above we multiplied by 2, now we divide data by 2:
my_plot <- my_plot + scale_y_continuous(sec.axis = sec_axis(trans = ~ . / my_factor,
name = "Rainfall (mm)"))
Continues with OP's code
my_plot <- my_plot + scale_x_date(date_breaks = "2 weeks",
date_minor_breaks = "1 week",
date_labels = "%b %d") +
scale_color_manual(breaks = c("Control", "T1", "T2", "T3", "T4"),
values = c("blue", "yellow", "hotpink1", "orange", "red")) +
labs(title = "Stomatal Conductance - Tamata Maples",
y = expression(Conductance (m~mol~m^{-2})),
x = "Date") +
theme_bw()
my_plot
Some other related answered questions: adding a cumulative curve or combining Bar and Line chart.
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
Combining Bar and Line chart (double axis) in ggplot2
First, scale Rate
by Rate*max(df$Response)
and modify the 0.9
scale of Response text.
Second, include a second axis via scale_y_continuous(sec.axis=...)
:
ggplot(df) +
geom_bar(aes(x=Year, y=Response),stat="identity", fill="tan1", colour="sienna3")+
geom_line(aes(x=Year, y=Rate*max(df$Response)),stat="identity")+
geom_text(aes(label=Rate, x=Year, y=Rate*max(df$Response)), colour="black")+
geom_text(aes(label=Response, x=Year, y=0.95*Response), colour="black")+
scale_y_continuous(sec.axis = sec_axis(~./max(df$Response)))
Which yields:
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:
R - creating a bar and line on same chart, how to add a second y axis
Starting with version 2.2.0 of ggplot2
, it is possible to add a secondary axis - see this detailed demo. Also, some already answered questions with this approach: here, here, here or here. An interesting discussion about adding a second OY axis here.
The main idea is that one needs to apply a transformation for the second OY axis. In the example below, the transformation factor is the ratio between the max values of each OY axis.
# Prepare data
library(ggplot2)
set.seed(2018)
df <- data.frame(x = c(1:5), y = abs(rnorm(5)*100))
df$y2 <- abs(rnorm(5))
# The transformation factor
transf_fact <- max(df$y)/max(df$y2)
# Plot
ggplot(data = df,
mapping = aes(x = as.factor(x),
y = y)) +
geom_col(fill = 'blue') +
# Apply the factor on values appearing on second OY axis
geom_line(aes(y = transf_fact * y2), group = 1) +
# Add second OY axis; note the transformation back (division)
scale_y_continuous(sec.axis = sec_axis(trans = ~ . / transf_fact,
name = "Second axis")) +
geom_label(aes(y = transf_fact * y2,
label = round(y2, 2))) +
theme_bw() +
theme(axis.text.x = element_text(angle = 20, hjust = 1))
But if you have a particular wish for the one-to-one transformation, like, say value 100 from Y1 should correspond to value 1 from Y2 (200 to 2 and so on), then change the transformation (multiplication) factor to 100 (100/1): transf_fact <- 100/1
and you get this:
The advantage of transf_fact <- max(df$y)/max(df$y2)
is using the plotting area in a optimum way when using two different scales - try something like transf_fact <- 1000/1
and I think you'll get the idea.
How to plot a combined bar and line plot in ggplot2
Is this what you had in mind?
ratio <- max(feat$Count)/max(feat$CI2)
ggplot(feat) +
geom_bar(aes(x=Feat, y=Count),stat="identity", fill = "steelblue") +
geom_line(aes(x=Feat, y=OR*ratio),stat="identity", group = 1) +
geom_point(aes(x=Feat, y=OR*ratio)) +
geom_errorbar(aes(x=Feat, ymin=CI1*ratio, ymax=CI2*ratio), width=.1, colour="orange",
position = position_dodge(0.05)) +
scale_y_continuous("Count", sec.axis = sec_axis(~ . / ratio, name = "Odds Ratio"))
Edit: Just for fun with the legend too.
ggplot(feat) +
geom_bar(aes(x=Feat, y=Count, fill = "Count"),stat="identity") + scale_fill_manual(values="steelblue") +
geom_line(aes(x=Feat, y=OR*ratio, color = "Odds Ratio"),stat="identity", group = 1) + scale_color_manual(values="orange") +
geom_point(aes(x=Feat, y=OR*ratio)) +
geom_errorbar(aes(x=Feat, ymin=CI1*ratio, ymax=CI2*ratio), width=.1, colour="orange",
position = position_dodge(0.05)) +
scale_y_continuous("Count", sec.axis = sec_axis(~ . / ratio, name = "Odds Ratio")) +
theme(legend.key=element_blank(), legend.title=element_blank(), legend.box="horizontal",legend.position = "bottom")
Since you asked about adding p values for comparisons in the comments, here is a way you can do that. Unfortunately, because you don't really want to add **all* the comparisons, there's a little bit of hard coding to do.
library(ggplot2)
library(ggsignif)
ggplot(feat,aes(x=Feat, y=Count)) +
geom_bar(aes(fill = "Count"),stat="identity") + scale_fill_manual(values="steelblue") +
geom_line(aes(x=Feat, y=OR*ratio, color = "Odds Ratio"),stat="identity", group = 1) + scale_color_manual(values="orange") +
geom_point(aes(x=Feat, y=OR*ratio)) +
geom_errorbar(aes(x=Feat, ymin=CI1*ratio, ymax=CI2*ratio), width=.1, colour="orange",
position = position_dodge(0.05)) +
scale_y_continuous("Count", sec.axis = sec_axis(~ . / ratio, name = "Odds Ratio")) +
theme(legend.key=element_blank(), legend.title=element_blank(), legend.box="horizontal",legend.position = "bottom") +
geom_signif(comparisons = list(c("A","H"),c("B","F"),c("D","E")),
y_position = c(150,60,40),
annotation = c("***","***","n.s."))
ggplot bar plot by multiple groups + line graph
You could use facet_wrap to plot the weeks beside each other:
ggplot(data, aes(fill=tmp)) +
geom_bar(aes(x=day_s, y=mpd, group=tmp) ,stat="identity") +
facet_wrap(.~tmp) +
theme_bw()
Update
To get summed up rpd as line plot you can do the following:
library(dplyr)
rpd_sum <- data %>%
group_by(tmp, day_s) %>%
summarise(sum_rpd = sum(rpd)) %>%
mutate(newClass = paste(tmp, day_s))
data$newClass <- paste(data$tmp, data$day_s)
dataNew <- merge(data, rpd_sum )
ggplot(dataNew, aes(fill=tmp)) +
geom_bar(aes(x=day_s, y=mpd) ,stat="identity") +
geom_line(aes(x=day_s, y=sum_rpd*10, group=tmp),stat="identity") +
scale_y_continuous(sec.axis = sec_axis( trans=~./10, name="rpd Axis")) +
facet_wrap(.~tmp) +
theme_bw()
ggplot2 (Barplot + LinePlot) - Dual Y axis
ggplot2
supports dual axis (for good or for worse), where the second axis is a linear transformation of the main axis.
We can work it out for this case:
library(ggplot2)
ggplot(df, aes(x = TimesReshop)) +
geom_col(aes( y = OccuranceCT, fill="redfill")) +
geom_text(aes(y = OccuranceCT, label = OccuranceCT), fontface = "bold", vjust = 1.4, color = "black", size = 4) +
geom_line(aes(y = AverageRepair_HrsPerCar * 1500, group = 1, color = 'blackline')) +
geom_text(aes(y = AverageRepair_HrsPerCar * 1500, label = round(AverageRepair_HrsPerCar, 2)), vjust = 1.4, color = "black", size = 3) +
scale_y_continuous(sec.axis = sec_axis(trans = ~ . / 1500)) +
scale_fill_manual('', labels = 'Occurance', values = "#C00000") +
scale_color_manual('', labels = 'Time Reshop', values = 'black') +
theme_minimal()
Plot line and bar graph (with secondary axis for line graph) using ggplot
ggplot is a "high-level" plotting library, meaning that it is built to express clear relationships in data, rather than a simple system for drawing shapes. One of its fundamental assumptions is that secondary or dual data axes are usually a bad idea; such figures plot more than one relationship into the same space, with no guarantee that the two axes actually share a meaningful relationship (see for example spurious correlations).
All that said, ggplot does indeed have the ability to define secondary axes, although using it for the purpose you describe is intentionally difficult. One way to accomplish your goal would be to split your data set into two separate ones, then plot these in the same ggplot object. It's certainly possible, but take note of how much extra code is required to produce the effect you're after.
library(tidyverse)
library(scales)
df.base <- df[c('MONTHS', 'BASE')] %>%
mutate(MONTHS = factor(MONTHS, MONTHS, ordered = T))
df.percent <- df[c('MONTHS', 'INTERNETPERCENTAGE', 'SMARTPHONEPERCENTAGE')] %>%
gather(variable, value, -MONTHS)
g <- ggplot(data = df.base, aes(x = MONTHS, y = BASE)) +
geom_col(aes(fill = 'BASE')) +
geom_line(data = df.percent, aes(x = MONTHS, y = value / 40 * 12500000 + 33500000, color = variable, group = variable)) +
geom_point(data = df.percent, aes(x = MONTHS, y = value / 40 * 12500000 + 33500000, color = variable)) +
geom_label(data = df.percent, aes(x = MONTHS, y = value / 40 * 12500000 + 33500000, fill = variable, label = sprintf('%i%%', value)), color = 'white', vjust = 1.6, size = 4) +
scale_y_continuous(sec.axis = sec_axis(~(. - 33500000) / 12500000 * 40, name = 'PERCENT'), labels = comma) +
scale_fill_manual(values = c('lightblue', 'red', 'darkgreen')) +
scale_color_manual(values = c('red', 'darkgreen')) +
coord_cartesian(ylim = c(33500000, 45500000)) +
labs(fill = NULL, color = NULL) +
theme_minimal()
print(g)
Related Topics
How to Place Legends at Different Sides of Plot (Bottom and Right Side) with Ggplot2
Why Are the Colors Wrong on This Ggplot
Repeat Vector to Fill Down Column in Data Frame
Back-To-Back Barplot with Independent Axes R
How to Calculate a Table of Pairwise Counts from Long-Form Data Frame
Merge Plm Fitted Values to Dataset
Filling in a New Column Based on a Condition in a Data Frame
How to Preserve Continuous (1,2,3,...N) Ranking Notation When Ranking in R
Combine/Merge Columns While Avoiding Na
Pass R Variable to Rodbc's SQLquery with Multiple Entries
How to Expand a Large Dataframe in R
Tidyr::Pivot_Wider() Reorder Column Names Grouping by 'Name_From'
Ggplot2: Problem with X Axis When Adding Regression Line Equation on Each Facet