Public
Edited
Nov 14, 2023
Insert cell
Insert cell
data = FileAttachment("weather-data.json").json()
Insert cell
chart = {
const canvasDimensions = {
width: 928,
height: 500,
marginTop: 10,
marginRight: 10,
marginBottom: 40,
marginLeft: 40
};

function drawCanvas() {
const { width, height } = canvasDimensions;

return d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height]);
}

// dew point - horizontal / axisBottom
const horizontalAxis = {
getScale(data) {
const { marginLeft, marginRight, width } = canvasDimensions;

const xDomain = d3.extent(data, (d) => d.dewPoint);
const xRange = [marginLeft, width - marginRight];
const xScale = d3.scaleLinear(xDomain, xRange).nice();

return { xDomain, xRange, xScale };
},
draw({ data, canvas }) {
const { height, width, marginBottom } = canvasDimensions;
const { xScale } = this.getScale(data);

const xAxis = d3.axisBottom(xScale);

canvas
.append("g")
.classed("bottom-axis", true)
.attr("transform", `translate(0,${height - marginBottom})`)
.call(xAxis)
.append("text")
.attr("x", width / 2)
.attr("y", marginBottom - 5)
.attr("fill", "currentColor")
.html("Dew point (°F)");
}
};

// relative humidity — vertical / axisLeft
const verticalAxis = {
getScale(data) {
const { height, marginBottom, marginTop } = canvasDimensions;

const yDomain = d3.extent(data, (d) => d.humidity);
const yRange = [height - marginBottom, marginTop];
const yScale = d3.scaleLinear(yDomain, yRange).nice();

return { yDomain, yRange, yScale };
},
draw({ data, canvas }) {
const { marginLeft, marginRight, height } = canvasDimensions;

const { yScale } = this.getScale(data);
const yAxis = d3.axisLeft(yScale).ticks(4);

canvas
.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(yAxis)
.append("text")
.attr("x", -(height / 2))
.attr("y", -marginLeft + 10)
.style("transform", "rotate(270deg)")
.attr("fill", "currentColor")
.text("Relative Humidity");
}
};

function drawContent({ data, canvas }) {
const { xScale } = horizontalAxis.getScale(data); // dewPoint
const { yScale } = verticalAxis.getScale(data); // humidity

const colorScale = d3
.scaleLinear()
.domain(d3.extent(data, (d) => d.cloudCover))
.range(["#ffa500", "#6e8c56"]);

canvas
.append("g")
.selectAll("circle")
.data(data)
.join("circle")
.attr("cx", (d) => xScale(d.dewPoint))
.attr("cy", (d) => yScale(d.humidity))
.attr("r", 4)
.attr("fill", (d) => colorScale(d.cloudCover));
}

// 1. Draw the canvas
const canvas = drawCanvas();

// 2. Axes
horizontalAxis.draw({ data, canvas });
verticalAxis.draw({ data, canvas });

// 3. Content
drawContent({ data, canvas });

// Always be rendering
return canvas.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