Visualising my daily constitutionals (walks)

The result of my attempt to build a calendar heatmap from scratch with HTML, CSS, and JS. The heatmap visualises my daily walks in 2024.

Calendar heatmaps

It's hard to think of another chart type that can show daily data over a 12-month period in such a small space as well as a calendar heatmap.

Calendar heatmaps allow you to glean: relative values between individual days, busiest days e.g. Mondays, weekends etc. (by looking at the rows), busiest weeks (by looking at the columns), and any trends throughout the year.

Building from scratch

My version below is based on the GitHub commit calendar heatmap. And like the GitHub version, you can hover over each cell to see the relevant data for that day, in my case, the date and distance walked.

My initial version used a linear colour scale (specifically the brightness, referred to as “lightness” in the oklch colour space), the problem I found was that the majority of my walks were ~5 km, but I had a single walk that was 50 km. The result was one very bright cell, with the rest all pretty much the same dull shade of green.

I then decided to use a logarithmic scale for brightness, and this worked much better. The logarithmic scale allowed the short (5–10 km) walks to remain visible, and the differences between them to be discernible.

The issue now was that the long walks were too similar to each other in brightness e.g. my 50 km walk looked almost the same brightness as my 20 km walk. So, I decided to bring in a second parameter i.e. a drop-shadow. The spread of the drop-shadow increases (linearly) with the distance walked, specifically, each 10 km walked adds 1 pixel of spread to the shadow. The result is an “overspill” effect, reminiscent of an old CRT display.

As an aside, I noticed that the overspill was appearing behind adjacent cells, so I set the z-index of each cell to be equal to the distance walked, so brighter cells are always on a layer above less bright cells.

Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Mon Tue Wed Thu Fri Sat Sun

Conclusions

I really like the way this one has turned out—especially the overspill effect. But, I'm far less happy with the code itself. I was about 90% of the way through building it—struggling to align the day and month labels—when I realised that I should have simply used a HTML table, rather than CSS Grid & Flex.

You can see the code over at CodePen.

Further reading

Update (24th Dec): After posting the article above, a friend of mine pointed out a calendar heatmap used by the Smashrun website (a running analytics site).

They have a great blog post that describes the thinking behind their implementation of a calendar heatmap. No “overspilling cells” in their solution, they use various coloured symbols to handle the outlying values.