I have a dataset which runs over many days. For each day, I have multiple hours. In this toy example, I am looking for 3 days and, for each of the three days, I am looking at the data for 13 individual hours (from 6am to 6pm).
I want to capture both the date and the hour in the x-axis. However, rather than repeat the date for each of the 13 individuals hours, I'd like to span the date across those hours, something like tab_spanner
in gt
.
For example, consider this sample code:
library(ggplot2)
exp<-data.frame(
date = c(rep("2025-02-01", 13), rep("2025-02-02", 13),rep("2025-02-03", 13)),
hour = rep(seq(6, 18, 1),3),
obs = runif(13*3, min=1, max=50)
)
exp |>
mutate(
date.hour = factor(paste0(date, " ", hour, " hour"), levels=unique(paste0(date, " ", hour, " hour")), ordered=TRUE)
) |>
ggplot(aes(x=date.hour, y=obs, group=1)) +
geom_line() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
This will generate the following graph:
However, what I am wondering is if it is possible to span the date across the hours, to create a graph that looks something like this:
Using the recently released legendry
package you can achieve your desired result easily using guide_axis_nested
like so, i.e. map the interaction of date
and hour
on x
, set the delimiter to split the variables using key_range_auto
and set the style for each level of axis labels using levels_text=
which expects a list
of element_text
elements.
library(ggplot2)
library(legendry)
exp |>
ggplot(
aes(
x = interaction(hour, date),
y = obs, group = 1
)
) +
geom_line() +
guides(x = guide_axis_nested(
key = key_range_auto(sep = "\\."),
levels_text = list(
element_text(angle = 90, vjust = 0.5, hjust = 1),
element_text(angle = 0, hjust = .5)
)
))