Bucharest 1930s 📽 old footage restored using machine learning

This is a follow-up on my recent post on automatic restoration of old video footage using machine learning.

📽 Source videos

Fining source videos for Bucharest project proved to be more challenging than for Budapest, but eventually I settled on a footage from the 1930s, often considered the golden age of the city – a time when it was also dubbed little Paris (this period is also called perioada interbelică – the period between the wars in Romanian)

Continue reading “Bucharest 1930s 📽 old footage restored using machine learning”

Budapest 1896 📽 Automatic restoration of old video footage using machine learning

Recently, several videos have been popping up on the internet that showed really old video footage restored to modern standards. From a contextual perspective, it is a very fascinating process – i.e. using the knowledge of the past 100 years to create a better image of the even more distant past – but it is also an interesting machine learning application. In a nutshell, the process is the following: you show an algorithm a lot if images of how our world currently looks like, a few images about how our world used to look like in the past – and then it tries to recreate the feel of the modern images on the old images (and a video is just a bunch of images chained after another).

Ezt a bejegyzést magyar nyelven is olvashatod.

Perhaps the most prominent videos in this category are the ones made by Denis Shiryaev: Arrival of a Train at La Ciotat from 1896 and A Trip Through New York City from 1911. Denis shares the methodology only conceptually, but of course anyone in the know suspects that there are several steps involved. So, I looked for some old footage of Budapest and I had a nice weekend project lined up… But before I delve in, allow me to take off my 👒 in front of Denis – this was a reaaally long and a reaaally difficult process!

Continue reading “Budapest 1896 📽 Automatic restoration of old video footage using machine learning”

Modelling 🦠 Coronavirus – Quarantine?!

As coronavirus is threatening to become a global pandemic, I’ve built seven epidemiological models of increasing complexity in order to illustrate how infectious diseases get transmitted over time. Among others, I try to answer the questions of what is the scientific rationale behind a surgical mask or an all-out quarantine. This is a video commentary of a simulation modelling exercise using system dynamics – if you like it, maybe I’ll make some others in the future 😃.

Continue reading “Modelling 🦠 Coronavirus – Quarantine?!”

Metrocyclopaedia 🚇 Interactive map of all metro systems of the world

I have been playing around quite a bit with CesiumJS recently. It is likely the best tool out there to visualize global datasets on an interactive 3D Earth in the browser.

As you might know from the title of his blog, 😁 I am fascinated by complex systems. A particular kind of complex systems are infrastructures, and 🇫🇷 metro 🇺🇸 subway 🇬🇧 underground 🇩🇪 U-bahn lines are one of the most mesmerizing pieces of infrastructure – as they give us an insight into how society organizes itself around patterns. But, unlike the road network, the metro system also gives us a sense of population density at a glance – provided that the city planners made the sensible decision to position the stations at the most frequented locations, which apparently does not always happen.

Recently, I have also been experimenting with 3D globes, with various oddball datasets.. For example, I’ve visualized all Antarctic research stations, Global Warming Stripes and more recently Traffic congestion. So my next project was to visualize the metro systems of the world, ideally all of them at once, if possible, on an interactive Earth.

Continue reading “Metrocyclopaedia 🚇 Interactive map of all metro systems of the world”

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.

%d bloggers like this: