Published
Edited
Apr 11, 2022
4 forks
69 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = d3.csvParse(await FileAttachment("nyc-weather.csv").text())
Insert cell
Insert cell
xAccessor = d => +d["pressure"]
Insert cell
yAccessor = d => +d["humidity"]
Insert cell
Insert cell
dms = {
let dms = {
width: width,
height: 500,
marginTop: 0,
marginRight: 0,
marginBottom: 50,
marginLeft: 50,
}
dms.boundedWidth = dms.width - dms.marginLeft - dms.marginRight
dms.boundedHeight = dms.height - dms.marginTop - dms.marginBottom
return dms
}
Insert cell
wrapper = d3.create("div")
Insert cell
svg = wrapper.html("").append("svg")
.attr("viewBox", [0, 0, dms.width, dms.height])
.style("overflow", "visible")
Insert cell
bounds = svg.append("g")
.attr("transform", move(dms.marginLeft, dms.marginTop))
Insert cell
Insert cell
Insert cell
xScale = d3.scaleLinear()
.domain(d3.extent(data, xAccessor))
.range([0, dms.boundedWidth])
Insert cell
yScale = d3.scaleLinear()
.domain(d3.extent(data, yAccessor))
.range([dms.boundedHeight, 0])
Insert cell
x = d => xScale(xAccessor(d))
Insert cell
y = d => yScale(yAccessor(d))
Insert cell
Insert cell
xAxis = d3.axisBottom(xScale)
Insert cell
yAxis = d3.axisLeft(yScale)
Insert cell
drawAxes = {
bounds.append("g")
.attr("transform", move(0, dms.boundedHeight))
.call(xAxis)
bounds.append("g")
.call(yAxis)
}
Insert cell
Insert cell
addData = bounds.selectAll("circle")
.data(data)
.join("circle")
.attr("cx", x)
.attr("cy", y)
.attr("r", radius)
.attr("fill", "cornflowerblue")
Insert cell
Insert cell
chart = wrapper.node()
Insert cell
Insert cell
viewof radius = slider({min: 1, max: 10, value: 5})
Insert cell
Insert cell
delaunay = d3.Delaunay.from(data.map(d => ([
x(d),
y(d),
])))
Insert cell
createInteractions = {
const tooltipWidth = 100
const tooltip = wrapper.append("div")
.style("position", "absolute")
.style("padding", "10px 15px")
.style("background", "white")
.style("left", "0")
.style("top", "0")
.style("width", tooltipWidth + "px")
.style("box-sizing", "border-box")
.style("border", "1px solid")
.style("font-family", "sans-serif")
.style("font-size", "12px")
.style("transition", "transform 0.1s ease-out")
.style("pointer-events", "none")
.style("opacity", 0)
bounds.append("rect")
.attr("width", dms.boundedWidth)
.attr("height", dms.boundedHeight)
.style("fill", "transparent")
.on("mousemove", function(e) {
const [mouseX, mouseY] = d3.mouse(this)
const index = delaunay.find(mouseX, mouseY)
const point = data[index]
let parsedX = x(point) + dms.marginLeft
if (parsedX > dms.width - tooltipWidth - 10) parsedX -= tooltipWidth
let parsedY = y(point) + dms.marginTop
tooltip.style("opacity", 1)
tooltip.style("transform", `translate(${parsedX}px, calc(${parsedY > dms.height - 200 ? -100 : 0}% + ${parsedY}px))`)

tooltip.html([
`<div><strong>${point["date"]}</strong></div>`,
`<div><strong>x</strong>: ${ xAccessor(point) }</div>`,
`<div><strong>y</strong>: ${ yAccessor(point) }</div>`,
].join(" "))
})
.on("mouseleave", metric => {
tooltip.style("opacity", 0)
})
}
Insert cell
Insert cell
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