Apologies in advance for anything amateurish; this is my first stack post.
I'm trying to create a dodged bar plot in ggplot2, where the bars within each date bin are ordered by count. However, ggplot2 just seems to ignore the levels. I can't tell if it's defaulting to alphabetical ordering or something else.
Here's a reproducible example that demonstrates the issue. Any suggestions on how to order the bars within each date bin by count? Thanks in advance!
library(ggplot2)
library(dplyr)
library(forcats)
set.seed(42)
daily_data <- expand.grid(
date = seq.Date(from = as.Date("2024-01-01"), to = as.Date("2024-01-10"), by = "1 day"),
location = c("West", "East", "North")
) %>%
mutate(count = sample(10:100, size = n(), replace = TRUE))
daily_data <- daily_data %>%
group_by(date) %>%
mutate(location = fct_reorder2(location, date, count)) %>%
ungroup()
p <- ggplot(daily_data, aes(x = factor(date), y = count, fill = location)) +
geom_col(stat = "identity", position = "dodge") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p)
What I've tried so far:
- Manually setting factor levels with
factor()
- Using
fct_reorder()
andfct_reorder2()
in the original mutate call as well as in the fill argument ofaes()
I don't think it's defaulting to alphabetical ordering, but I could be wrong. Any changes I make to the structure or class of location
has no effect on the resulting plot.
This post covers the same topic, but it doesn't look like there was a solution reached, at least not one that I could parse.
Apologies in advance for anything amateurish; this is my first stack post.
I'm trying to create a dodged bar plot in ggplot2, where the bars within each date bin are ordered by count. However, ggplot2 just seems to ignore the levels. I can't tell if it's defaulting to alphabetical ordering or something else.
Here's a reproducible example that demonstrates the issue. Any suggestions on how to order the bars within each date bin by count? Thanks in advance!
library(ggplot2)
library(dplyr)
library(forcats)
set.seed(42)
daily_data <- expand.grid(
date = seq.Date(from = as.Date("2024-01-01"), to = as.Date("2024-01-10"), by = "1 day"),
location = c("West", "East", "North")
) %>%
mutate(count = sample(10:100, size = n(), replace = TRUE))
daily_data <- daily_data %>%
group_by(date) %>%
mutate(location = fct_reorder2(location, date, count)) %>%
ungroup()
p <- ggplot(daily_data, aes(x = factor(date), y = count, fill = location)) +
geom_col(stat = "identity", position = "dodge") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p)
What I've tried so far:
- Manually setting factor levels with
factor()
- Using
fct_reorder()
andfct_reorder2()
in the original mutate call as well as in the fill argument ofaes()
I don't think it's defaulting to alphabetical ordering, but I could be wrong. Any changes I make to the structure or class of location
has no effect on the resulting plot.
This post covers the same topic, but it doesn't look like there was a solution reached, at least not one that I could parse.
Share Improve this question edited yesterday jpsmith 17.4k6 gold badges20 silver badges45 bronze badges asked yesterday Sam SwansonSam Swanson 333 bronze badges New contributor Sam Swanson is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 01 Answer
Reset to default 2Making location a factor will typically just give it one ordering; it looks like in this case it's the order for the first date, and using that order in every other date. To get what you want will probably take something like the approach used in tidytext::reorder_within(), where the data is ordered at a granularity that reflects both the location and the date (and mapped to group
, which will drive the dodging), and then labeled to hide that. https://juliasilge/blog/reorder-within/
daily_data <- daily_data %>%
mutate(location2 = tidytext::reorder_within(location, desc(count), date))
ggplot(daily_data, aes(x = factor(date), y = count, fill = location, group = location2)) +
geom_col(position = "dodge") +
# tidytext::scale_x_reordered() + # Not necessary in this case since we're
# using date for the x axis
theme(axis.text.x = element_text(angle = 45, hjust = 1))