How to change the order of fill aesthetic in faceted ggplot? - r

I have a faceted ggplot that is all but done. I cannot seem to get the fill aesthetic to be descending for each group in the dodged plot and across facets. The idea is to look at the plot and quickly recognise the top three categories within each group on the y-axis - and that the colors will be order different for each group. Here is some code to get a representative graph.
library(tidyverse)
set.seed(123)
#using crossing from purrr
df <- crossing(
mean = 1:8,
cats = sample(letters[1:3], 8, T),
gender = c('Male', 'Female')) %>%
mutate(vary_x = sample(seq(1,3,.1),nrow(.), T))
df %>%
ggplot(aes(mean, vary_x, fill = cats))+
geom_bar(stat = 'identity',
position = 'dodge') +
facet_grid(.~gender) +
coord_flip()

Something like this maybe:
df %>%
ggplot(aes(mean, reorder(vary_x,mean), fill = cats))+
geom_bar(stat = 'identity',
position = 'dodge') +
facet_grid(.~gender) +
coord_flip()

Related

ggplot2 barplot - adding percentage labels inside the stacked bars but retaining counts on the y-axis

I have created an stacked barplot with the counts of a variables. I want to keep these as counts, so that the different bar sizes represent different group sizes. However, inside the bar plot i would like to add labels that show the proportion of each stack - in terms of percentage.
I managed to create the stacked plot of count for every group. Also I have created the labels and they are are placed correctly. What i struggle with is how to calculate the percentage there?
I have tried this, but i get an error:
dataex <- iris %>%
dplyr::group_by(group, Species) %>%
dplyr::summarise(N = n())
names(dataex)
dataex <- as.data.frame(dataex)
str(dataex)
ggplot(dataex, aes(x = group, y = N, fill = factor(Species))) +
geom_bar(position="stack", stat="identity") +
geom_text(aes(label = ifelse((..count..)==0,"",scales::percent((..count..)/sum(..count..)))), position = position_stack(vjust = 0.5), size = 3) +
theme_pubclean()
Error in (count) == 0 : comparison (1) is possible only for atomic
and list types
desired result:
well, just found answer ... or workaround. Maybe this will help someone in the future: calculate the percentage before the ggplot and then just just use that vector as labels.
dataex <- iris %>%
dplyr::group_by(group, Species) %>%
dplyr::summarise(N = n()) %>%
dplyr::mutate(pct = paste0((round(N/sum(N)*100, 2))," %"))
names(dataex)
dataex <- as.data.frame(dataex)
str(dataex)
ggplot(dataex, aes(x = group, y = N, fill = factor(Species))) +
geom_bar(position="stack", stat="identity") +
geom_text(aes(label = dataex$pct), position = position_stack(vjust = 0.5), size = 3) +
theme_pubclean()

Reorder vertical axis alphabetically and change position of binary variable of stacked percent bar graph (ggplot2)

I have a dataset with two variables: 1) ID, 2) Infection Status (Binary:1/0).
I would like to use ggplot2 to
Create a stacked percentage bar graph with the various ID on the verticle-axis (arranged alphabetically with A starting on top), and the percent on the horizontal-axis. I can't seem to get a code that will automatically sort the ID alphabetically as my original dataset has quite a number of categories and will be difficult to arrange them manually.
I also hope to have the infected category (1) to be red and towards the left of the blue non-infected category (0). Is it also possible to change the sub-heading of the legend box from "Non_infected" to "Non-infected"?
I hope that the displayed ID in the plot will include the count of the number of times the ID appeared in the dataset. E.g. "A (n=6)", "B (n=3)"
My sample code is as follow:
ID <- c("A","A","A","A","A","A",
"B","B","B",
"C","C","C","C","C","C","C",
"D","D","D","D","D","D","D","D","D")
Infection <- sample(c(1, 0), size = length(ID), replace = T)
df <- data.frame(ID, Infection)
library(ggplot2)
library(dplyr)
library(reshape2)
df.plot <- df %>%
group_by(ID) %>%
summarize(Infected = sum(Infection)/n(),
Non_Infected = 1-Infected)
df.plot %>%
melt() %>%
ggplot(aes(x = ID, y = value, fill = variable)) + geom_bar(stat = "identity", position = "stack") +
xlab("ID") +
ylab("Percent Infection") +
scale_fill_discrete(guide = guide_legend(title = "Infection Status")) +
coord_flip()
Right now I managed to get this output:
I hope to get this:
Thank you so much!
First, we need to add a count to your original data.frame.
df.plot <- df %>%
group_by(ID) %>%
summarize(Infected = sum(Infection)/n(),
Non_Infected = 1-Infected,
count = n())
Then, we augment our ID column, turn the Infection Status into a factor variable, use forcats::fct_rev to reverse the ID ordering, and use scale_fill_manual to control your legend.
df.plot %>%
mutate(ID = paste0(ID, " (n=", count, ")")) %>%
select(-count) %>%
melt() %>%
mutate(variable = factor(variable, levels = c("Non_Infected", "Infected"))) %>%
ggplot(aes(x = forcats::fct_rev(ID), y = value, fill = variable)) +
geom_bar(stat = "identity", position = "stack") +
xlab("ID") +
ylab("Percent Infection") +
scale_fill_manual("Infection Status",
values = c("Infected" = "#F8766D", "Non_Infected" = "#00BFC4"),
labels = c("Non-Infected", "Infected"))+
coord_flip()

Ggplot grouped column chart with two sets of x labels

I have the following dataset which produces a grouped bar plot:
library(ggplot2)
library(dplyr)
expand.grid(gender=c("M","F"),
education=c("HS","College","Advanced"),
value = sample(1:20,8, replace = T)) %>%
ggplot(aes(x = education, y = value, fill = gender))+
geom_col(position = position_dodge())
But instead of having a legend I want the labels to be on the x axis like this:
Is this possible?
Thanks
as camille already mentioned in a comment, you can use facet_wrap
expand.grid(gender=c("M","F"),
education=c("HS","College","Advanced"),
value = sample(1:20,8, replace = T)) %>%
ggplot(aes(x = gender, y = value, fill = gender))+
geom_col(position = position_dodge()) +
facet_wrap(~education)
The resulting plot looks like this:
If you want to remove the legend, just add theme(legend.position="none")

Plot many variables

Having a dataframe like this one:
From a dataframe like this one:
data <- data.frame(year = c(2010,2011,2012,2010,2011,2012),
name = c("stock1","stock1","stock1","stock2","stock2","stock2"),
value = c(0,3,1,4,1,3))
I would like to create a plot and I use this:
library(ggplot2)
ggplot(data=data, xName="year", groupName="name", brewerPalette="Blues")
but I can't receive the plot. Anything wrong in the call?
I think you need something like this:
library(ggplot2)
library(dplyr)
library(RColorBrewer)
df %>%
group_by(name) %>%
ggplot(aes(year,value,fill=name))+
geom_col()+
scale_fill_brewer(palette = "Blues")
If you want a grouped bar plot (as I guessed from your code), this code may be helpful:
ggplot(data = data, aes(x = as.factor(year), y = value, fill = name)) +
geom_bar(stat = "identity", position = position_dodge(0.8), width = 0.7) +
scale_fill_brewer(palette = "Blues")

How to order bars in faceted ggplot2 bar chart

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))

Resources