Public
Edited
Jan 18, 2024
Insert cell
Insert cell
cohort_histograms@1.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
yearly = d3.groups(histogram_data, (d) => d.cohort)
Insert cell
Insert cell
binMin = {
let retval = 0;

yearly.forEach((item) => {
let data = item[1];
let localMax = d3.min(data, (d) => d.bin_start);
retval = localMax < retval ? localMax : retval;
});

return retval;
}
Insert cell
binMax = {
let retval = 0;

yearly.forEach((item) => {
let data = item[1];
let localMax = d3.max(data, (d) => d.bin_end);
retval = localMax > retval ? localMax : retval;
});

return retval;
}
Insert cell
gap = 30
Insert cell
margin = ({ left: 20, right: 20, top: 70, bottom: 70 })
Insert cell
xHisto = d3
.scaleLinear()
.range([margin.left, width - margin.left])
.domain([-max, max])
Insert cell
curve = d3.curveBundle
Insert cell
yHisto = d3.scaleLinear().domain([0, maxBin]).range([0, -90])
Insert cell
max = 5
Insert cell
width = 800
Insert cell
chart = {
const height = 600;
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);
// .attr("style", "max-width: 100%; height: auto; background: #fff8e7");

const mainGroup = svg.append("g").attr("transform", "translate(0,120)");

const defs = mainGroup.append("defs");

const gradient = defs
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("x2", "100%")
.attr("y1", "0%")
.attr("y2", "0%");

gradient
.append("stop")
.attr("offset", "25%")
.attr("style", "stop-color:blue;stop-opacity:1");

// gradient
// .append("stop")
// .attr("offset", "40%") // Adjusted
// .attr("style", "stop-color:white;stop-opacity:1");

gradient
.append("stop")
.attr("offset", "50%") // Adjusted
.attr("style", "stop-color:white;stop-opacity:1");

gradient
.append("stop")
.attr("offset", "75%")
.attr("style", "stop-color:red;stop-opacity:1");

yearly.forEach((item, index) => {
const year = item[0];
const data = item[1];

const glorified = [];

data.forEach((bin, i) => {
if (i == 0) {
glorified.push({ value: -max, count: 0 });
glorified.push({ value: bin.bin_start, count: 0 });
}

glorified.push({
value: (bin.bin_start + bin.bin_end) / 2,
count: bin.count
});
});

glorified.push({
value: data[data.length - 1].bin_end,
count: 0
});

glorified.push({
value: max,
count: 0
});

const g = mainGroup
.append("g")
.attr("transform", `translate(0,${index * gap})`);

g.append("path")
.attr("fill", "url(#gradient)")
// .attr("fill", "white")
.attr("stroke", "black")
.attr("stroke-opacity", 0.7)
.attr("d", line(glorified));

g.append("text")
.text(year)
.attr("font-size", 11)
.attr("dx", margin.left)
.attr("dy", -4)
.attr("text-anchor", "start");

// console.log(glorified);
});

// svg
// .append("line")
// .attr("x1", xHisto(0))
// .attr("x2", xHisto(0))
// .attr("y1", margin.top)
// .attr("y2", height - margin.bottom)
// .attr("stroke", "white");
// .attr("opacity", 0.2);

const xAxis = d3
.axisBottom(xHisto)
.tickFormat((d) => (d === 0 ? `${d}°C` : `${d3.format("+.0f")(d)}`));

mainGroup
.append("g")
.attr("transform", `translate(0,${yearly.length * gap - gap})`)
.call(xAxis)
.select(".domain")
.remove();

return svg.node();
}
Insert cell
line = d3
.line()
.x((d) => xHisto(d.value))
.y((d) => yHisto(d.count))
.curve(curve)
Insert cell
daily_averages_per_cohort.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
xYear = d3
.scaleLinear()
.domain([0, 365])
.range([margin.left, width - margin.right])
Insert cell
cohortLine = d3
.line()
.x((d) => xYear(d.index))
.y((d) => -d.value * 3)
Insert cell
cohortGap = 30
Insert cell
cohortChart = {
const height = 600;
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);

const mainGroup = svg.append("g").attr("transform", "translate(0,90)");

const defs = mainGroup.append("defs");

const gradient = defs
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("x2", "100%")
.attr("y1", "0%")
.attr("y2", "0%");

gradient
.append("stop")
.attr("offset", "20%")
.attr("style", "stop-color:blue;stop-opacity:1");

// gradient
// .append("stop")
// .attr("offset", "40%") // Adjusted
// .attr("style", "stop-color:white;stop-opacity:1");

gradient
.append("stop")
.attr("offset", "50%") // Adjusted
.attr("style", "stop-color:white;stop-opacity:1");

gradient
.append("stop")
.attr("offset", "80%")
.attr("style", "stop-color:red;stop-opacity:1");

cohorts.forEach((item, index) => {
const year = item.cohort;
const data = days.map((d, i) => {
return {
index: i,
value: item[d]
};
});

console.log(year, data);

const g = mainGroup
.append("g")
.attr("transform", `translate(0,${index * cohortGap})`);

g.append("path")
// .attr("fill", "url(#gradient)")
.attr("fill", "lightgrey")
.attr("stroke", "black")
.attr("d", cohortLine(data));

g.append("text").text(year).attr("font-size", 9);
});

const xAxis = d3.axisBottom(xHisto);

mainGroup
.append("g")
.attr("transform", `translate(0,${yearly.length * 12})`)
.call(xAxis);

return svg.node();
}
Insert cell
days[days.length - 1]
Insert cell
days = d3.range(1, 367, 1)
Insert cell
cohorts[0][1]
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