How to order bars in faceted ggplot2 bar chart - r

If I want to order the bars in a ggplot2 barchart from largest to smallest, then I'd usually update the factor levels of the bar category, like so
one_group <- data.frame(
height = runif(5),
category = gl(5, 1)
)
o <- order(one_group$height, decreasing = TRUE)
one_group$category <- factor(one_group$category, levels = one_group$category[o])
p_one_group <- ggplot(one_group, aes(category, height)) +
geom_bar(stat = "identity")
p_one_group
If have have several groups of barcharts that I'd like in different facets, with each facet having bars ordered from largest to smallest (and different x-axes) then the technique breaks down.
Given some sample data
two_groups <- data.frame(
height = runif(10),
category = gl(5, 2),
group = gl(2, 1, 10, labels = letters[1:2])
)
and the plotting code
p_two_groups <- ggplot(two_groups, aes(category, height)) +
geom_bar(stat = "identity") +
facet_grid(. ~ group, scales = "free_x")
p_two_groups
what do I need to do to get the bar ordering right?
If it helps, an equivalent problem to solve is: how do I update factor levels after I've done the faceting?

here is a hack:
two_groups <- transform(two_groups, category2 = factor(paste(group, category)))
two_groups <- transform(two_groups, category2 = reorder(category2, rank(height)))
ggplot(two_groups, aes(category2, height)) +
geom_bar(stat = "identity") +
facet_grid(. ~ group, scales = "free_x") +
scale_x_discrete(labels=two_groups$category, breaks=two_groups$category2)
make UNIQUE factor variable for all entries (category2)
reorder the variable based on the height
plot on the variable: aes(x=category2)
re-label the axis using original value (category) for the variable (category2) in scale_x_discrete.

Here is a hack to achieve what you want. I was unable to figure out how to get the category values below the tick marks. So if someone can help fix that, it would be wonderful. Let me know if this works
# add a height rank variable to the data frame
two_groups = ddply(two_groups, .(group), transform, hrank = rank(height));
# plot the graph
p_two_groups <- ggplot(two_groups, aes(-hrank, height)) +
geom_bar(stat = "identity") +
facet_grid(. ~ group, scales = "free_x") +
opts(axis.text.x = theme_blank()) +
geom_text(aes(y = 0, label = category, vjust = 1.5))

Related

labels on a stacked density plot

I'm generating a stacked density plot:
ggplot(data=tydy_rawdata, aes(x=timepoint, y=tpm, group=fct_inorder(names),
fill=fct_inorder(names))) +
geom_density(position="fill",
stat="identity") +
scale_fill_manual(values = rev(mycolors))
plot :
I would like to add label on each curve (or at least the top 3 or 4) basing on the "names" displayed on the right.
I'm trying adding geom_text but the result is this :
gplot(data=tydy_rawdata, aes(x=timepoint, y=tpm, group=fct_inorder(names),
fill=fct_inorder(names))) +
geom_density(position="fill",
stat="identity") +
geom_text(aes(label=names)) +
scale_fill_manual(values = rev(mycolors))
plot :
Are there some way to do it?
First, your chart is a stacked area chart, i.e. geom_density with stat="identity" is equal to geom_area. Second, when adding labels via geom_text you have to take account of the position argument. As you use position="fill" for your density/area chart you also have to do the same for geom_text.
As you provided no example data I created my own to make your issue reproducible:
library(ggplot2)
library(forcats)
set.seed(123)
tydy_rawdata <- data.frame(
names = rep(LETTERS[1:10], each = 6),
timepoint = factor(seq(6)),
tpm = runif(6 * 10, 0, 80)
)
ggplot(data = tydy_rawdata, aes(
x = timepoint, y = tpm,
group = fct_inorder(names), fill = fct_inorder(names)
)) +
geom_area(
position = "fill",
color = "black"
) +
geom_text(aes(label = names), position = "fill")

stack bars by an ordering variable which is numeric ggplot

