Draw a line on top of stacked bar_plot - r

I would like to draw a line (or making points) on top of my stacked bar_plots. As I have no real data points I can refer to (only the spereated values and not the sum of them) I don't know how I can add such line. The Code produce this plot:
I want to add this black line(my real data are not linear):
library(tidyverse)
##Create some fake data
data3 <- tibble(
year = 1991:2020,
One = c(31:60),
Two = c(21:50),
Three = c(11:40)
)
##Gather the variables to create a long dataset
new_data3 <- data3 %>%
gather(model, value, -year)
##plot the data
ggplot(new_data3, aes(x = year, y = value, fill=model)) +
geom_bar(stat = "identity",position = "stack")

You can use stat_summary and sum for the summary function:
ggplot(new_data3, aes(year, value)) +
geom_col(aes(fill = model)) +
stat_summary(geom = "line", fun.y = sum, group = 1, size = 2)
Result:

You could get sum by year and plot it with new geom_line
library(dplyr)
library(ggplot2)
newdata4 <- new_data3 %>%
group_by(year) %>%
summarise(total = sum(value))
ggplot(new_data3, aes(x = year, y = value, fill=model)) +
geom_bar(stat = "identity",position = "stack") +
geom_line(aes(year, total, fill = ""), data = newdata4, size = 2)

Related

Maintain space between bars regardless of sample numbers

I want to make several plots same space interval between bars regardless of sample numbers
As described below.
Not like this
My original script is
myData <- read.csv('L1L2_100percent.csv', header = T, sep =',')
ggplot(data = myData, aes(x = region, y = vaf, fill = type)) +
geom_bar(stat = "identity", width = 0.4) +
coord_flip()
I think it has to do with saving pictures with a specific height, but I think the height
has to be determined with sample numbers but I don't know the exact value.
You just need to adjust the height of the plot on saving proportional to the number of bars.
Here, plt1 has 5 instead of 10 bars thus it should be saved with a height that is only half than those of plt2:
library(tidyverse)
# create example data
myData <-
iris %>% transmute(
region = row_number() %% 20,
vaf = Sepal.Length,
type = Species
)
plt1 <-
myData %>%
filter(region < 5) %>%
ggplot(aes(x = region, y = vaf, fill = type)) +
geom_bar(stat = "identity") +
coord_flip()
plt2 <-
myData %>%
filter(region < 10) %>%
ggplot(aes(x = region, y = vaf, fill = type)) +
geom_bar(stat = "identity") +
coord_flip()
ggsave("plt1.png", plt1, height = plt1$data$region %>% unique() %>% length())
ggsave("plt2.png", plt2, height = plt2$data$region %>% unique() %>% length())
Plt1:
Plt2:

How to create scaled and faceted clustered bargraphs of a summarized dataframe in ggplot2?

I am trying to create a grid of bargraphs that show the average for different species. I am using the iris dataset for this question.
I summarised the data, melted it into long form long, and tried to use facet_wrap.
iris %>%
group_by(Species) %>%
summarise(M.Sepal.Length=mean(Sepal.Length),
M.Sepal.Width=mean(Sepal.Width),
M.Petal.Length= mean(Petal.Length),
M.Petal.Width=mean(Petal.Width)) %>%
gather(key = Part, value = Value, M.Sepal.Length:M.Petal.Width) %>%
ggplot(., aes(Part, Value, group = Species, fill=Species)) +
geom_col(position = "dodge") +
facet_grid(cols=vars(Part)) +
facet_grid(cols = vars(Part))
However, the graph I am getting has x.axis labels that are strung across each facet grid. Additionally the clustered graphs are not centered within each facet box. Instead they appear at the location of their respective x-axis label. I'd like to get rid of the x-axis labels, center the graphs, and scale the graphs within each facet.
Here is an image of the resulting graph marked up with my expected output:
Perhaps this is what you're looking for?
The key changes are:
Remove Part as the variable mapped to x, that way the data is plotted in the same location in every facet
Switch to facet_wrap so you can use scales = "free_y"
Use labs to manually add the x title
Add theme to get rid of the x-axis ticks and tick labels.
library(ggplot2)
library(dplyr) # Version >= 1.0.0
iris %>%
group_by(Species) %>%
summarise(across(1:4, mean, .names = "M.{col}")) %>%
gather(key = Part, value = Value, M.Sepal.Length:M.Petal.Width) %>%
ggplot(., aes(x = 1, y = Value, group = Species, fill=Species)) +
geom_col(position = "dodge") +
facet_wrap(.~Part, nrow = 1, scales = "free_y") +
labs(x = "Part") +
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank())
I also took the liberty of switching out your manual call to summarise with the new across functionality.
Here's how you might also calculate error bars:
library(tidyr)
iris %>%
group_by(Species) %>%
summarise(across(1:4, list(M = mean, SE = ~ sd(.)/sqrt(length(.))),
.names = "{fn}_{col}")) %>%
pivot_longer(-Species, names_to = c(".value","Part"),
names_pattern = "([SEM]+)_(.+)") %>%
ggplot(., aes(x = 1, y = M, group = Species, fill=Species)) +
geom_col(position = "dodge") +
geom_errorbar(aes(ymin = M - SE, ymax = M + SE), width = 0.5,
position = position_dodge(0.9)) +
facet_wrap(.~Part, nrow = 1, scales = "free_y") +
labs(x = "Part", y = "Value") +
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank())

Label grouped bar plot in R

