1

Assume we have a timetable over 2 years. Each year, we want to do something at certain days, and mark these days on the timeline. Similar to a Gant char, but the difference is that periods can have gaps in between. This means for instance there is an activity from 13. to 20. April, and the next one from 1. to 8. May of the same year. In the MWE below I am only using a time period from 1. January 2000 to 28. February 2000, for simplicity:

library(data.table)
library(ggplot2)
x <- seq(as.Date("2000/01/01"),
         as.Date("2000/02/28"), "day")
y <- x
y[c(3,6,8,9,34:43,50:59)] <- NA
x[c(1,2,3,12:33,44:58)] <- NA
timetable <- data.table(Year=c(rep("Year_1",59),rep("Year_2",59)),
date=c(x,y))

How can I create a timetable which illustrates the activities in form of rectangular shapes? Similar to the charts shown here: Gantt charts with R or here: Creating a Multi-Project Timeline Using ggplot2 in R But here it should allow gaps in between.

So in other words, what I am trying to do is to fill out an existing timeline, and leave out days with no activities (blank). How can this be done with ggplot2?

X7248724X
  • 13
  • 2

1 Answers1

0

So here is a possibility; you first find out which of your dates are missing values and then run length encode the missingness:

is_missing <- timetable[, rle(is.na(date)), by = Year]

From this, you can easily calculate the positions of the dates in your table that are not missing:

end <- cumsum(is_missing$lengths)
start <- end - is_missing$lengths + 1

# Take now only the parts that are not missing
end <- end[!is_missing$values]
start <- start[!is_missing$values]

From this, you can build a new dataframe containing the start and end dates of periods:

newdf <- data.frame(
  Year  = timetable$Year[start],
  start = timetable$date[start],
  end   = timetable$date[end]
)
newdf$y <- 1:nrow(newdf) # just a counter for visualisation

Which you could use to plot something like the following:

ggplot(newdf) +
  geom_rect(aes(xmin = start, xmax = end, 
                ymin = 0 + y,
                ymax = 1 + y, fill = Year))

enter image description here

Note that the Year variable doesn't really mean the year, since the dates themselves only span one year (the year 2000), so I've treated it as a categorical variable. Furthermore, the 3rd and 6th entries in newdf are only one day, which appears as a zero-width rectangle in the plot, since it starts and ends at the same point:

> newdf
    Year      start        end y
1 Year_1 2000-01-04 2000-01-11 1
2 Year_1 2000-02-03 2000-02-12 2
3 Year_1 2000-02-28 2000-02-28 3
4 Year_2 2000-01-01 2000-01-02 4
5 Year_2 2000-01-04 2000-01-05 5
6 Year_2 2000-01-07 2000-01-07 6
7 Year_2 2000-01-10 2000-02-02 7
8 Year_2 2000-02-13 2000-02-18 8

You can do xmax = end + 1 or xmin = start - 1 inside the aes() function if you want these 1 day periods to appear.

EDIT: For the Year variable on the y-axis, you can treat them as numeric in geom_rect()

ggplot(newdf) +
  geom_rect(aes(xmin = start, xmax = end, 
                ymin = -0.45 + as.numeric(Year),
                ymax = 0.45 + as.numeric(Year), fill = Year)) +
  scale_y_continuous(breaks = seq_len(nlevels(newdf$Year)),
                     labels = levels(newdf$Year))

enter image description here

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • thanks, that looks very good. The only thing that is missing now is to have the plots per year in a single row. So e.g. for year 1 (red), you are currently using two separate rows for the activities. Would it be possible to plot them on a single row (with the gap remaining in between, as intended)? – X7248724X Oct 17 '19 at 10:07
  • I've edited my answer to plot the `Year` on the y-axis. – teunbrand Oct 17 '19 at 11:15
  • @teunbrand sorry, but using `xmax = end + 1` or `xmin = start - 1` seems incorrect, as it adds 1d to all periods, doesn't it? not jut to the 1d periods? – User878239 Nov 08 '19 at 21:56
  • 1
    Yes, but also: 1 day is an interval of 24h; the way it is now, it is encoded as an empty (0h) interval which is also incorrect, I would argue. – teunbrand Nov 08 '19 at 22:22