ggplot combine dodge with stacked barplot - r

I would like to combine stacked with dodge style of a barplot in ggplot. I'm quite near it with this code:
dates_g <- as.Date(c("2020-03-30","2020-03-30", "2020-04-30","2020-04-30", "2020-05-30","2020-05-30"))
value_x <- c(1, 2, 4, 1.4, 3.2, 1.3)
value_y <- c(1.2, 3, 4.6, 1, 3, 1)
ID <- c("A", "B", "A", "B", "A", "B")
results <- data.frame(dates_g, value_x, value_y, ID)
barwidth = 13
bar_comparison <- ggplot() +
geom_bar(data = results[,c(1,2,4)],
mapping = aes(x=dates_g , y=value_x, fill=ID),
stat ="identity",
position = "stack",
width = barwidth) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
geom_bar(data = results[,c(1,3,4)],
mapping = aes(x=dates_g + barwidth + 0.01 , y=value_y, fill=ID),
stat ="identity",
position = "stack",
width = barwidth) +
xlab("Date") + ylab("Value (in millions)")
ggplotly(bar_comparison)
which gives as a result:
I'm still not happy about two things: I would like the date to be between the two bars (but this is a minor problem) and then I really would like to have, for each date, different colors for the two bars: for example I would like to have the left bar to be in a scale of green (dark green and light green) and the right one in a scale of blue (dark blue and light blue). is it possible?

This at least is a solution for the main question.
I would suggest to use facet_wrap.
Data preparation for this -> bring data in long format, Extract the month name of your date (I use lubridate for this), then plot with ggplot
library(lubridate)
results_long <- results %>%
pivot_longer(
cols = starts_with("value"),
names_to = "Names",
values_to = "Values"
) %>%
mutate(dates_name = parse_number(as.character(dates_g)),
dates_name = month(ymd(dates_g), label = TRUE))
ggplot(results_long, aes(x = Names, y = Values, fill = ID)) +
geom_bar(stat = 'identity', position = 'stack') + facet_grid(~ dates_name) +
theme_bw()

Related

how to prevent bars from stacking, when a factor is present multiple times?

I am having issues in preventing same factor from stacking on top of itself when plotting a barplot. Problem is that I don't know how to plot the unique values of such factor and i end up having it n times (n = times the factor is repeated) in the same plot. Here a nice example of the issue:
library("ggplot2")
mydata <- data.frame(var_one=rep(c("a", "b", "c", "d", "e"), 5), var_two=rep(c(1.5, 2, 2.2, 1.8, 1.2), 5))
dev.new()
ggplot(mydata, aes(x=var_one, y=var_two)) +
geom_bar(stat="identity", fill="lightcoral", alpha=.8, width=.4, color="black")
the goal is to have only one of the multiple stacked factors. How to do it? I also tried with geom_col, instead of geom_bar but it doesn't seem to solve the issue.
dev.new()
ggplot(mydata, aes(x=var_one, y=var_two)) +
geom_col(fill="lightcoral", alpha=.8, width=.4, color="black")
This is what i need:
mydata_mod <- data.frame(var_one=c("a", "b", "c", "d", "e"), var_two=c(1.5, 2, 2.2, 1.8, 1.2))
dev.new()
ggplot(mydata_mod, aes(x=var_one, y=var_two)) +
geom_bar(stat="identity", fill="lightcoral", alpha=.8, width=.4, color="black")
but the problem is the data structure that i am using is not in the format of mydata_mod but it is defined as mydata and i have to keep it that way. Ideas?
You could achieve your desired result by using stat_summary or by switching to stat="summary" in geom_bar to compute the sum on the fly:
library("ggplot2")
ggplot(mydata, aes(x = var_one, y = var_two)) +
stat_summary(
geom = "bar", fun = "sum",
fill = "lightcoral", alpha = .8, width = .4, color = "black"
)
ggplot(mydata, aes(x = var_one, y = var_two)) +
geom_bar(
stat = "summary", fun = "sum",
fill = "lightcoral", alpha = .8, width = .4, color = "black"
)
Another option is to wrangle the data:
library(dplyr)
library(ggplot2)
mydata %>%
group_by(var_one) %>%
summarise(sum = sum(var_two)) %>%
ggplot(aes(x = var_one, y=sum)) +
geom_col(fill="lightcoral", alpha=.8, width=.4, color="black")

R Stacked Bar Chart: How to change the order of geom text labels