I'm tryng to add label to a grouped bar plot in r.
However I'm using percentege in the y axis, and I want the label to be count.
I've tried to use the geom_text() function, but I don't how exacly the parameters i need to use.
newdf3 %>%
dplyr::count(key, value) %>%
dplyr::group_by(key) %>%
dplyr::mutate(p = n / sum(n)) %>%
ggplot() +
geom_bar(
mapping = aes(x = key, y = p, fill = value),
stat = "identity",
position = position_dodge()
) +
scale_y_continuous(labels = scales::percent_format(),limits=c(0,1))+
labs(x = "", y = "%",title="")+
scale_fill_manual(values = c('Before' = "deepskyblue", 'During' = "indianred1", 'After' = "green2", '?'= "mediumorchid3"),
drop = FALSE, name="")
Here is an exemple of how I need it:
here's a sample of data I'm using:
key value
A Before
A After
A During
B Before
B Before
C After
D During
...
I also wanted to keep the bars with no value (label = 0).
Can someone help me with this?
Here is MWE of how to add count labels to a simple bar chart. See below for the case when these are grouped.
library(datasets)
library(tidyverse)
data <- chickwts %>%
group_by(feed) %>%
count %>%
ungroup %>%
mutate(p = n / sum(n))
ggplot(data, aes(x = feed, y = p, fill = feed)) +
geom_bar(stat = "identity") +
geom_text(stat = "identity",
aes(label = n), vjust = -1)
You should be able to do the same thing on your data.
EDIT: StupidWolf points out in the comments that the original example has grouped data. Adding position = position_dodge(0.9) in geom_text deals with this.
Again, no access to the original data, but here's a different MWE using mtcars showing this:
library(datasets)
library(tidyverse)
data <- mtcars %>%
as_tibble %>%
transmute(gear = as_factor(gear),
carb = as_factor(carb),
cyl = cyl) %>%
group_by(gear, carb) %>%
count
ggplot(data, aes(x = gear, y = n, fill = carb)) +
geom_bar(stat = "identity",
position = "dodge") +
geom_text(aes(label = n),
stat = "identity",
vjust = -1,
position = position_dodge(0.9))

ggplot2 weighted bar plot with position = "dodge"

I am trying to make a weighted dodged bar plot with ggplot2. With stacked bars the behavior is as expected:
df <- data.frame(group = rep(letters[1:3], each = 4),
sex = rep(c("m", "f"), times = 6),
weight = 1:12)
ggplot(df, aes(x = group, fill = sex, y = weight)) +
geom_bar(stat = "identity")
The bars have length equal to the total weight.
If I add position = "dodge", the length of the female group a bar is 4 rather than the expected 6. Similarly, all other bars are only as long as the highest weight in each group & sex combination rather than representing the total weight.
ggplot(df, aes(x = group, fill = sex, y = weight)) +
geom_bar(stat = "identity", position = "dodge")
How do I make the bar lengths match the total weight?
You can first summarise the data in your desired way and then plot it:
library(dplyr)
library(ggplot2)
df %>%
group_by(group, sex) %>%
summarise(total_weight = sum(weight)) %>%
ggplot(aes(x = group, fill = sex, y = total_weight)) +
geom_bar(stat = "identity", position = "dodge")
The problem with your original approach is that as you have several values of weight for one group, sex combination and then specify stat="identity", they are plotted on top of each other. This can be visualized:
ggplot(df, aes(x = group, fill = sex, y = weight)) +
geom_bar(stat = "identity", position = "dodge", color = "black", alpha = 0.5)
#kath's explanation is correct.
Another alternative, if you don't want to summarise the data frame before passing it to ggplot(): use the stat_summary() function instead of geom_bar():
ggplot(df, aes(x = group, fill = sex, y = weight)) +
stat_summary(geom = "bar", position = "dodge", fun.y = sum)

draw the sum value above the stacked bar in ggplot2

How do I draw the sum value of each class (in my case: a=450, b=150, c=290, d=90) above the stacked bar in ggplot2? Here is my code:
#Data
hp=read.csv(textConnection(
"class,year,amount
a,99,100
a,100,200
a,101,150
b,100,50
b,101,100
c,102,70
c,102,80
c,103,90
c,104,50
d,102,90"))
hp$year=as.factor(hp$year)
#Plotting
p=ggplot(data=hp)
p+geom_bar(binwidth=0.5,stat="identity")+
aes(x=reorder(class,-value,sum),y=value,label=value,fill=year)+
theme()
You can do this by creating a dataset of per-class totals (this can be done multiple ways but I prefer dplyr):
library(dplyr)
totals <- hp %>%
group_by(class) %>%
summarize(total = sum(value))
Then adding a geom_text layer to your plot, using totals as the dataset:
p + geom_bar(binwidth = 0.5, stat="identity") +
aes(x = reorder(class, -value, sum), y = value, label = value, fill = year) +
theme() +
geom_text(aes(class, total, label = total, fill = NULL), data = totals)
You can make the text higher or lower than the top of the bars using the vjust argument, or just by adding some value to total:
p + geom_bar(binwidth = 0.5, stat = "identity") +
aes(x = reorder(class, -value, sum), y = value, label = value, fill = year) +
theme() +
geom_text(aes(class, total + 20, label = total, fill = NULL), data = totals)
You can use the built-in summary functionality of ggplot2 directly:
ggplot(hp, aes(reorder(class, -amount, sum), amount, fill = year)) +
geom_col() +
geom_text(
aes(label = after_stat(y), group = class),
stat = 'summary', fun = sum, vjust = -1
)

Resources