Sebagai pelari, salah satu grafik favorit saya di Strava adalah workout analysis yang sangat berguna untuk mengevaluasi latihan kecepatan, seperti interval, tempo, fartlek dan sejenisnya. Grafik ini sebetulnya adalah diagram batang atau bar chart yang menampilkan pace (menit per kilometer) untuk setiap split/lap. Hanya saja, bar chart ini sedikit dimodifikasi sedemikian rupa, lebar dari batang bervariasi sesuai dengan panjang/pendeknya split (berdasarkan waktu atau jarak). Contohnya workout analysis dari salah satu latihan dengan menu:

  • 20 menit warming-up
  • 18x 1 menit pada pace 5k dengan 1 menit recovery
  • 3 menit recovery
  • 10 menit tempo
  • cooling-down

Workout tersebut digambarkan sangat apik oleh Strava:

Strava

Saya tertarik membuat replikasi grafik tersebut menggunakan R dengan memanfaatkan paket populer ggplot2 yang dipadukan dengan plotly agar menjadi interaktif. Karena Strava tidak menyediakan, saya download dataset-nya dari Garmin Connect. Kebetulan saya menggunakan jam Garmin untuk merekam latihan saat itu.

Pada ggplot2, jenis objek geometri (geom) yang cocok untuk menggambarkan chart ini adalah geom_rect yang berguna untuk membuat persegi panjang (rectangle) pada sebuah plot. Jenis geometri ini memerlukan titik koordinat sudut kiri bawah dan sudut kanan atas dari setiap persegi panjang.

Persiapan data

Data split terdiri dari tiga kolom yaitu Laps, Time berformat H:M:S dan Distance dalam km.

split <- read.csv("data/split.csv")
head(split)
##   Laps  Time Distance
## 1    1 20:34     3.42
## 2    2  1:00     0.23
## 3    3  1:00     0.12
## 4    4  1:00     0.24
## 5    5  1:00     0.11
## 6    6  1:00     0.24

Untuk membuat chart, saya membutuhkan beberapa variabel tambahan untuk setiap lap yang diturunkan dari ketiga variabel tersebut, yaitu:

  • Batas bawah dan batas atas dari Distance untuk sumbu X, dan
  • Batas bawah dan batas atas dari Pace atau waktu per km untuk sumbu Y.

Saya akan memanfaatkan dplyr untuk keperluan ini, dibantu oleh lubridate untuk mengelola kolom bertipe waktu.

library(dplyr)
library(lubridate)

split <- split %>%
  arrange(Laps) %>%
  mutate(Cumulative_distance = cumsum(Distance),
         Distance_start = Cumulative_distance - Distance,
         Time_sec = period_to_seconds(ms(Time)),
         Pace_sec = Time_sec/Distance,
         Base_pace_sec = max(Pace_sec) + 30,
         Pace = format(as_datetime(Pace_sec),'%M:%S'))

head(split)
##   Laps  Time Distance Cumulative_distance Distance_start Time_sec Pace_sec
## 1    1 20:34     3.42                3.42           0.00     1234 360.8187
## 2    2  1:00     0.23                3.65           3.42       60 260.8696
## 3    3  1:00     0.12                3.77           3.65       60 500.0000
## 4    4  1:00     0.24                4.01           3.77       60 250.0000
## 5    5  1:00     0.11                4.12           4.01       60 545.4545
## 6    6  1:00     0.24                4.36           4.12       60 250.0000
##   Base_pace_sec  Pace
## 1      575.4545 06:00
## 2      575.4545 04:20
## 3      575.4545 08:20
## 4      575.4545 04:10
## 5      575.4545 09:05
## 6      575.4545 04:10

Saya sengaja menjadikan kolom waktu (Time dan Pace) dalam detik/second. Konversi detik menjadi waktu akan dikerjakan dalam ggplot2. Saya rasa ini lebih mudah. Atau ada pendapat lain?

Buat chart dengan ggplot2

Dengan ggplot2, membuat chart ala Strava relatif simpel. Setelah inisiasi layer ggplot, cukup input kolom-kolom yang menjadi batas dalam aes pada geom_rect. aes dalam ggplot sebetulnya tidak diperlukan di sini, hanya saja akan berguna untuk menampilkan tooltips nanti.

library(ggplot2)

p <- ggplot(split, aes(label=Laps, label1=Distance, label2=Time, label3=Pace)) +
  geom_rect(
    aes(xmin=Distance_start, xmax=Cumulative_distance,
        ymin=as_datetime(Pace_sec), ymax=as_datetime(Base_pace_sec), 
        fill=Pace_sec), 
    colour="white") +
  scale_y_time(labels = function(t) strftime(t, "%M:%S"))  +
  theme(legend.position='none') +
  xlab("Distance (km)") +
  ylab("Pace (minutes/km)") +
  labs(title = "Running Analysis: 18 x 1 minute 5k pace + 10 minutes tempo") 

p

Nice, sudah terlihat bentuknya.

Hanya saja, axis-Y perlu dibalik (reverse). Sebetulnya dulu saya berhasil membalik koordinat dari axis-Y seperti ini dengan trik dari Stackoverflow. Hanya saja, gglot2 sepertinya tidak mendukung lagi. Jadi kali ini kita manfaatkan fungsi yang ada pada gglotly saja.

Jadikan lebih interaktif dengan plotly

Plotly adalah salah satu library untuk membuat grafik interaktif berbasis JavaScript yang mendukung berbagai bahasa pemrograman seperti R, Python, Julia, MATLAB, dan lain-lain. Dalam R, plotly “kompatibel” dengan ggplot2. Grafik statis yang dibuat dengan ggplot2, dapat dikonversi menjadi grafik plotly yang interaktif hanya dengan menggunakan perintah sederhana.

Kita coba konversikan plot p tadi dengan perintah berikut ini.

library(plotly)

ggplotly(p, tooltip = c("label", "label1", "label2", "label3")) %>%
  layout(yaxis = list(autorange = "reversed"))

Taddaaa !!! Split-chart Strava ala-ala berhasil kita buat.

Perintah ggplotly berfungsi untuk mengkonversi grafik ggplot menjadi plotly. Hampir semua geom_ dapat dikonversi menggunakan fungsi ini. Pada pengaturan layout, kita tambahkan opsi autorange = "reversed" untuk membalik titik koordinat. Sedangkan tooltips berguna untuk menampilkan tooltips atau data yang akan muncul ketika chart kita sorot dengan mouse. Kolom label.? sudah kita siapkan sebelumnya saat membuat ggplot tadi.

Semoga bermanfaat :)