The geom Texts labels are automatically in decreasing order instead of the data frame.
The question is concerning this part of the snippet "geom_text(aes(label = Freq)..."
Here you can clearly see the that the order is not followed by geom_text. But Frequency descreasing in all categories.
ggplot(df_beine_clan, aes(x = Var2, y = Freq, fill = Var1)) +
geom_bar(stat = "identity") +
geom_text(aes(label = Freq), vjust = 0, size = 5, nudge_y = 2, nudge_x = -0.5)
See Freq Order
How to command that the order should not be changed when rendered on the bar chart?
You could add position_stack like this:
library(ggplot2)
ggplot(df_beine_clan, aes(x = Var2, y = Freq, fill = Var1)) +
geom_bar(stat = "identity") +
geom_text(aes(label = Freq), position = position_stack(vjust = 0.5), size = 5)
Created on 2022-09-03 with reprex v2.0.2
Answering your question without having a MWE is a bit tricky. Hence, as Julien mentioned, an output of dput(df_beine_clan) would be helpful.
I tried to recreate an example, but this might not be applicable to the structure of your data. It might give you an example, however how to tackle the problem. I have created a column in the data table, that contains the label I think you want to add to your plot. Having a separate column gives you more flexibility inside ggplot.
library(tidyverse)
Group <- c("A", "A", "A", "B", "B", "B")
Value <- c(2,4,6,8,10,12)
Response <- c("Yes","No","Maybe","Yes","No","Maybe")
label <- Value
df <- data.frame(Group, Value, Response, label)
ggplot(df, aes(x = Group, y = Value, fill = Response)) + geom_bar(stat = "identity") +
geom_text(aes(label = label), position = position_stack(vjust = 0.5))
Changing the variable label to label <- sort(Value, decreasing = T) or label <- c("Blue", "Green", "Red", "Blue", "Green", "Red") gives you the two figures below.

gghighlight (R): Labeling bar charts

Alright, after a long silent read along, here's my first question. I am trying to add corresponding labels of unhighlighted items for a grouped barplot. When I insert gghighlight in front of the geom_text I get the following plot:
library(tidyverse)
library(gghighlight)
df <- data.frame (group = c("A", "A", "B", "B", "C", "C"),
value = c("value_1", "value_2","value_1", "value_2","value_1", "value_2"),
mean = c(1.331, 1.931, 3.231, 3.331, 4.631, 3.331)
)
ggplot(data = df, aes(x = group, y = mean, fill = value)) +
geom_bar(stat = "identity", position = "dodge") +
gghighlight(group != "B",
label_key = group
) +
geom_text(aes(label = round(mean, digits = 2)),
stat= "identity",
vjust = -.5,
position = position_dodge(width = .9)
)
If I move gghightlight behind the geom_text I get the following plot:
ggplot(data = df, aes(x = group, y = mean, fill = value)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label = round(mean, digits = 2)),
stat= "identity",
vjust = -.5,
position = position_dodge(width = .9)
) +
gghighlight(group != "B",
label_key = group)
Is there a way to label the unhighligthed bars like the highlighted ones?
Thanks in advance.
############## EDIT ###########
Besides graying out certain columns (see #TarJae's answer), there is also the possibility to make them transparent (essential parts are from this post: ggplot transparency on individual bar):
subset_df <- df %>%
mutate(alpha.adj = as.factor(ifelse(group != "B", 1, 0.6)))
ggplot(data = subset_df, aes(x = group, y = mean, fill = value, alpha=factor(alpha.adj))) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label = round(mean, digits = 2)),
stat= "identity",
vjust = -.5,
position = position_dodge(width = .9)
) +
scale_alpha_manual(values = c("0.6"=0.6, "1"=1), guide='none')
[]
Are you looking for this?
This is a solution without using gghighlight package:
library(tidyverse)
subset_df <- df %>%
mutate(highlight = if_else(group != "B", mean, NA_real_))
ggplot(data = subset_df, aes(x = group, y = mean, group=value)) +
geom_col(fill = 'grey', alpha = 0.6, position = 'dodge') +
geom_col(aes(y = highlight, fill = value), position = 'dodge') +
geom_text(aes(group, label = round(mean, digits = 2)),
position = position_dodge(width = 1))
This is a solution with the gghighlight package and some limited hacky code.
When reading the vignette, I noticed that the author of the package "filters out" the data that are not highlighted. You can see that if you save your highlighted plot in p_h and then look at p_h$data, the values for group B have disappeared.
library(tidyverse)
library(gghighlight)
p_h <- ggplot(data = df, aes(x = group, y = mean, fill = value)) +
geom_bar(stat = "identity", position = "dodge") +
gghighlight(group != "B",
label_key = group) +
geom_text(aes(label = round(mean, digits = 2)),
stat= "identity",
vjust = -.5,
position = position_dodge(width = .9))
> p_h$data
group value mean
1 A value_1 1.331
2 A value_2 1.931
5 C value_1 4.631
6 C value_2 3.331
If we re-insert the data (after the call to gghighlight() has removed them), then geom_text() will be able to find the means for group B again.
One can "recover" the data and re-insert them with the following code:
### create a ggplot object with the original complete data
### you could check that with p_to_copy_data$data
p_to_copy_data <- ggplot(data = df)
### copy the complete data to your highlighted plot data section
p_h$data <- p_to_copy_data$data
p_h
This yields the following graph:

