Sparkline Sound-Off

This article, part of the writing collection, was published on and last updated on .

It’s JS Naked Day!

I’m participating in JS Naked Day with the hope of helping to promote the rule of least power. This means that your browsing experience on this website during the 50 hours that make up JS Naked Day should be identical to one where you have disabled JavaScript in your browser.

This is an excellent exercise in making sure there is a clear separation of concerns between HTML for markup, CSS for styling, and JavaScript for interactivity. I highly recommend trying it out and participating yourself!

I have been following in the footsteps of Jeremy Keith for a few months now. Dotted around my website, now, are sparklines, representing my activity over time. As an added bonus, a little tune based on the sparkline's values plays when you click on it. With a moderate amount of musical theory under my belt, here's how I accomplished that audio delight.

Added an interactive demo at the bottom!

To suit my needs, I started with Jeremy Keith’s Canvas-Sparkline and made some modifications. I won’t go into detail about how the Canvas API or the Web Audio API, but there are many resources available if you want a background.


I’m using the same CSV to generate the audio as I am the sparkline itself. Each of the values in the array represent how many posts I made per week for the most recent 26 weeks (half a year).

<svg-sparkline values="0,0,0,0,0,0,0,0,4,0,0,4,9,1,4,5,2,4,2,6,4,6,4,6,5,0"></svg-sparkline>

Because this is really just a fun little easter egg as opposed to a perfect 1-to-1 representation of the data, I decided to map the values against a major pentatonic scale which results in music that is a bit more pleasant to listen to, rather than unharmonious noise if I used a chromatic scale. If I was going for a perfect representation of the data, I would stick to a chromatic scale so that the difference between notes matches their difference in numerical value.

I’ve chosen C4, also known as Middle C, for my starting base notes which represent values of 0 in my data.


Let’s pause and review a little background about musical notes and their relationship to the frequency of each note.

As an example, we’ll take A4, also known as the Stuttgart pitch. It’s the first A above middle C and sits at 440Hz. Unfortunately, frequencies for other notes aren’t quite as simple. We cannot increment 440 by a fixed amount for each consecutive note. In fact, each consecutive note’s frequency is exactly the 12th root of 2 times greater than the previous and vice versa.

A graph showing the logarithmic relationship of frequencies in a diatonic scale, displayed as Frequency over Cents
graph showing the logarithmic relationship of frequencies in a diatonic scale

A4 = 440Hz

A♯4 / B♭4 = 440Hz × 12√2 = 466.16Hz

B4 = 466.16Hz × 12√2 = 493.88Hz

Because I want the music produced by the sparklines to be remotely pleasing to listen to, we need a way to reliably map our unitless number inputs to musical notes. As a result, and to make the music theory more familiar to myself, the data should map directly onto the standard chromatic scale that most modern Western music is based on.

Wikipedia has a great chart with a bunch of this sort of data.

We’ll use the following function to calculate the frequency for a given note on a piano, where A4 is the 49th key on a standard piano:

f(n) = (12√2)n-49 × 440Hz
let getFrequencyFromKeys = (key) => {
	return 2 ** ((key - 49) / 12) * 440;
};

So if we want to calculate the frequency of C4 (Middle C), the 40th key on the keyboard:

f(40) = (12√2)40-49 × 440Hz = 261.626Hz

Quintuplets Permalink

Now that we have established a way of translating each unitless value in our sparkline into a pitch, let’s get a bit more musical and start mapping to a Major Pentatonic scale.

Without going into gory detail, which you can read about here (even more reading if you’re interested), this type of scale is nice because between any two notes of the scale there exists harmony. This means that no matter what notes are chosen by the sparkline data, a mostly-pleasant tune will come back.

As opposed to a chromatic scale where notes are a semi-tone apart, a major pentatonic scale follows a pattern of whole-tones and semi-tones, which we’ll implement inside an array, each value representing one semi-tone step:

let keyIntervals = [2, 2, 3, 2, 3];

Given that our base note is C4, the 40th key on a keyboard, the possible keys that we’re working with are as follows:

40, 42, 44, 47, 49, 52, 54, 56, 59, 61, 64, 66, …

With these keys we can calculate their respective frequencies:

261.626, 293.665, 349.228, 391.995, 440.000, 523.251, 587.330, 698.456, 783.991, 880.000, 1046.502, 1174.659, …

In order to quell any feverish posting on my part, as unlikely as that may be, I am limiting the highest value for the sparkline arbitrarily to 12. This prevents clarity from being lost at the bottom end of the visual sparkline and limits the tunes that are generated from varying too wildly or playing notes which are unpleasant or imperceptible.

Put your money where your mouth is Permalink

Here’s an example. First, we need the per-week data:

0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 9, 1, 4, 5, 2, 4, 2, 6, 4, 6, 4, 6, 5, 0

If we work through this array, item by item, using each value as the key to retrieve the correct frequency, we end up with the following keys and frequencies:

40, 40, 40, 40, 40, 40, 40, 40, 49, 40, 40, 49, 61, 42, 49, 52, 45, 49, 45, 54, 49, 54, 49, 54, 52, 40 becomes 261.626, 261.626, 261.626, 261.626, 261.626, 261.626, 261.626, 261.626, 440.000, 261.626, 261.626, 440.000, 880.000, 293.665, 440.000, 523.251, 349.228, 440.000, 349.228, 587.330, 440.000, 587.330, 440.000, 587.330, 523.251, 261.626

We can pump these values into the Web Audio API to create the tones in our browsers, playing each frequency in succession over four seconds:

Interactive Demo Permalink

Check out my new interactive demo at spark-line!

You can also send an anonymous reply (using Quill and Comment Parade).

5 Responses

  1. 2 Bookmarks
  2. 1 Like
  3. 2 Links