How can I plot presence/absence data on a time series?

I have some schedule data in the following format

groupA     10  16
groupA     10  16
groupA     12  18
groupA     12  14
groupB     16  20
groupB     16  22
groupB     18  24
groupC     00  10
groupC     04  12
groupC     08  16


I want to create a plot with three lines on the Y axis, and a range from 0 to 24 on the X axis. At a minimum I want to be able to create a gantt-like chart, with a separate line in the plot for each line above, colour coded by the first column (group identifier), but preferably, I'd like to have it so that there are only three lines in the plot, one for each group, increasing the hue of across the line to represent density - although it just occurred to me that this may be a case wher a violin plot could work.

Any suggestions on how to do this?

• This question is about data visualization. This is on-topic. Please reopen. Jun 25 '20 at 15:15
• Can I re-open it or does it require mdewey or whuber to do it? Jun 25 '20 at 17:20
• It takes either a moderator like whuber, or five regular users with sufficient reputation to vote for reopening. Actually, four, now that I have voted to reopen. I am cautiously optimistic either one will happen in the next few hours. Jun 25 '20 at 17:40
• I have raised the issue on Meta. Jun 25 '20 at 18:17
• I was looking for suggestions on how to think. about visualizing it, but I think that a violin plot produces a pretty easily interpretable figure. Jun 25 '20 at 18:32

As you see, I would not use a violin plot, since the kernel density estimate would completely obscure the discreteness of the counts involved. Instead, I would use a black body radiation palette to indicate counts. See here for the function I am using, as well as some pointers to more information about black body radiation palettes.

First, let's recreate your data in R:

df <- structure(list(group = c("groupA", "groupA", "groupA", "groupA",
"groupB", "groupB", "groupB", "groupC", "groupC", "groupC"),
from = c(10, 10, 12, 12, 16, 16, 18, 0, 4, 8),
to = c(16, 16, 18, 14, 20, 22, 24, 10, 12, 16)),
class = "data.frame", row.names = c(NA, -10L))


Now we create a matrix that contains the counts at each point in time, per group:

tt <- seq(min(df$$from),max(df$$to))
nn <- matrix(nrow=length(tt),ncol=length(unique(df$$group)),dimnames=list(tt,unique(df$$group)))
for ( ii in seq_along(unique(df$$group)) ) { df_sub <- subset(df,group==unique(dfgroup)[ii]) nn[,ii] <- sapply(tt,function(jj)sum(jj>=df_subfrom & jj<=df_sub$$to))
}
nn_max <- max(nn)


Here is the function I mentioned. I use it to create a palette, where white corresponds to zero and black to the maximum nn_max:

blackBodyRadiationColors <- function(x, max_value=1) {
# x should be between 0 (black) and 1 (white)
# if large x come out too bright, constrain the bright end of the palette
#     by setting max_value lower than 1
foo <- colorRamp(c(rgb(0,0,0),rgb(1,0,0),rgb(1,1,0),rgb(1,1,1)))(x*max_value)/255
apply(foo,1,function(bar)rgb(bar[1],bar[2],bar[3]))
}

plot(range(as.matrix(df[,-1])),c(0.5,ncol(nn)+0.5),type="n",xlab="",ylab="",yaxt="n")
for ( ii in seq_along(unique(df$group)) ) { for ( jj in tail(tt,-1) ) lines(c(jj-1,jj),rep(ncol(nn)+1-ii,2),col=colors[nn[jj,ii]+1],lwd=10) } legend("left",lwd=3,col=colors,legend=0:nn_max)  Alternatively (e.g., for paper publication), you could use grayscale:  grayscale <- paste0("gray",round((nn_max:0)*100/nn_max)) plot(range(as.matrix(df[,-1])),c(0.5,ncol(nn)+0.5),type="n",xlab="",ylab="",yaxt="n") axis(2,1:ncol(nn),rev(colnames(nn)),las=2) for ( ii in seq_along(unique(df$group)) ) {