Public
Edited
Apr 16, 2024
Insert cell
Insert cell
Insert cell
{
const data = [
{ dummy_date: new Date("2000-01-01"), ano_pi: 0.5, decade: "2000" },
{ dummy_date: new Date("2000-02-01"), ano_pi: 1.0, decade: "2000" },
{ dummy_date: new Date("2000-03-01"), ano_pi: 1.2, decade: "2000" },
{ dummy_date: new Date("2000-04-01"), ano_pi: 0.8, decade: "2000" },
{ dummy_date: new Date("2000-01-01"), ano_pi: 0.3, decade: "2010" },
{ dummy_date: new Date("2000-02-01"), ano_pi: 0.7, decade: "2010" },
{ dummy_date: new Date("2000-03-01"), ano_pi: 0.9, decade: "2010" },
{ dummy_date: new Date("2000-04-01"), ano_pi: 0.6, decade: "2010" }
];

const margin = { top: 40, right: 40, bottom: 30, left: 25 };
const totalWidth = 960;
const height = 350 - margin.top - margin.bottom;

const svg = d3
.create("svg")
.attr("viewBox", `0 0 ${totalWidth} ${height + margin.top + margin.bottom}`)
.attr("style", "max-width: 100%; height: auto; font: 10px sans-serif;");

const dataByDecade = d3.group(data, (d) => d.decade);

let facetWidth =
(totalWidth - margin.left - margin.right) / dataByDecade.size;

const y = d3
.scaleLinear()
.domain([0, d3.max(data, (d) => d.ano_pi)])
.range([height, 0]);

const x = d3
.scaleTime()
.domain(d3.extent(data, (d) => d.dummy_date))
.range([0, facetWidth - margin.right]);

const xSuperimposed = d3
.scaleTime()
.domain(d3.extent(data, (d) => d.dummy_date))
.range([0, totalWidth - margin.left - margin.right]);

const lineGenerator = d3
.line()
.x((d) => x(d.dummy_date)) // Initially set to use the 'x' scale
.y((d) => y(d.ano_pi));

let isMerged = false;

function updateFacets() {
facetWidth = isMerged
? totalWidth - margin.left - margin.right
: (totalWidth - margin.left - margin.right) / dataByDecade.size;

const currentXScale = isMerged ? xSuperimposed : x;
lineGenerator.x((d) => currentXScale(d.dummy_date));

svg
.selectAll(".facet")
.transition()
.duration(750)
.attr("transform", (_, i) =>
isMerged
? `translate(${margin.left}, ${margin.top})`
: `translate(${margin.left + i * facetWidth}, ${margin.top})`
);

svg
.selectAll(".x-axis")
.transition()
.duration(750)
.call(
d3
.axisBottom(currentXScale)
.tickFormat(d3.timeFormat("%b"))
.tickValues([
new Date("2000-01-01"),
new Date("2000-02-01"),
new Date("2000-03-01"),
new Date("2000-04-01")
])
)
.call((g) => g.select(".domain").remove())
.call((g) => g.selectAll(".tick line").attr("stroke", "#777"));

svg
.selectAll(".line")
.transition()
.duration(750)
.attr("d", (d) => lineGenerator(d));

// Debugging console.log statements
console.log("Facet Width:", facetWidth);
console.log("Is Merged:", isMerged);
}

svg.on("click", function () {
isMerged = !isMerged;
updateFacets();
});

dataByDecade.forEach((values, decade, i) => {
const xOffset = margin.left + i * facetWidth;

const facetGroup = svg
.append("g")
.attr("class", "facet")
.attr("transform", `translate(${xOffset}, ${margin.top})`);

facetGroup
.append("text")
.attr("class", "decade-label")
.attr("x", facetWidth / 2) // Center the label
.attr("y", 0 - margin.top / 2) // Adjust y position
.text(decade + "s")
.style("font-size", "16px") // Adjust font size
.attr("text-anchor", "middle");

facetGroup
.append("g")
.attr("class", "x-axis")
.attr("transform", `translate(0, ${height})`)
.call(
d3
.axisBottom(x)
.tickFormat(d3.timeFormat("%b"))
.tickValues([
new Date("2000-01-01"),
new Date("2000-02-01"),
new Date("2000-03-01"),
new Date("2000-04-01")
])
)
.call((g) => g.select(".domain").remove())
.call((g) => g.selectAll(".tick line").attr("stroke", "#777"));

facetGroup
.append("g")
.call(d3.axisLeft(y).tickValues([0, 0.5, 1, 1.5, 2]))
.call((g) => g.select(".domain").remove())
.call((g) => g.selectAll(".tick line").attr("stroke", "#777"))
.call((g) =>
g
.selectAll("line")
.attr("x2", facetWidth - margin.right)
.attr("stroke", "#ddd")
);

facetGroup
.selectAll(".line")
.data([values]) // Bind the data for each decade
.enter()
.append("path")
.attr("class", "line")
.attr("fill", "none")
.attr("stroke", "steelblue") // Adjust stroke color for visibility
.attr("stroke-width", 2) // Adjust stroke width
.attr("d", lineGenerator);
});

updateFacets();
return svg.node();
}
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