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:
factor()
fct_reorder()
and fct_reorder2()
in the original mutate call as well as in the fill argument of aes()
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.
Making 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.com/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))