I am working a making som nice plots that I can copy-paste when needed (that is why I have included so many options). So I have this plot:
library(tidyverse)
mtcars %>%
group_by(cyl) %>%
summarise(n=n()) %>%
ungroup() %>%
mutate(cars = "cars") %>%
ggplot(aes(x = as.factor(cars), y = n, fill=as.factor(cyl))) +
geom_bar(stat="identity", width = .3) +
geom_text(aes(label = paste0(round(n, digits = 0), "stk.")),
position = position_stack(vjust = 0.5)) +
labs(title = "Number of cars with cylinders in the data set",
subtitle= "If needed",
caption= "Fodnote",
x= "", y="Antal",
fill="# of cylinders") +
theme(#legend.position="none",
plot.caption = element_text(hjust = 0))
How can I reorder the stacks so e.g. the blue is at the bottom, then the red stack and the green stack on top.
Thanks. I think the solution involes forcats...
Is this what you're looking for? To change the fill color, use scale_fill_manual() or scale_fill_brewer()
library(tidyverse)
library(forcats)
mtcars %>%
group_by(cyl) %>%
summarise(n=n()) %>%
ungroup() %>%
mutate(cars = "cars",
cars = factor(cars),
cyl = factor(cyl)) %>%
# use fct_reorder here
mutate(cyl = fct_reorder(cyl, n)) %>%
ggplot(aes(x = cars, y = n, fill = cyl)) +
geom_col(width = .3) +
geom_text(aes(label = paste0(round(n, digits = 0), "stk.")),
position = position_stack(vjust = 0.5)) +
labs(title = "Number of cars with cylinders in the data set",
subtitle = "If needed",
caption = "Footnote",
x = "", y = "Antal",
fill = "# of cylinders") +
theme(#legend.position="none",
plot.caption = element_text(hjust = 0))
To define order, convert cyl to factor with desired levels.
df1 = mtcars
df1$cyl = factor(df1$cyl, levels = c(6, 4, 8))
df1 %>%
group_by(cyl) %>%
summarise(n=n()) %>%
ungroup() %>%
mutate(cars = "cars") %>%
ggplot(aes(x = as.factor(cars), y = n, fill=as.factor(cyl))) +
#scale_fill_manual(values=c("green", "red", "blue")) +
geom_bar(stat="identity", width = .3) +
geom_text(aes(label = paste0(round(n, digits = 0), "stk.")),
position = position_stack(vjust = 0.5)) +
labs(title = "Number of cars with cylinders in the data set",
subtitle= "If needed",
caption= "Fodnote",
x= "", y="Antal",
fill="# of cylinders") +
theme(#legend.position="none",
plot.caption = element_text(hjust = 0))
Related
I have been attempting to add a label on top of each bar to represent the proportion that each ethnic group makes up in referrals.
For some reason I cannot get the labels to be placed at the top of each bar. How do I fix this?
My code below
freq <- df %>%
group_by(ethnicity) %>%
summarise(n = n()) %>%
mutate(f = round((n/sum(n)*100, 1))
df %>%
group_by(pathway) %>%
count(ethnicity) %>%
ggplot(aes(x = ethnicity, y = n , fill = pathway)) +
geom_bar(stat = "identity", position = "stack") +
geom_text(data = freq,
aes(x= ethnicity, y = f, label = f),
inherit.aes = FALSE) +
theme(legend.position = "bottom") +
scale_fill_manual(name = "",
values = c("light blue", "deepskyblue4"),
labels = "a", "b") +
xlab("") +
ylab("Number of Referrals") +
scale_y_continuous(breaks = seq(0, 2250, 250), expand = c(0,0)
Here is what it currently looks like
Since you are using the count as your y-axis position in geom_bar, you need to use the same thing in your geom_text to get the labels in the right place. Below is an example using mtcars dataset. Using vjust = -1 I put a little bit of space between the label and the bars to make it more legible and aesthetically pleasing.
library(tidyverse)
mtcars %>%
group_by(carb) %>%
summarise(n = n()) %>%
mutate(f = round(proportions(n) * 100, 1)) -> frq
mtcars %>%
group_by(gear) %>%
count(carb) -> df
df %>%
ggplot(aes(x = carb, y = n, fill = gear)) +
geom_bar(stat = "identity", position = "stack") +
geom_text(data = frq,
vjust = -1,
aes(x= carb, y = n, label = f),
inherit.aes = FALSE)
Created on 2022-10-31 by the reprex package (v2.0.1)
I am using a dataframe to create facet plot by months to view highest covid CFR states for each month (Issue shown in point 3).
DF:
df_ind_stacked_cum <- read.csv(url("https://raw.githubusercontent.com/johnsnow09/covid19-df_stack-code/main/df_ind_stacked_cum.csv"))
When I create a plot this is what I get:
2.1
2.2 code:
df_ind_stacked_cum %>%
filter(!State.UnionTerritory %in%
c("Maharashtra***","Punjab***","Chandigarh***","Telangana***", "Cases being reassigned to states")) %>%
mutate(month = lubridate::month(Date, label = TRUE, abbr = TRUE)) %>%
filter(Cases_type == "Confirmed") %>%
group_by(State.UnionTerritory, month) %>%
summarise(CFR = max(CFR, na.rm = TRUE)) %>%
group_by(month) %>%
top_n(n = 7, wt = CFR) %>%
ungroup() %>%
mutate(State.UnionTerritory = fct_reorder(State.UnionTerritory, CFR, max)) %>%
ggplot(aes(x = CFR, y = State.UnionTerritory,
fill = State.UnionTerritory, group = State.UnionTerritory )) +
geom_col() +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90),
legend.position = "none") +
facet_wrap(~month) +
# coord_cartesian(clip = "off") +
# scale_fill_tableau() +
labs(title = "Top 7 CFR States based on each month")
Issue: When I add scale_fill_brewer() then plot looks changed ?
3.1
3.2 Code:
df_ind_stacked_cum %>%
filter(!State.UnionTerritory %in%
c("Maharashtra***","Punjab***","Chandigarh***","Telangana***", "Cases being reassigned to states")) %>%
mutate(month = lubridate::month(Date, label = TRUE, abbr = TRUE)) %>%
filter(Cases_type == "Confirmed") %>%
group_by(State.UnionTerritory, month) %>%
summarise(CFR = max(CFR, na.rm = TRUE)) %>%
group_by(month) %>%
top_n(n = 7, wt = CFR) %>%
ungroup() %>%
mutate(State.UnionTerritory = fct_reorder(State.UnionTerritory, CFR, max)) %>%
ggplot(aes(x = CFR, y = State.UnionTerritory,
fill = State.UnionTerritory, group = State.UnionTerritory )) +
geom_col() +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90),
legend.position = "none") +
facet_wrap(~month) +
# coord_cartesian(clip = "off") +
# scale_fill_tableau() +
labs(title = "Top 7 CFR States based on each month") +
scale_fill_brewer(palette = "Paired")
It gets changed based on palette I select:
scale_fill_brewer(palette = "Set2")
How can I change colors without changing the plot?
I have a stacked bar chart of proportions, so all bars total 100%. I would like to add a label to the end of each bar (i.e. on the far right-hand side of each bar, not within the bar itself) to show the total number of observations in each bar.
Something like this gets close-ish...
library(dplyr)
library(ggplot2)
data("mtcars")
mtcars %>%
# prep data
mutate(across(where(is.numeric), as.factor)) %>%
count(am, cyl, gear) %>%
mutate(prop = n / sum(n)) %>%
# plot
ggplot(aes(x = prop, y = cyl)) +
geom_col(aes(fill = gear),
position = "fill",
alpha = 0.8) +
facet_wrap(~am, ncol = 1) +
theme_minimal() +
scale_x_continuous(labels = scales::percent) +
# add labels to show total n for each bar
geom_text(aes(label = paste0("n = ", stat(y)), group = cyl),
stat = 'summary',
fun = sum)
...but (i) the values for my n labels clearly aren't the sums for each bar that I was expecting, and (ii) I can't figure out how to position the labels at the end of each bar. I thought I could specify a location on the x-axis within the geom_text aes, like this...
mtcars %>%
# prep data
mutate(across(where(is.numeric), as.factor)) %>%
count(am, cyl, gear) %>%
mutate(prop = n / sum(n)) %>%
# plot
ggplot(aes(x = prop, y = cyl)) +
geom_col(aes(fill = gear),
position = "fill",
alpha = 0.8) +
facet_wrap(~am, ncol = 1) +
theme_minimal() +
scale_x_continuous(labels = scales::percent) +
# add labels to show total n for each bar
geom_text(aes(label = paste0("n = ", stat(y)), group = cyl, x = 1),
stat = 'summary',
fun = sum)
...but I can't work out why that throws the x-axis scale out, and doesn't position all the labels at the same location on the scale.
Thanks in advance for any suggestions!
Try this:
library(dplyr)
library(ggplot2)
data("mtcars")
#Code
mtcars %>%
# prep data
mutate(across(where(is.numeric), as.factor)) %>%
count(am, cyl, gear) %>%
mutate(prop = n / sum(n)) %>%
# plot
ggplot(aes(x = prop, y = cyl)) +
geom_col(aes(fill = gear),
position = "fill",
alpha = 0.8) +
geom_text(aes(x=1.05,label = paste0("n = ", stat(y)), group = cyl),
hjust=0.5
)+
facet_wrap(~am, ncol = 1,scales = 'free')+
theme_minimal() +
scale_x_continuous(labels = scales::percent)
Output:
This is a modified version to add both proportions and numbers
library(dplyr)
library(ggplot2)
library(scales)
data("mtcars")
mtcars %>%
# prep data
mutate(across(where(is.numeric), as.factor)) %>%
count(am, cyl, gear) %>%
mutate(prop = n / sum(n)) %>%
# plot
ggplot(aes(x = prop, y = cyl)) +
geom_col(aes(fill = gear),
position = "fill", alpha = 0.8) +
theme_minimal() +
scale_x_continuous(labels = scales::percent) +
# add labels to show total n for each bar
geom_text(aes(x = 1.1, , group = cyl,
label = paste0("n = ", stat(y))),
hjust = 0.5) +
geom_text(aes(x = prop, y = cyl, group = gear,
label = paste0('p =',round(stat(x),2))),
hjust = 0.5, angle = 0,
position = position_fill(vjust = .5)) +
facet_wrap(~am, ncol = 1, scales = 'free')
It's not the most elegant solution, but I got there in the end by expanding on #Duck's answer for the positioning of labels (thanks!), and calculating the totals to be used as labels outside of ggplot.
mtcars %>%
# prep data
mutate(across(where(is.numeric), as.factor)) %>%
count(am, cyl, gear) %>%
group_by(cyl, am) %>%
mutate(prop = n / sum(n)) %>%
mutate(column_total = sum(n)) %>%
ungroup() %>%
# plot
ggplot(aes(x = prop, y = cyl)) +
geom_col(aes(fill = gear),
position = "fill",
alpha = 0.8) +
geom_text(aes(x = 1.05, label = paste0("n = ", column_total))) +
facet_wrap(~am, ncol = 1, scales = 'free')+
theme_minimal() +
scale_x_continuous(labels = scales::percent)
I have a face_wrapped plot with free y axis in ggplot2. I was wondering if it is possible to reposition some of the flipped x-axis label based on the red arrows shown in the picture below?
library(tidyverse)
data <- read_csv('https://raw.githubusercontent.com/rnorouzian/e/master/surv.csv')
names(data)[2:5] <- c("Representation", "Solidification", "Application", "Confidence")
data %>%
pivot_longer(cols = -id) %>%
mutate(name = name,
value = str_wrap(value, 20)) %>%
ggplot() +
geom_bar(aes(value, fill = name), show.legend = FALSE) +
facet_wrap(.~name, scales = 'free_y') +
coord_flip() +
labs(y = "Students", x = "") +
theme(axis.text.y = element_text(size=8))
We can reorder after creating the frequency with count
library(dplyr)
library(tidyr)
library(ggplot2)
data %>%
pivot_longer(cols = -id) %>%
mutate(name = name,
value = str_wrap(value, 20)) %>%
count(name, value) %>%
ggplot(aes(x = reorder(value, n), y = n, fill = name)) +
geom_bar(show.legend = FALSE, stat = 'identity') +
facet_wrap(.~name, scales = 'free_y') +
coord_flip() +
labs(y = "Students", x = "") +
theme(axis.text.y = element_text(size=8))
-output
Or if it is a custom order, then have to create the custom order vector and use that to change the 'value' to a factor with levels specified in that order
data1 <- data %>%
pivot_longer(cols = -id) %>%
mutate(name = name,
value = str_wrap(value, 20))
lvls <- unique(data1$value)[c(3, 10, 1, 5, 9, 4, 8, 7, 6, 2)]
data1 %>%
mutate(value = factor(value, levels = lvls)) %>% # // change here
ggplot() +
geom_bar(aes(value, fill = name), show.legend = FALSE) +
facet_wrap(.~name, scales = 'free_y') +
coord_flip() +
labs(y = "Students", x = "") +
theme(axis.text.y = element_text(size=8))
This code should get the exact picture you want, by reordering the factor after you have pivoted longer
data %>%
pivot_longer(cols = -id) %>%
mutate(name = name,
value = factor(str_wrap(value, 20))) %>%
mutate(value = forcats::fct_relevel(value, "Agree", after = 1)) %>%
mutate(value = forcats::fct_relevel(value, "The assignment\nhelped me solidify\nthe key concepts", after = Inf)) %>%
mutate(value = forcats::fct_relevel(value, "The assignment\nreflected the class\ninstructions", after = Inf)) %>%
mutate(value = forcats::fct_relevel(value, "The assignment\nhighly reflected the\nclass instructions", after = Inf)) %>%
mutate(value = forcats::fct_relevel(value, "The assignment\ngave me a great\nopportunity to apply\nwhat I learned", after = Inf)) %>%
ggplot() +
geom_bar(aes(value, fill = name), show.legend = FALSE) +
facet_wrap(.~name, scales = 'free_y') +
coord_flip() +
labs(y = "Students", x = "") +
theme(axis.text.y = element_text(size=8))
I am learning r and I have problem with sorting the double bar in ascending or descending order and I want to set the legend just on the top of the plot with two color represent respectively with one row and two columns like for example:
The title Time
box color Breakfast box color Dinner
And the plot here
Here is my dataframe:
dat <- data.frame(
time = factor(c("Breakfast","Breakfast","Breakfast","Breakfast","Breakfast","Lunch","Lunch","Lunch","Lunch","Lunch","Lunch","Dinner","Dinner","Dinner","Dinner","Dinner","Dinner","Dinner"), levels=c("Breakfast","Lunch","Dinner")),
class = c("a","a","b","b","c","a","b","b","c","c","c","a","a","b","b","b","c","c"))
And here is my code to make change:
dat %>%
filter(time %in% c("Breakfast", "Dinner")) %>%
droplevels %>%
count(time, class) %>%
group_by(time) %>%
mutate(prop = n/sum(n)) %>%
ggplot(aes(x = class, y = prop, fill = time, label = scales::percent(prop))) +
geom_col(position = 'dodge') +
geom_text(position = position_dodge(width = 0.9), vjust = 0.5, size = 3) +
scale_y_continuous(labels = scales::percent)+
coord_flip()
Any help would be appreciated.
Something like this should be close to what you are asking, feel free to ask more
Resources consulted during the answer: http://www.sthda.com/english/wiki/ggplot2-legend-easy-steps-to-change-the-position-and-the-appearance-of-a-graph-legend-in-r-software
Using part of the answer you can look further into https://ggplot2.tidyverse.org/reference/theme.html
library(tidyverse)
dat <- data.frame(
time = factor(c("Breakfast","Breakfast","Breakfast","Breakfast","Breakfast","Lunch","Lunch","Lunch","Lunch","Lunch","Lunch","Dinner","Dinner","Dinner","Dinner","Dinner","Dinner","Dinner"), levels=c("Breakfast","Lunch","Dinner")),
class = c("a","a","b","b","c","a","b","b","c","c","c","a","a","b","b","b","c","c"))
dat %>%
filter(time %in% c("Breakfast", "Dinner")) %>%
droplevels %>%
count(time, class) %>%
group_by(time) %>%
mutate(prop = n/sum(n)) %>%
ggplot(aes(x = fct_reorder(class,prop), y = prop, fill = time, label = scales::percent(prop))) +
geom_col(position = 'dodge') +
geom_text(position = position_dodge(width = 0.9), vjust = 0.5, size = 3) +
scale_y_continuous(labels = scales::percent)+
coord_flip() +
labs(x = "class",fill = "Time") +
theme(legend.position = "top", legend.direction="vertical", legend.title=element_text(hjust = 0.5,face = "bold",size = 12))
Created on 2020-05-08 by the reprex package (v0.3.0)
To get the legend title above the legend key, requires a little additional adjustments to the theme and guides.
dat %>%
filter(time %in% c("Breakfast", "Dinner")) %>%
droplevels %>%
count(time, class) %>%
group_by(time) %>%
mutate(prop = n/sum(n)) %>%
ggplot(aes(x = class, y = prop, fill = time, label = scales::percent(prop))) +
geom_col(position = 'dodge') +
geom_text(position = position_dodge(width = 0.9), vjust = 0.5, size = 3) +
scale_y_continuous(labels = scales::percent)+
coord_flip() +
theme(legend.position="top", legend.direction="vertical", legend.title=element_text(hjust = 0.5))+
guides(fill = guide_legend(title = "Time", nrow = 1))