Peloton Data Visualization

I created this Data Visualization p5⁎js sketch after watching Patt Vira’s video tutorial on creating a Habit Tracker - Data Visualization. I really enjoyed watching the video and then creating this visualization with the p5.js library. I downloaded my Peloton workout data from 2024 and then formatted it into a CSV file that contains 3-columns one with the full date as well as two additional columns with the month and date where I completed at least one Peloton workout. The CSV file looks like this:
FullDate,month,date
2024-01-03,1,3
2024-01-06,1,6
According to the above CSV data my first Peloton workouts of 2024 were on January 3rd and January 6.
The visualization shows the dates in a circular pattern with the workouts as circles. The colors of the circles are randomly selected from a color palette. The visualization is a fun way to see the workouts over time. I’ve shared my code below but if you’d like a full walkthrough of how to create this visualization, I highly recommend watching Patt Vira’s video tutorial.
View p5⁎js sketch Source Code
/*
----- Coding Tutorial by Patt Vira -----
Name: Habit Tracker - Data Visualization
Video Tutorial: https://youtu.be/mQ4Cst7o4Ek
Connect with Patt: @pattvira
https://www.pattvira.com/
----------------------------------------
*/
let table;
let dates = [];
let months = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
let runningDates = [];
let b = 3;
let size = 9;
let scl = 1.35;
const colorPalette = [
"#ffadad",
"#ffd6a5",
"#fdffb6",
"#caffbf",
"#9bf6ff",
"#a0c4ff",
"#bdb2ff",
"#ffc6ff",
];
let fontR, fontB;
let border = 15;
function preload() {
table = loadTable("PelotonWorkouts.csv", "csv", "header");
fontR = loadFont("Alef-Regular.ttf");
fontB = loadFont("Alef-Bold.ttf");
}
function setup() {
createCanvas(500, 500);
for (let i = 0; i < months.length; i++) {
for (let j = 0; j < months[i]; j++) {
dates.push({ month: i + 1, date: j + 1 });
}
}
for (let row = 0; row < table.getRowCount(); row++) {
let runningMonth = table.getNum(row, "month");
let runningDate = table.getNum(row, "date");
let didIRun = (element) =>
element.month == runningMonth && element.date == runningDate;
let index = dates.findIndex(didIRun);
if (index != -1) {
runningDates.push(index);
}
}
}
function draw() {
background("#fbf4ff");
strokeWeight(0.5);
fill("#2b2135");
textAlign(CENTER, CENTER);
textSize(size * 2);
textFont(fontR);
text("Monica's Peloton Workouts", width / 2, height / 6);
fill("#bdb2ff");
textSize(size * 6);
textFont(fontB);
text("2024", width / 2, height / 16);
line(0, border, width, border);
line(0, height - border, width, height - border);
line(border, 0, border, height);
line(width - border, 0, width - border, height);
ellipseMode(CENTER);
translate(width / 2, (height + 50) / 2);
noStroke();
for (let i = 0; i < runningDates.length; i++) {
let val = runningDates[i];
let angle = sqrt(val) * b;
let r = b * angle;
let x = r * cos(angle);
let y = r * sin(angle);
fill(random(colorPalette));
if (i > frameCount % 100) {
console.log(frameCount);
ellipse(x, y, size * scl, size * scl);
}
}
textAlign(CENTER, CENTER);
textSize(size);
fill("#2b2135");
for (let i = 0; i < dates.length; i++) {
let angle = sqrt(i) * b;
let r = b * angle;
let x = r * cos(angle);
let y = r * sin(angle);
if (dates[i].date == 1) {
textFont(fontB);
} else {
textFont(fontR);
}
push();
translate(x, y);
if (i != 0) {
rotate(angle + PI / 2);
}
text(dates[i].date, 0, 0);
pop();
}
noLoop();
}
function keyPressed() {
const SPACEBAR = " ";
if (key === "s") {
saveCanvas("workouts");
}
}