I am trying to create a swimlane plot of different subjects doses over time. When I run my code the bars are stacked by amount of dose. My issue is that subjects doses vary they could have 5, 10 , 5 in my plot the 5's are stacked together. But I want the represented as they happen over time. In my data set I have the amount of time each patient was on a dose for ordered by when they had the dose. I want by bars stacked by ordering variable called "p" which is numeric is goes 1,2,3,4,5,6 etc which what visit the subject had that dose.
ggplot(dataset,aes(x=diff+1, y=subject)) +
geom_bar(stat="identity", aes(fill=as.factor(EXDOSE))) +
scale_fill_manual(values = dosecol, name="Actual Dose in mg")
I want the bars stacked by my variable "p" not by fill
I tried forcats but that does not work. Unsure how to go about this the data in the dataset is arranged by p for each subject
example data
dataset <- data.frame(subject = c("1002", "1002", "1002", "1002", "1034","1034","1034","1034"),
exdose = c(5,10,20,5,5,10,20,20),
p= c(1,2,3,4,1,2,3,4),
diff = c(3,3,9,7,3,3,4,5)
)
ggplot(dataset,aes(x=diff+1, y=subject)) +
geom_bar(stat="identity", aes(fill=as.factor(exdose)),position ="stack") +
scale_fill_manual(values = dosecol, name="Actual Dose in mg")
If you want to order your stacked bar chart by p you have to tell ggplot2 to do so by mapping p on the group aesthetic. Otherwise ggplot2 will make a guess which by default is based on the categorical variables mapped on any aesthetic, i.e. in your case the fill aes:
Note: I dropped the scale_fill_manual as you did not provide the vector of colors. But that's not important for the issue.
library(ggplot2)
ggplot(dataset, aes(x = diff + 1, y = subject, group = p)) +
geom_col(aes(fill = as.factor(exdose)))
EDIT And to get the right order we have to reverse the order of the stack which could be achieved using position_stack(reverse = TRUE):
Note: To check that we have the right order I added a geom_text showing the p value.
ggplot(dataset, aes(x = diff + 1, y = subject, group = p)) +
geom_col(aes(fill = as.factor(exdose)), position = position_stack(reverse = TRUE)) +
geom_text(aes(label = p), position = position_stack(reverse = TRUE))
Second option would be to convert p to a factor which the order of levels set in the reverse order:
ggplot(dataset, aes(x = diff + 1, y = subject, group = factor(p, rev(sort(unique(p)))))) +
geom_col(aes(fill = as.factor(exdose))) +
geom_text(aes(label = p), position = "stack")

How to add an Asterix (significance) above specific bars in faceted bar graph (ggplot R)

