I am trying to create a barplot using ggplot2
where I am stacking by one variable and dodging by another.
Here is an example data set:
df=data.frame(
year=rep(c("2010","2011"),each=4),
treatment=rep(c("Impact","Control")),
type=rep(c("Phylum1","Phylum2"),each=2),
total=sample(1:100,8))
I would like to create a barplot where x=treatment
, y=total
, the stacked variable is type
and the dodged variable is year
. Of course I can do one or the other:
ggplot(df,aes(y=total,x=treatment,fill=type))+geom_bar(position="dodge",stat="identity")
ggplot(df,aes(y=total,x=treatment,fill=year))+geom_bar(position="dodge",stat="identity")
But not both! Thanks to anyone who can provide advice.
Here's an alternative take using faceting instead of dodging:
ggplot(df, aes(x = year, y = total, fill = type)) +
geom_bar(position = "stack", stat = "identity") +
facet_wrap( ~ treatment)
With Tyler's suggested change: + theme(panel.margin = grid::unit(-1.25, "lines"))
The closest you can get is by drawing a border around the dodged
bars to highlight the stacked type
values.
ggplot(df, aes(treatment, total, fill = year)) +
geom_bar(stat="identity", position="dodge", color="black")
You can use interaction(year, treatment)
as the x-axis variable as an alternative to dodge
.
library(dplyr)
library(ggplot2)
df=data.frame(
year=rep(c("2010","2011"),each=4),
treatment=rep(c("Impact","Control")),
type=rep(c("Phylum1","Phylum2"),each=2),
total=sample(1:100,8)) %>%
mutate(x_label = factor(str_replace(interaction(year, treatment), '\\.', ' / '),
ordered=TRUE))
ggplot(df, aes(x=x_label, y=total, fill=type)) +
geom_bar(stat='identity') +
labs(x='Year / Treatment')
Created on 2018-04-26 by the reprex package (v0.2.0).
It can be done however its tricky/fiddly, you basically have to layer the bar chart.
here is my code:
library(tidyverse)
df=data.frame(
year=rep(c(2010,2011),each=4),
treatment=rep(c("Impact","Control")),
type=rep(c("Phylum1","Phylum2"),each=2),
total=sample(1:100,8))
# separate the by the variable which we are dodging by so
# we have two data frames impact and control
impact <- df %>% filter(treatment == "Impact") %>%
mutate(pos = sum(total, na.rm=T))
control <- df %>% filter(treatment == "Control") %>%
mutate(pos = sum(total, na.rm=T))
# calculate the position for the annotation element
impact_an <- impact %>% group_by(year) %>%
summarise(
pos = sum(total) + 12
, treatment = first(treatment)
)
control_an <- control %>% group_by(year) %>%
summarise(
pos = sum(total) + 12
, treatment = first(treatment)
)
# define the width of the bars, we need this set so that
# we can use it to position the second layer geom_bar
barwidth = 0.30
ggplot() +
geom_bar(
data = impact
, aes(x = year, y = total, fill = type)
, position = "stack"
, stat = "identity"
, width = barwidth
) +
annotate(
"text"
, x = impact_an$year
,y = impact_an$pos
, angle = 90
, label = impact_an$treatment
) +
geom_bar(
data = control
# here we are offsetting the position of the second layer bar
# by adding the barwidth plus 0.1 to push it to the right
, aes(x = year + barwidth + 0.1, y = total, fill = type)
, position = "stack"
, stat = "identity"
, width = barwidth
) +
annotate(
"text"
, x = control_an$year + (barwidth * 1) + 0.1
,y = control_an$pos
, angle = 90
, label = control_an$treatment
) +
scale_x_discrete(limits = c(2010, 2011))
This doesn't really scale well, however there are ways you could code it up to make it suit your situation, credit where its due I originally learnt this method from the following post: https://community.rstudio.com/t/ggplot-position-dodge-with-position-stack/16425
you can play with some alpha:
df %>%
group_by(year, treatment) %>%
mutate(cum_tot = cumsum(total)) %>%
ggplot(aes(treatment, cum_tot, fill =year)) +
geom_col(data = . %>% filter( type=="Phylum1"), position = position_dodge(width = 0.9), alpha = 1) +
geom_col(data = . %>% filter( type=="Phylum2"), position = position_dodge(width = 0.9), alpha = 0.4) +
geom_tile(aes(y=NA_integer_, alpha = factor(type))) +
scale_alpha_manual(values = c(1,0.4))
Now you can add theme(panel.background = element_rect(fill ="yellow"))
some background fill to mix the colors:
Finally you have to fix the legend using inkscape.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.