0

I am trying to graph a weekly schedule. It is similar to what is described here, but I want to show line segments that are like Monday 8pm to Tuesday 4am (indicating day and time).

The goal is to be able to plot multiple peoples' schedules together to see how much overlap there is in each functional group each day.

I haven't tried the below methods, but I believe that I could get where I want by either picking a starting date-time (a Sunday) and offset by days and time (ymd_hms("2023-07-02 00:00:00") + days(1) + hours(20)), then mask the date with axis scaling in ggplot, or I have to convert everything to durations (like the other method, but render the dates as durations) and then set the x-axis values manually.

Is there a way to render an abstract or relative date-time (like Monday, 8pm) or do I have to use one of my above workarounds?

  • This overview of different Gantt charting solutions might be helpful: https://stackoverflow.com/questions/3550341/gantt-charts-with-r#29999300 – I_O Jul 07 '23 at 20:44

1 Answers1

1

I suggest rewriting (augmenting) all of your timestamps to begin on the same "Sunday" (or whichever day) using lubridate::floor_date, and then counting into that week. For instance, some sample data:

set.seed(42)
dat <- data.frame(starttime = as.POSIXct("2000-01-01", tz = "UTC") + 100*86400*runif(10), type = LETTERS[1:10])
dat$endtime <- dat$starttime + 86400*runif(10)
dat$weekstart <- lubridate::floor_date(dat$starttime, "weeks")
dat$start1 <- dat$weekstart[1] + difftime(dat$starttime, dat$weekstart, units = "secs")
dat$end1 <- dat$weekstart[1] + difftime(dat$endtime, dat$weekstart, units = "secs")
head(dat)
#             starttime type             endtime  weekstart              start1                end1
# 1 2000-04-01 11:32:04    A 2000-04-01 22:31:13 2000-03-26 2000-04-01 11:32:04 2000-04-01 22:31:13
# 2 2000-04-03 16:58:51    B 2000-04-04 10:14:22 2000-04-02 2000-03-27 16:58:51 2000-03-28 10:14:22
# 3 2000-01-29 14:44:05    C 2000-01-30 13:10:01 2000-01-23 2000-04-01 14:44:05 2000-04-02 13:10:01
# 4 2000-03-24 01:04:27    D 2000-03-24 07:12:16 2000-03-19 2000-03-31 01:04:27 2000-03-31 07:12:16
# 5 2000-03-05 04:11:21    E 2000-03-05 15:17:03 2000-03-05 2000-03-26 04:11:21 2000-03-26 15:17:03
# 6 2000-02-21 21:49:49    F 2000-02-22 20:23:26 2000-02-20 2000-03-27 21:49:49 2000-03-28 20:23:26

range(dat$starttime)
# [1] "2000-01-14 11:11:59 UTC" "2000-04-03 16:58:51 UTC"
range(dat$start1)
# [1] "2000-03-26 04:11:21 UTC" "2000-04-01 14:44:05 UTC"

We'll be using start1 and end1 for plotting. It doesn't matter if we based them all off of dat$weekstart[1] or min(dat$weekstart), since the reference date is never shown, just the day-of-week.

Plot method:

library(ggplot2)
ggplot(dat, aes(y = type)) +
  geom_segment(aes(x = start1, xend = end1, yend = type)) +
  scale_x_datetime(date_labels = "%a %H:%M")

ggplot2 with weekday-only x-axis

Some notes about this:

  • while floor_date supports starting the week on arbitrary days of the week, unless you care, it doesn't matter: the "seconds of the week" is never shown; but if you really want to control it (perhaps for follow-on filtering?), then look into the week_start= argument.
  • since we're keeping x= (and xend=) as proper POSIXt objects, we can use the native functionality of scale_x_datetime, including its date_breaks= (not shown, but could be something like date_breaks="12 hours" if desired).
r2evans
  • 141,215
  • 6
  • 77
  • 149