I am trying to plot a bar graph using ggplot. The graph is displaying as I would like but I can't figure out how to add an Asterix "*" above some of the bars to show significance. Whenever I try it wither adds them to all of the bars or completely seems to skew the graph.
I need to have an Asterix only above
Group A: Treatment A and Treatment B;
Group B: Treatment A
Thankyou!!
Treatment <- rep(c("Treatment A","Treatment A","Treatment B","Treatment B"), 3)
Group <- c(rep(c("A. Paired cohort"), 4),rep(c("B. Low cohort"), 4),rep(c("C. Normal cohort"), 4))
Outcome <- rep(c("Outcome P","Outcome D"),6)
Percent <- c(6.7,3.3,22.6,16.1,4.9,2.4,25,15,8.2,4.1,20.8,17)
df <- data.frame(Treatment,Group,Outcome,Percent)
#keep original order, not alphabetised
df$Outcome <- factor(df$Outcome, levels = unique(df$Outcome)
#plot graph
ggplot(df,
aes(x=Outcome, y=Percent)) +
geom_bar(aes(fill=Treatment),stat="identity", position="dodge")+
theme_classic() +
scale_fill_grey() +
xlab("") + ylab("%") +
facet_wrap(~Group) +
ylim(0,40)
One option would be to
Add an indicator variable to your data to indicate signifcance using e.g. dplyr::case_when.
This indicator could then be used in geom_text to conditionally add an asterisk as a label on top of the desired bars. To align the * with bars we have to map Treatment on the group aes and make use of position_dodge(width = .9), where .9 is the default width of a geom_bar/col. Additionally I set vjust=-.1 to put the labels slightly above the bars.
library(ggplot2)
library(dplyr)
df$significant <- dplyr::case_when(
grepl("^A", df$Group) & grepl("(A|B)$", df$Treatment) ~ TRUE,
grepl("^B", df$Group) & grepl("A$", df$Treatment) ~ TRUE,
TRUE ~ FALSE
)
# plot graph
ggplot(df, aes(x = Outcome, y = Percent)) +
geom_col(aes(fill = Treatment), position = "dodge") +
geom_text(aes(label = ifelse(significant, "*", ""), group = Treatment),
position = position_dodge(width = .9), vjust = -.1, size = 20 / .pt) +
theme_classic() +
scale_fill_grey() +
labs(x = "", y = "%") +
facet_wrap(~Group) +
ylim(0, 40)

Equal bar width across facet_wrap barplots

I have a data frame that looks like this:
category = c(rep("house", 2), rep("apartment", 4), rep("condo", 3))
sample = paste("ID", seq(1:9), sep='')
group = c(rep(1,9), rep(2,9))
value = c(0.990000, 0.608143, 0.451284, 0.500343, 0.482670, 0.358965, 0.393272, 0.300472, 0.334363, 0.001000, 0.391857, 0.548716, 0.499657, 0.517330, 0.641035, 0.606728, 0.699528, 0.665637)
data = as.data.frame(cbind(category, sample, group, value))
I want to use the variable 'category' to facet_wrap a stacked barplot, like this:
ggplot(data, aes(x=sample, y=value, fill=group)) +
geom_bar(stat="identity", width=1) +
facet_wrap(facet ~ ., scales="free_x")
The number of samples in each category is uneven but ggplot automatically makes each barplot the same width, meaning that the bars across plots are not the same width, like this:
Is there a way to force ggplot to keep the bars all the same width, such that the overall width of each barplot is different across plots?
Thanks for any tips!
Try facet_grid
ggplot(data, aes(x = sample, y = value, fill = group)) +
geom_bar(stat = "identity", width = 1, col = "black") +
facet_grid(. ~ category, scales = "free", space = "free")

Plotting a bar chart with years grouped together

I am using the fivethirtyeight bechdel dataset, located here https://github.com/rudeboybert/fivethirtyeight, and am attempting to recreate the first plot shown in the article here https://fivethirtyeight.com/features/the-dollar-and-cents-case-against-hollywoods-exclusion-of-women/. I am having trouble getting the years to group together similarly to how they did in the article.
This is the current code I have:
ggplot(data = bechdel, aes(year)) +
geom_histogram(aes(fill = clean_test), binwidth = 5, position = "fill") +
scale_fill_manual(breaks = c("ok", "dubious", "men", "notalk", "nowomen"),
values=c("red", "salmon", "lightpink", "dodgerblue",
"blue")) +
theme_fivethirtyeight()
I see where you were going with using the histogram geom but this really looks more like a categorical bar chart. Once you take that approach it's easier, after a bit of ugly code to get the correct labels on the year columns.
The bars are stacked in the wrong order on this one, and there needs to be some formatting applied to look like the 538 chart, but I'll leave that for you.
library(fivethirtyeight)
library(tidyverse)
library(ggthemes)
library(scales)
# Create date range column
bechdel_summary <- bechdel %>%
mutate(date.range = ((year %/% 10)* 10) + ((year %% 10) %/% 5 * 5)) %>%
mutate(date.range = paste0(date.range," - '",substr(date.range + 5,3,5)))
ggplot(data = bechdel_summary, aes(x = date.range, fill = clean_test)) +
geom_bar(position = "fill", width = 0.95) +
scale_y_continuous(labels = percent) +
theme_fivethirtyeight()
ggplot

Resources