Public
Edited
May 26, 2023
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
dataRaw = elecProdSourceWorld1
Insert cell
Insert cell
data = removeKeyFromObjects(dataRaw, 'OtherRenewables');
Insert cell
// get column names for IDs of energy types
ids = Object.keys(data[0]).slice(3,)
Insert cell
Insert cell
Insert cell
margin = ({top: 25, right: 20, bottom: 35, left: 50})
Insert cell
marginTrend = ({top: 25, right: 10, bottom: 35, left: 10})
Insert cell
height = 500
Insert cell
Insert cell
Insert cell
Insert cell
// declare x-scales
xScale = d3.scaleBand()
.domain(data.map(d => d.Year))
.range([margin.left, width - margin.right])
.paddingInner(0.2);
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.style("font-family", "IBM Plex Mono")
.style("font-size", "12px")
.call(d3.axisBottom(xScale).tickValues(d3.range(1990, 2021, 5)).tickSizeOuter(0))
Insert cell
function yScaleDoms(data) {
let minLowerBoundaries = []
let maxUpperBoundaries = []

data.forEach(series => {
minLowerBoundaries.push(d3.min(series, d => d[0]));
maxUpperBoundaries.push(d3.max(series, d => d[1]));
});
const minDomain = d3.min(minLowerBoundaries);
const maxDomain = d3.max(maxUpperBoundaries);
return {
'minDomain': minDomain,
'maxDomain': maxDomain
};
};
Insert cell
// domain sizes
minDomain = yScaleDoms(annotatedData).minDomain;
Insert cell
maxDomain = yScaleDoms(annotatedData).maxDomain;
Insert cell
// Declare the vertical scale
yScale = d3.scaleLinear()
.domain([minDomain, maxDomain])
.range([height - margin.bottom, margin.top])
.nice();
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.style("font-family", "IBM Plex Mono")
.style("font-size", "12px")
.call(d3.axisLeft(yScale))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
elec-prod-source-world-trend@2.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
dataTrend = elecProdSourceWorldTrend2
Insert cell
// initialise stack layout - different for the change/trend chart
stackGeneratorTrend = d3.stack()
.keys(formatsInfo.map(f => f.id))
.order(d3.stackOrderInsideOut)
.offset(d3.stackOffsetSilhouette);
//.offset(d3.stackOffsetDiverging);
Insert cell
// first need annotated data for plot using the same generator as before
annotatedDataTrend = stackGeneratorTrend(dataTrend);
Insert cell
// x axis using linear scale
xScaleTrend = d3.scaleLinear()
.domain([d3.min(dataTrend, d => d.Year), d3.max(dataTrend, d => d.Year)])
.range([margin.left, width - margin.right])
Insert cell
xAxisTrend = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.style("font-family", "IBM Plex Mono")
.style("font-size", "12px")
.call(d3.axisBottom(xScaleTrend).tickValues(d3.range(1990, 2021, 5)).tickSizeOuter(0));
Insert cell
// xAxis will be the same - so just need to define yAxis
// domain sizes
minDomainTrend = yScaleDoms(annotatedDataTrend).minDomain;
Insert cell
maxDomainTrend = yScaleDoms(annotatedDataTrend).maxDomain;
Insert cell
// Declare the vertical scale
yScaleTrend = d3.scaleLinear()
.domain([minDomainTrend, maxDomainTrend])
.range([height - margin.bottom, margin.top])
.nice();
Insert cell
yAxisTrend = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(yScaleTrend));
Insert cell
/// area generator for trend/change chart
areaGeneratorTrend = d3.area()
.x(d => xScale(d.data.Year) + xScale.bandwidth()/2)
.y0(d => yScaleTrend(d[0]))
.y1(d => yScaleTrend(d[1]))
.curve(d3.curveCatmullRom);
Insert cell
// predefined selections
areaPaths = d3.selectAll(".areas-container path")
Insert cell
tooltipSelect = d3.select(".tooltip")
Insert cell
tooltipYearSelect = d3.select(".tooltip-year")
Insert cell
// mouse event
highlight = {
const svg = d3.select(chartYoY);
d3.selectAll(".areas-container path")
.on("mousemove", e => {
const xPosition = d3.pointer(e)[0];
d3.select(".tooltip")
.attr("transform", `translate(${xPosition}, 0)`)
.style("stroke-opacity", 100);
// get year for x position to set tooltip text
const year = Math.round(xScaleTrend.invert(xPosition));
d3.select(".tooltip-year").text(year);

// add updated detail to tooltip
const yearData = dataTrend.find(item => item.Year === year);

formatsInfo.forEach(type => {
d3.select(`.type-${type.id}`)
.text(`${type.label}: ${d3.format(".0%")(yearData[type.id])}`);
});
})
}
Insert cell
d3.selectAll(".areas-container path")
Insert cell
xScaleTrend.invert(1)
Insert cell
Insert cell
stackGeneratorTrendBar = d3.stack()
.keys(formatsInfo.map(f => f.id))
Insert cell
annotatedDataTrendBar = stackGeneratorTrendBar(dataTrend);
Insert cell
// chart build
// chartYoYBar = {
// const svg = d3.create("svg")
// .attr("viewBox", [0, 0, width, height]);

// svg.append("g")
// .call(xAxis);

// svg.append("g")
// .call(yAxisTrend);

// annotatedDataTrendBar.forEach(serie => {
// svg.append("g")
// .selectAll(`.bar-${serie.key}`)
// .data(serie)
// .join("rect")
// .attr("class", d => `bar-${d.key}`)
// .attr("x", d => xScale(d.data.Year))
// .attr("y", d => yScaleTrend(d[1]))
// .attr("width", xScale.bandwidth())
// .attr("height", d => yScaleTrend(d[0]) - yScaleTrend(d[1]))
// .attr("fill", colorScale(serie.key));
// })
// //return svg.node();
// }
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require("d3@6", "d3-scale@4")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more