Public
Edited
Apr 10, 2022
5 stars
Insert cell
# Daily mean distribution of temperatures for Zagreb
Data: [DHMZ](https://meteo.hr/)
Insert cell
chart = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

svg
.append("defs")
.append("linearGradient")
.attr("id", "line-gradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", width)
.attr("y2", 0)
.selectAll("stop")
.data([
{ offset: "0%", color: "blue" },
{ offset: "50%", color: "white" },
{ offset: "100%", color: "red" }
])
.enter()
.append("stop")
.attr("offset", function (d) {
return d.offset;
})
.attr("stop-color", function (d) {
return d.color;
});

svg.append("g").call(xGrid);

binnedData.forEach((month, index) => {
const g = svg
.append("g")
.attr("transform", `translate(0,${index * curveHeight * 1.1})`);

g.append("path")
.attr("fill", "url('#line-gradient')")
.attr("d", area(month));

g.append("path")
.attr("fill", "none")
.attr("stroke", "black")
.attr("d", line(month));

g.append("text")
// .attr("text-anchor", "end")
.attr("x", x((month[0].x0 + month[0].x1) / 2))
.attr("y", curveHeight + 5)
// .attr("dy", 5)
.attr("alignment-baseline", "hanging")
.attr("font-family", "sans-serif")
.attr("opacity", 0.6)
.attr("font-size", 10)
.text(`${d3.timeFormat("%b %Y")(dataByMonth[index][1][0].date)}`);

g.append("text")
.attr("text-anchor", "end")
.attr("font-family", "sans-serif")
// .attr("dx", -10)
.attr("font-size", 12)
.attr("opacity", 0.75)
.attr("x", x((month[0].x0 + month[0].x1) / 2) - 10)
.attr("y", curveHeight)
.text(`${month[0].x0}°C`);

g.append("text")
// .attr("dx", 10)
.attr("font-size", 12)
.attr("opacity", 0.75)
.attr("font-family", "sans-serif")
.attr(
"x",
x((month[month.length - 1].x1 + month[month.length - 1].x0) / 2) + 10
)
.attr("y", curveHeight)
.text(`${month[month.length - 1].x1}°C`);
});

return svg.node();
}
Insert cell
xGrid = (g) =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(
d3
.axisBottom(x)
.ticks(20)
.tickSize(-height + margin.top + margin.bottom)
)
.call((g) => g.select(".domain").remove())
.call((g) => g.selectAll("text").remove())
.call((g) =>
g.selectAll("line").attr("stroke", "black").attr("opacity", 0.1)
)
Insert cell
line = d3
.line()
.x((d) => x((d.x0 + d.x1) / 2))
.y((d) => y(d.length))
.curve(curve)
Insert cell
area = d3
.area()
.x((d) => x((d.x0 + d.x1) / 2))
.y0((d) => y(d.length))
.y1(y.range()[0])
.curve(curve)
Insert cell
curve = d3.curveCatmullRom
Insert cell
binnedData = dataByMonth.map((d) => {
return bin(d[1]);
})
Insert cell
height = 800
Insert cell
margin = ({ left: 100, right: 50, bottom: 10, top: 10 })
Insert cell
x = d3
.scaleLinear()
.domain([bounds.min, bounds.max])
.range([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear().domain([0, bounds.maxBins]).range([curveHeight, 0])
Insert cell
curveHeight = 60
Insert cell
bounds = {
var maxBins = 0;
var min = null;
var max = null;
binnedData.forEach((month) => {
month.forEach((bin) => {
if (bin.length > maxBins) maxBins = bin.length;
if (min == null || bin.x0 < min) min = bin.x0;
if (max == null || bin.x1 > max) max = bin.x1;
});
});
return {
maxBins: maxBins,
min: min,
max: max
};
}
Insert cell
bin = d3.bin().value((d) => d.temp)
Insert cell
dataByMonth = d3.rollups(
data,
(v) => v,
(d) => d.date.getMonth()
)
Insert cell
data = d3.csvParse(await FileAttachment("gric.csv").text(), (d) => {
return {
date: d3.utcParse("%Y%m%d")(d.date),
temp: ((d.temp - 32) * 5) / 9
};
})
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