Separately these seem easy, but I can only complete two of the requirements before breaking the third. What I want to do with a stacked column chart:
Group by week and order the stacked bar chart with the earliest date (Thursday) on the bottom and the last date (Wed) on top.
Custom color each day.
Label the legend with the tp_codes.
Here is the data and an example of a regular bar chart that I would like to "flip" into a stacked bar chart with 3 columns - one for each week - with the bottom most data the first day of the week (Thur).
# DATA -----------------------------------------------------------------------------------------------------------------
session_df <- structure(list(date = structure(c(19570, 19571, 19572, 19573,
19574, 19575, 19576, 19577, 19578, 19579, 19580, 19581, 19582,
19583), class = "Date"), metric = c(2, 8, 12, 18, 6, 12, 20,
2, 6, 9, 7, 19, 4, 17), tp_code = c("Off", "ReEntry", "Strength",
"Match 1", "Recovery", "Activation", "Match 2", "Off", "Strength",
"Speed", "Activation", "Match 1", "ReEntry-Activation", "Match 2"
), week = structure(c(19566, 19566, 19566, 19573, 19573, 19573,
19573, 19573, 19573, 19573, 19580, 19580, 19580, 19580), class = "Date"),
tp_color = c("grey", "lightgreen", "blue", "darkgreen", "chartreuse",
"lightyellow", "darkgreen", "grey", "blue", "yellow", "lightyellow",
"darkgreen", "lightgreen", "darkgreen")), row.names = c(NA,
-14L), class = c("tbl_df", "tbl", "data.frame"))
# ALMOST CORRECT PLOT --------------------------------------------------------------------------------------------------
# Pull out custom colors + codes to pass to ggplot scale_color_manual()
# via https://stackoverflow.com/questions/68557812/use-custom-color-and-custom-label-from-dataframe-columns-in-ggplot2
cols <- distinct(session_df, tp_code, tp_color) |> deframe()
session_df |>
ggplot(aes(x = date, y = metric, fill = tp_code)) +
geom_bar(position='stack', stat='identity') +
scale_color_manual(aesthetics = 'fill',
values = cols
)+
facet_wrap(~week)
I've been using this plot to see if I can tease out why things aren't displaying in the correct order. For instance, Attempt 2 below colors each day correctly, stacks Week 1 (07-28) in the correct order, but Week 2 (08-04) and Week 3 (08-11) are stacked in reverse order. Comments in code hopefully give enough evidence of what is wrong with each chart.
# PRE-PLOT -------------------------------------------------------------------------------------------------------------
cols <- distinct(session_df, date, tp_color) |> deframe()
labs <- distinct(session_df, date, tp_code) |> deframe() # not necessary here but may come in handy to change label name
# ATTEMPT 1 ------------------------------------------------------------------------------------------------------------
# Dates are stacked in the correct order but colors do not match
# Attempting to reverse the colors does not seem to work. Note: colors are reversed for entire df, but not for each week
# Legend needs to have tp_code, not factor(date)
session_df |>
ggplot(aes(x = week, y = metric, fill = factor(rev(date)))) +
geom_bar(position='stack', stat='identity') +
scale_color_manual(aesthetics = 'fill',
values = cols # this doesn't work
# values = rev(cols) # this doesn't work either
) +
theme_minimal()
# ATTEMPT 2 ------------------------------------------------------------------------------------------------------------
# Only change was the remove rev() from `factor(rev(date))` above
# This correctly colors the dates, but days are stacked in the rev order in all three weeks
# (Thur is on top, should be on bottom)
# Attempting to rev `cols` does not change the color
# Legend needs to have tp_code, not factor(date)
session_df |>
ggplot(aes(x = week, y = metric, fill = factor(date))) + #
geom_bar(position='stack', stat='identity') +
scale_color_manual(aesthetics = 'fill',
values = cols # this doesn't work
) +
theme_minimal()
# ATTEMPT 3 ------------------------------------------------------------------------------------------------------------
# Instead of `fill = date` changed to `fill = tp_code`
# Colors attached to `tp_code` here. Above examples colors were attached to date
cols <- distinct(session_df, tp_code, tp_color) |> deframe()
# This displays the legend correctly with tp_code
# This is colored correctly
# The stack order is incorrect for the second and third week only, which are randomly stacked...
session_df |>
mutate(tp_code = factor(tp_code, levels = rev(unique(tp_code)))) |>
ggplot(aes(x = week, y = metric, fill = tp_code)) +
geom_bar(position='stack', stat='identity') +
scale_color_manual(aesthetics = 'fill',
values = cols
)+
theme_minimal()
I am guessing my lack of understanding of the underlying structure of the stacks and the parameters needed to be passed into scale_color_manual
are to be blamed.
To achieve your desired result map tp_code
on the fill
aes but map date
on the group
aes to order or stack your bars by date
. Finally use position = position_stack(reverse = TRUE)
to reverse the order of the stack if desired.
Note: I added a geom_label
layer to check that the dates are in the desired order.
library(ggplot2)
library(dplyr)
library(tibble)
cols <- distinct(session_df, tp_code, tp_color) |> deframe()
session_df |>
ggplot(aes(x = week, y = metric, fill = tp_code, group = date)) +
geom_col(position = position_stack(reverse = TRUE)) +
geom_label(aes(label = date),
position = position_stack(reverse = TRUE),
size = 8 / .pt, fill = "white"
) +
scale_fill_manual(
values = cols
) +
theme_minimal()