D3 liquid fill gauge for maps

I teach a data visualization course, and recently one of my students has come to me with the idea of “half-filling map areas”. I was like that’s a great idea, go find an example on the internet, I’m sure there is plenty. Well, as it turns out, there isn’t plenty, so I’ve decided to do my own.

The starting point is the famous D3 liquid fill gauge visualization by Curtis Bratton. This visual has since been integrated in all the major BI platforms and developed kind of like a “cult” following in the dataviz community.

So the task is to recreate the above, but for maps. Well, maps are just a bunch of custom shapes, so first we need to start with recreating the visual for a custom shape. I did that here. We start with the 1.1 version of the gauge.

What we needed to do here is to change loadLiquidFillGauge function. So we create a custom shape function (on top of the default circle, rect and polygon). Then, when we create the clip path, we use this custom shape instead of the default circle.

function liquidFillGaugeDefaultShape(g, radius, fillCircleRadius, color) {
    g.append("polygon")
        .attr("points", parseFloat(radius - fillCircleRadius) + ',' + 
            parseFloat(radius - fillCircleRadius) + ' ' +
            parseFloat(radius) + ',' + 
            parseFloat(radius + fillCircleRadius) + ' ' +
            parseFloat(radius + fillCircleRadius) + ',' + 
            parseFloat(radius + fillCircleRadius))
        .style("fill", color)
}

(...)

var fillCircleGroup = gaugeGroup
    .append("g")
    .attr("clip-path", "url(#clipWave" + elementId + ")")
liquidFillGaugeDefaultShape(fillCircleGroup,
    radius, fillCircleRadius, config.waveColor)

However, in order to convert this toy-visualization to a real map, we need to do some modifications regarding the clip shape. This is the desired end result.

Here we extend the loadLiquidFillGauge function with an additional argument, shapeID, which will be used as the path to be clipped, so a typical call will look like loadLiquidFillGauge(elementId, shapeID, value, config). Then, we need to change the clipping method itself. This will be done in a few steps. Currently, the method assumes that the path to be clipped is located at 0, 0. This leads to an incorrect clip path, therefore we need to get the bounding box and the location (center) of our shape. Then, the clipping path itself needs to be moved to the same location using transform translate.

var BBox = d3.select('#' + shapeID).node().getBBox()
var radius = Math.min(parseInt(BBox.width), parseInt(BBox.height)) / 2;
var locationX = parseInt(BBox.width) / 2 - radius + BBox.x;
var locationY = parseInt(BBox.height) / 2 - radius + BBox.y;

(...)

fillCircleGroup.append(function () {
        var shape = d3.select('#' + shapeID);
        shape.attr('transform', 'translate(' +
            (-locationX) + ',' + (-locationY) + ')')
            .style("fill", config.waveColor)
        return shape.node();
    });

And there you have it! I’ve created two demo Observable notebooks as well, where you can play around with the code:


The visualization was created with D3.v3 because this is what I had more experience with and my lack of time to convert the legacy D3 liquid fill gauge to D3.v4 or D3.v5. So that’s a good plan for the near future. Also, there is a caveat that the liquid level inside the shapes will be just the distance between the bounding box‘s min and max y coordinates. So, theoretically, this could be improved by an area proportional representation to reduce distortion for highly asymmetric countries – i.e. the ones that are much narrower at their bottom than at their top such as Brazil or Norway. However, that’s a story for another time 🙂

If you like this stuff follow my GitHub, Twitter and Website. Or if it helps you a lot, consider a small donation on PayPal or in crypto.

🏆 II. székelydata dataviz competition

Over at my Hungarian blog (dubbed székelydata) I am launching the second edition of Transylvania’s first data visualization competition – aimed at young people and fresh university students! You do need to understand quite a bit of Hungarian in order to grasp what’s going on, but hey, I thought it would be nice to let you know. This year’s topic is climate change and it looks quite exciting already!

Rebranding

Hi all, Dénes here!

Today Try something new. Everyday. becomes Kontext. This is to reflect the broadening in scope of the blog to include complex systems analyses as well. I have recently reshaped my online portfolio into 6 distinct channels across all platforms (Facebook, Twitter, YouTube).

Thank you ❤️ for all of your support and encouragement!

Some of my projects/initiatives are incubating/dormant:

Furthermore, the following pages are dying/retiring:

ISS crew by country 🇺🇸🇷🇺🇯🇵🇪🇺🇨🇦

The other day I got into a discussion about the International Space Station (ISS), namely where does its crew come from. I started reading up on it and I figured that it is worth a quick visualization. So I’ve created an interactive one, in echarts. The data comes from here and the code is here.

The ISS has been designed to hold a crew of 7. However, that has happened only rarely, with sometimes the crew size rising up to 9 for a few days, during mission changes. ISS missions are designed to last about half a year, but of course their actual duration will vary on the launch windows and rocket failures. Missions usually overlap a few days with each other, so during crew change periods, the population merely doubles.

Did you know the ISS has been crewed continuously for almost 20 years? In the commissioning phase, Between October 2000 and March 2003, its permanent crew was 3, with American NASA 🇺🇸 astronauts and Russian Roscosmos 🇷🇺 cosmonauts rotating in a 2-1 pattern. Then, after the Columbia disaster, this was reduced to 2, before slowly starting to climb back up from May 2006.

Around this time, astronauts of nationalities other than American 🇺🇸 or Russian 🇷🇺 started to crew the station, from ESA of Europe 🇪🇺, JAXA of Japan 🇯🇵 and CSA of Canada 🇨🇦. The ISS reached its designed capacity of 7 in July 2009.

However, with the end of life for the Space Shuttle, the maximum number of people that can safely evacuate from the station using the Soyuz is 6 – and therefore the permanent crew is limited to that. Interestingly, during a crew change in November 2013, there have been a total of 9 people on the station for 3 days!

Since the stabilization of the permanent crew at 6 starting with 2011, the general pattern has been to allocate these 6 slots to 3 Russian 🇷🇺 cosmonauts, 2 American 🇺🇸 astronauts and one other astronaut: with this remaining space allocated to Japan 🇯🇵 for about half of the missions and a crew member from Europe 🇪🇺 or Canada 🇨🇦 sharing the other half.

However, one can notice an interesting switch-over starting with August 2017, from when American 🇺🇸 astronauts started to take up 3 spaces and Russian 🇷🇺 cosmonauts reduced to 2.

That’s all for today – explore the interactive graph, too!

Formula E ePrix around the world

I’ve fiddled a bit more with the F1 circuits’ geocenter map that I’ve created back in 2014, as one of my first D3.js projects.

Earlier this year, it got another update to include WRC and MotoGP history as well.

Now I’ve included Formula E. As the viewership numbers of F1 are sharply declining, I believe that the electric circus might be the next contender for the crown of motorsport. It has already overtaken F1 in the US.

Interactive dataviz: Formula 1 | MotoGP | WRC | Formula E

Formula E ePrix around the world
Formula E ePrix around the world

 

%d bloggers like this: