Creating Time Maps in R

Rodrigo Sousa Coutinho
Data Trekking
Published in
3 min readApr 13, 2019

Time Maps are a great way to understand events that happen with a certain cadence over time. Take a look at this article by Mark Watson for an excellent explanation on what they are and when they can be useful.

The end result of this article will be to create a Time Map that looks like this:

A Time Map for our event. Complete code at the end of the article.

Sample Data

The type of data I usually want to put in this type of chart comes in the form <TimeStamp> | <Event>. Here’s an example data frame:

library(dplyr)
set.seed(123)
df <- data.frame(helper = c(rnorm(500, 120, 100),
rnorm(500, 1, .8))) %>%
mutate(elapsed = cumsum(helper),
date = as.POSIXct('2019-05-25 10:00:00') + elapsed,
event = 'Ping') %>%
select(date, event)

This will create a data frame with events that happen about 2 minutes apart and then 1 second apart. The data frame looks like this (the event is useless, it’s there just to make the data frame more interesting):

> head(df)
date event
1 2019-05-25 10:01:03 Ping
2 2019-05-25 10:02:40 Ping
3 2019-05-25 10:07:16 Ping
4 2019-05-25 10:09:23 Ping
5 2019-05-25 10:11:36 Ping
6 2019-05-25 10:16:28 Ping

Transforming the data

Next step, we need to have a “time before” and “time after” value for our data frame. Here’s how to do it:

before_after <- df %>%
arrange(date) %>%
mutate(before = as.numeric(date - lag(date)),
after = as.numeric(lead(date) - date)) %>%
filter(!is.na(before) & !is.na(after))

This will create the following data frame:

>  head(before_after)
date event before after
1 2019-05-25 10:02:40 Ping 96.98225 275.870831
2 2019-05-25 10:07:16 Ping 275.87083 127.050839
3 2019-05-25 10:09:23 Ping 127.05084 132.928774
4 2019-05-25 10:11:36 Ping 132.92877 291.506499
5 2019-05-25 10:16:28 Ping 291.50650 159.585497
6 2019-05-25 10:19:07 Ping 159.58550 6.506124

Plotting the data

The simplest plot would be:

library(ggplot2)
ggplot(before_after, aes(x = before, y = after)) +
geom_hex()
If you’re not a fan of hexagons, replace geom_hex by stat_bin2d

But this is not very informative. There’s a very high concentration near (0,0) that we can barely see. Let’s use a logarithmic scale, and also add a bit more color to the chart:

library(RColorBrewer)
ggplot(before_after, aes(x = before, y = after)) +
geom_hex() +
scale_fill_gradientn(colours = rev(brewer.pal(5, "Spectral"))) +
scale_y_continuous(trans = "log10") +
scale_x_continuous(trans = "log10")

Better, but the axis labels aren’t very informative… Using breaks and labels on the axis, the time intervals become much more clear:

axis_labels = list('1/100s' = 0.1, '1 sec' = 1, '1 min' = 60, 
'2 min' = 120, '10 min' = 600)
ggplot(before_after, aes(x = before, y = after)) +
geom_hex() +
scale_fill_gradientn(colours = rev(brewer.pal(5, "Spectral"))) +
scale_y_continuous(trans = "log10", minor_breaks = NULL,
breaks = unlist(axis_labels),
labels = names(axis_labels)) +
scale_x_continuous(trans = "log10", minor_breaks = NULL,
breaks = unlist(axis_labels),
labels = names(axis_labels)) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

Here’s the complete code for the chart:

--

--

Rodrigo Sousa Coutinho
Data Trekking

Hi! I’m co-founder and Director of Data Science at OutSystems, with a passion for data, great products, and geeky stuff!