Rodrigo Sousa Coutinho
Apr 13 · 3 min read

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:

Data Trekking

Adventures and discoveries while navigating the amazing world of data

Rodrigo Sousa Coutinho

Written by

Hi! I’m co-founder and Strategic Product Manager at OutSystems, with a passion for mobile and web development, great products, and geeky stuff!

Data Trekking

Adventures and discoveries while navigating the amazing world of data

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade