Générer ses graphiques Strava avec Clojure et Incanter
J'utilise Strava pour enregistrer mes sessions de jogging : après avoir enregistré une session avec mon smartphone, je la publie pour pouvoir la partager et la revoir plus tard.
Strava fournit quelques tableaux de bord mais je voulais générer mes propres graphiques afin de visualiser ma progression.
Premier essai avec R
J'ai d'abord essayé d'utiliser RStudio, un IDE pour le langage R. Je pense que c'est un outil adapté mais je le connais très peu. Après avoir essayé pendant quelques heures d'importer mes données et de les transformer, j'ai abandonné !
J'essairai une autre fois ! 😅
Deuxième essai avec Clojure et Incanter
J'ai ensuite essayé d'utiliser Incanter, une librairie Clojure inspirée de R :
Clojure-based, R-like platform for statistical computing and graphics.
J'avais besoin de faire 3 choses :
- appeler l'API Strava pour récupérer les données au format JSON
- faire quelques transformations, essentiellement des conversions (m/s en km/h, secondes en minutes)
- afficher des graphiques (exemple : évolution de la vitesse moyenne par sortie en fonction du temps)
Allons-y !
1. Récupérer les données Strava
La fonction suivante appelle l'API Strava "activities" avec un jeton d'autorisation (access token) et récupère les 200 dernières sorties ("activities" = activité de course à pied, vélo ou natation) sous forme d'un tableau d'objets JSON :
(defn strava-activities [token]
(json/read-str (:body
(http-client/get
"https://www.strava.com/api/v3/activities"
{:query-params {:access_token token :per_page 200}}))))
2. Transformer les données
On définit les fonctions suivantes pour transformer les données :
; Convertir les vitesses en km/h (l'API Strava retourne des m/s) :
(def meters-per-second->kilometers-per-hour (partial * 3.6))
; Convertir les durées en minutes (l'API Strava API retourne des secondes) :
(defn- seconds->minutes [s] (/ s 60))
; Incanter peut seulement générer des graphiques à partir de données numériques, les dates au format ISO doivent donc être converties en timestamps :
(defn- string-date->millis [str-date]
(.getTime
(clojure.instant/read-instant-date str-date)))
Ces fonctions peuvent être appliquées aux données brutes, en utilisant par exemple l'opérateur "thread-last" (->>
), bien pratique pour chaîner les appels de fonctions :
(->> (strava-activities token)
(map #(update-in % ["average_speed"] meters-per-second->kilometers-per-hour))
(map #(update-in % ["start_date_local"] string-date->millis))
(map #(update-in % ["elapsed_time"] seconds->minutes))
(map #(update-in % ["moving_time"] seconds->minutes)))
3. Affichage d'un graphique avec Incanter
La dernière étape consiste à utiliser l'une des fonctions de la librairie Incanter pour afficher un graphique. L'exemple de code suivant affiche l'évolution de la vitesse moyenne de chaque sortie en fonction de la date de la sortie :
(defn display-chart [token]
(let [activities (get-activities token)]
(with-data
(to-dataset activities)
#_(view $data)
(view
(time-series-plot
($ :start_date_local)
($ :average_speed)
:group-by ($ :type)
:title "Average speed over time"
:x-label "time"
:y-label "average speed (km/h)"
:points true
:legend true)))))
Le graphique généré :
Le code complet, qui affiche plusieurs graphiques similaires, se trouve sur le repository GitHub strava-activity-graphs.