r = require.alias({
maplibregl: "maplibre-gl@2.1.9/dist/maplibre-gl.js",
h3: {},
deck: "deck.gl@8.9.35/dist.min.js"
});
maplibregl = r("maplibregl").catch(() => window["maplibregl"]);
deck = r("deck");
The transition to RENEWABLE ELECTRICITY is well underway, but there’s still a long way to go
Click to copy this into your story
r = require.alias({
maplibregl: "maplibre-gl@2.1.9/dist/maplibre-gl.js",
h3: {},
deck: "deck.gl@8.9.35/dist.min.js"
});
maplibregl = r("maplibregl").catch(() => window["maplibregl"]);
deck = r("deck");
import { Scrubber } from "@mbostock/scrubber";
viewof selectedYear = Scrubber(
Array.from(Array(22).keys(), n => n + 2000), // 2000 to 2021
{
autoplay: true,
delay: 100,
loop: true,
loopDelay: 500,
initial: 2000
}
);
viewof selectedMeasure = Inputs.radio(
new Map([
["Installed electricity capacity (MW)", "cap_mw"],
["Electricity generated this year (GWh)", "gen_gwh"],
]),
{
value: "cap_mw",
// label: "Measure"
}
)
electricityBubbles = new deck.MapboxLayer({
id: "electricityBubbles",
type: deck.ScatterplotLayer,
data: [],
getPosition: d => [Number(d.lon), Number(d.lat)],
stroked: false,
antialiasing: true,
pickable: true,
autoHighlight: true,
highlightColor: [0, 0, 0, 64]
})
/* this is a bit different to regular mapbox/maplibre instantiation
it lets have the map react to other values in the document, like
a button or a timer, without reinstantiating!
(based on https://observablehq.com/@tmcw/using-mapbox-gl-js) */
viewof map = {
let container = html`<div style="position: absolute; left: 0; top: 0; height: 100vh; width: 100%;" />`;
// Give the container dimensions.
yield container;
// Create the \`map\` object with the mapboxgl.Map constructor, referencing
// the container div
let map = new maplibregl.Map({
container,
bounds: [[-175, -80], [175, 85]],
// pitch: 30,
antialias: true,
style: "style.json"
});
// on map load:
// - dispatch its value back to ojs
// - add the deck.gl layer to the map
// - add a prop to the layer that adds/removes a popup from the map
// (we can't do this on initial layer def because the map isn't ready yet)
map.on("load", () => {
container.value = map;
container.dispatchEvent(new CustomEvent("input"));
map.addLayer(electricityBubbles);
// also configure the automatically-create deck instance
electricityBubbles.deck.setProps({ pickingRadius: 10 });
});
}
allData = FileAttachment("/data/irena-totals.csv").csv({ typed: true });
filteredData = allData
.filter(d => d.year == Number(selectedYear))
.filter(d => !isNaN(d["total_" + selectedMeasure]))
.filter(d => !isNaN(d["renewprop_" + selectedMeasure]));
function divergingSolorScale(x) {
const colorScale =
d3.scaleDiverging()
.domain([0, 0.5, 1])
.interpolator(d3.interpolateBrBG)
const obj = d3.color(colorScale(x))
return [obj.r, obj.g, obj.b, 216]
}
// radius scaling is handled by d3 (range is metres, not pixels)
radiusScale = d3.scaleSqrt()
.domain([0, d3.max(allData, d => d["total_" + selectedMeasure])])
.range([10, 2000000])
// popup content also depends on the selected column, so it needs to be
// added here outside the map load in order to stop the map from re-rendering
// when the selected column changes
function updatePopup(info, event) {
if (info && info.object) {
const figureText = selectedMeasure == "cap_mw" ?
` had <strong>
${Math.floor(info.object["total_" + selectedMeasure]).toLocaleString()} MW</strong>
of installed electricity supply as of
${info.object.year}` :
` generated
<strong>${Math.floor(info.object["total_" + selectedMeasure]).toLocaleString()}
GWh</strong> of electricity in ${info.object.year}`;
popup
.setLngLat(info.coordinate)
.setHTML(
`<span class="title">${info.object.country}</span>
${figureText}. <strong>
${(info.object["renewprop_" + selectedMeasure] * 100).toFixed(1)}%
</strong> of it was from renewable sources.`
)
.addTo(map);
} else {
popup.remove();
}
}
// attach our hover updater to the layer (can't do this until after the
// layer is itself attached)
// electricityBubbles.setProps({ onHover: updatePopup });
// when the data updates, update the data passed to the map and the scale fns
electricityBubbles.setProps({
data: filteredData,
getFillColor: d => divergingSolorScale(d["renewprop_" + selectedMeasure]),
getRadius: d => radiusScale(d["total_" + selectedMeasure]),
onHover: updatePopup
});
noDataNotice = filteredData.length < 1 ?
html`Data for this measure isn't available for ${selectedYear} yet.` :
html``
width = 25
bins = 10
legend =
svg`<svg>
<text fill="white" y=15 text-anchor="start" x=0>No renewables</text>
<text fill="white" y=15 text-anchor="end" x=${width * bins}>
Fully renewable
</text>
${d3.schemeBrBG[bins].map(
(colour, i) => svg`<rect height=15 y=23 width=${width}
x=${width * i} fill="${colour}"></rect>`
)}
<text fill="white" y=55 text-anchor="start" x=0>0%</text>
<text fill="white" y=55 text-anchor="end" x=${width * bins}>
100%
</text>
</svg>`
micro = require("micromodal@0.4.10")
micro.init({
awaitOpenAnimation: true,
awaitCloseAnimation: true
});
This map, as well as the analyses that underpin them, are available under a Creative Commons Attribution 4.0 licence.
Please acknowledge 360info and our data sources when you use these charts and data.
Copy and the following code and paste it into your story editor using the Embed button:
<iframe allow="fullscreen; clipboard-write self https://360info-electricitytransition.pages.dev/" allowfullscreen="true" src="https://360info-electricitytransition.pages.dev/map" title="Interactive map: electricity transition" style="width:100%; height:500px; border:none; background-color: white;" scrolling="no"></iframe>
This content is subject to 360info’s Terms of Use.
Visit the GitHub repository to:
The bubbles on this map concern a country’s electricity supply and how that electricity is generated.
There are two measures available: the installed capacity, which represents the amount of electrical power a country can theoretically produce at any one time, and the electricity generated, which represents the amount of electricity actually produced that year.
These measure might differ for many reasons: perhaps a source of electricity is only operational for part of the year, for example.
Regardless of the measure used, the bubbles are coloured according to the fraction of electricity (or electrical power) that comes from renewable sources, with green tones representing more renewable electricity and brown tones representing fewer renewables:
It’s also important to note that electricity is just a small part of many countries’ greenhouse gas emissions—this map says nothing about other sources, like manufacturing, heating or the tailpipe emissions from non-electric vehicles.
The renewable electricity sources in this dataset include:
The data underpinning this map comes from the International Renewable Energy Agency, which licenses data from its Arms Industry Database under Creative Commons 4.0 International.
Vector map tiles are provided by MapLibre under the BSD 3-Clause licence.