experiments-d3/inequality/www/linechart.js

87 lines
2.4 KiB
JavaScript
Raw Normal View History

2024-12-17 05:22:42 +00:00
const categories = ["TopPt1", "RemainingTop1", "Next9", "Next40", "Bottom50"];
function drawLineChart(svg, rawData, mode) {
const lineChartLayout = { top: 20, right: 30, bottom: 50, left: 60 };
lineChartLayout.width = 700 - lineChartLayout.left - lineChartLayout.right;
lineChartLayout.height = 400 - lineChartLayout.top - lineChartLayout.bottom;
// make a copy of the data so it can be mutated
let chartData = rawData.map((d) => Object.assign({}, d));
let maxY = 60_000_000;
if (mode === "percent") {
for (let row of chartData) {
let quarterTotal = categories
.map((c) => +row[c])
.reduce((partialSum, a) => partialSum + a, 0);
categories.forEach((c) => (row[c] /= quarterTotal / 100));
maxY = 100;
}
} else {
maxY = 60_000_000;
}
// set up SVG
svg
.selectAll("g.chart-content")
.data([null]) // bind a single (unused) data element to ensure a single <g>
.join("g")
.attr(
"transform",
`translate(${lineChartLayout.left},${lineChartLayout.top})`,
)
.attr("class", "chart-content");
// convert the Date field to DateTime type for d3 scaling
const parseDate = d3.timeParse("%Y:Q%q");
chartData.forEach((d) => (d.DateQ = parseDate(d.Date)));
// Create scales
const xScale = d3
.scaleTime()
.domain(d3.extent(chartData, (d) => d.DateQ))
.range([0, lineChartLayout.width]);
const yScale = d3
.scaleLinear()
.domain([0, maxY])
.nice()
.range([lineChartLayout.height, 0]);
// Axes (use null join trick again to update instead of append)
const xAxis = d3.axisBottom(xScale).ticks(20);
const yAxis = d3.axisLeft(yScale);
svg
.selectAll(".x-axis")
.data([null])
.join("g")
.attr("class", "x-axis")
.attr("transform", `translate(0,${lineChartLayout.height})`)
.call(xAxis);
svg
.selectAll(".y-axis")
.data([null])
.join("g")
.attr("class", "y-axis")
.call(yAxis);
// line path generator from D3, will use x/y range to map data to line
const line = d3
.line()
.x((d) => xScale(d.DateQ))
.y((d) => yScale(d.value));
// create a line per category
svg
.selectAll(".catLine")
.data(categories)
.join("path")
.attr("class", "catLine")
.attr("fill", "none")
.attr("stroke", (d, i) => d3.schemeOranges[5][i])
.attr("stroke-width", 2)
.attr("d", (category) =>
line(chartData.map((d) => ({ DateQ: d.DateQ, value: d[category] }))),
);
}