How to position labels on grouped bar plot columns in ggplot2

I am having trouble positioning percentage&count labels on a grouped barplot.
The labels are currently stacked together:
I think this is because I have been referring to an example code for a stacked barplot. I have tried adding position=position_dodge(width=1) to geom_textto unstack the labels, but I have gotten the following warning:
Warning: Ignoring unknown aesthetics: position
Don't know how to automatically pick scale for object of type PositionDodge/Position/ggproto/gg. Defaulting to continuous.
Error: Aesthetics must be valid data columns. Problematic aesthetic(s): position = position_dodge(width = 1).
Did you mistype the name of a data column or forget to add stat()?
Here is the code I have using the Titanic dataset:
data("titanic_train")
head(titanic_train, 6)
library(dplyr)
library(ggplot2)
titanic_train$Survived <- as.factor(titanic_train$Survived)
summary = titanic_train %>% group_by(Survived, Sex) %>% tally %>% mutate(pct = n/sum(n))
ggplot(summary, aes(x=Sex, y=n, fill=Survived)) + geom_bar(stat="identity", position="dodge") + geom_text(aes(label=paste0(sprintf("%1.1f", pct*100),"%\n", n)), colour="black")
How can I resolve this?
You can just add position = position_dodge(width = 1) to your geom_text call, but outside of aes. Your error was caused by trying to put position... inside aes.
library(dplyr)
library(ggplot2)
library(titanic)
ggplot(summary, aes(x = Sex, y = n, fill = Survived)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label = paste0(sprintf("%1.1f", pct * 100), "%\n", n)),
colour = "black",
position = position_dodge(width = 1)) +
coord_cartesian(ylim = c(0, 550))
I would like to share an example which you could replicate the same by using your data
data
df <- data.frame(
x = factor(c(1, 1, 2, 2)),
y = c(1, 3, 2, 1),
grp = c("a", "b", "a", "b")
)
plot
ggplot(data = df, aes(x, y, group = grp)) +
geom_col(aes(fill = grp), position = "dodge") +
geom_text(
aes(label = y, y = y + 0.05),
position = position_dodge(0.9),
vjust = 0
)

Control bar border (color) thickness with ggplot2 stroke

Is it possible to use the stroke argument introduced with ggplot2 2.0 to adjust the thickness of borders around bars? If not, is there a way to control bar-border thickness along the lines of point-border thickness? Stroke applies to borders around certain shapes -- see the second answer
A very modest MWE, showing fill only:
factor <- c("One", "Two", "Three", "Four")
value <- c(1, 2, 3, 4)
factor2 <- c("A", "B", "A", "B")
df <- data.frame(factor = factor(factor, levels = factor),
value = value, factor2 = factor2)
ggplot(df, aes(x = factor, y = value, color = factor2)) +
geom_bar(stat = "identity")
EDIT after COMMENT
OK, thanks to MLavoie's comment, it was so simple. Here is the code I have ended with, and, no, I am not actually using this plot other than to teach about ggplot and its capabilities.
ggplot(df, aes(x = factor, y = value, color = factor2)) +
scale_color_manual(values = c("darkgreen", "slateblue4")) +
geom_bar(stat = "identity", aes(fill = "transparent", size = ifelse(factor2 == "A", 2, 1))) +
guides(fill = FALSE) +
guides(size = FALSE) +
guides(color = FALSE)
well as I suggested by the OP, I will just recopy my comment as an answer.
you just need to set size in your geom_bar() expression:
geom_bar(stat = "identity", aes(fill = "transparent", size = ifelse(factor2 == "A", 2, 1)), size=2)

Resources