Published
Edited
Nov 1, 2021
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
// TODO: move to county data
const svg = d3.create("svg").attr("width", width).attr("height", height)
const maxTemp = d3.max(data, d=> +d.tavg_anomaly)
const tempScale = d3.scaleLinear()
.domain([-maxTemp, maxTemp])
.range([margin.left, width-margin.right])
const maxPrecip = d3.max(data, d=> +d.pcp_anomaly)
const precipScale = d3.scaleLinear()
.domain([maxPrecip, -maxPrecip]) // this is reversed to put drier on top
.range([height-margin.bottom, margin.top])
const colorScale = d3.scaleSequential(d3.interpolateBuPu)
.domain(d3.extent(data, d=> +d.wnv_incidence_cnt))
const sizeScale = d3.scaleSqrt()
.domain(d3.extent(data, d=> d.wnv_incidence_cnt))
.range(constants.radii)
const xAxis = d3.axisBottom(tempScale);
const yAxis = d3.axisLeft(precipScale);
const dotsContainer = svg.append("g").attr("class","container")
const dotgroups = dotsContainer.selectAll(".dot")
.data(data.sort((a, b)=> d3.ascending(+a.wnv_incidence_cnt, +b.wnv_incidence_cnt)))
.join("g")
.attr("class", d=>`dot ${"code-" + d.fipscode}`)
.attr("transform", d=> `translate(${tempScale(+d.tavg_anomaly)}, ${precipScale(+d.pcp_anomaly)})`)
.on("mouseover",function(d){
d3.select(this).raise();
console.log(d.fipscode)
d3.selectAll(`.dot`).selectAll("circle").attr("opacity", 0.3);
d3.selectAll(`.${"code-" + d.fipscode}`).selectAll("circle").attr("opacity", 1).attr("stroke", "black");
}).on("mouseout", function(){
console.log("mouseout")
d3.selectAll(`.dot`).selectAll("circle").attr("opacity", 0.6).attr("stroke", "unset");
});
dotgroups.append("circle")
.attr("fill", d=> d.wnv_incidence_cnt > threshold? colorScale(d.wnv_incidence_cnt): "lightgrey")
.attr("opacity", 0.6)
.attr("r", d=> sizeScale(d.wnv_incidence_cnt)) // make circle area scale
dotgroups.append("text")
.attr("class", "hover-label")
.text(d=> `${d.county} – ${d.year}`)
.attr("dy", d=> -sizeScale(d.wnv_incidence_cnt))
svg.append("g")
.attr("class", "axis x-axis")
.attr("transform", `translate(0, ${height- margin.bottom})`)
.call(xAxis)
.append("text")
.attr("class", "label")
.text("Avg. Temperature (∆ °C from mean)")
.attr("dy", "3em")
.attr("x", "50%");
svg.append("g")
.attr("class", "axis y-axis")
.attr("transform", `translate(${margin.left},0)`)
.call(yAxis)
.append("text")
.attr("class", "label")
.text("Precipitation (∆ cm from mean)")
.attr("y", "50%")
.attr("dx", "-3em")
.attr("writing-mode","vertical-lr");
// add quadrant lines
const annotationGroup = svg.append("g").attr("class", "annotations")
annotationGroup.append("path")
.attr("stroke","grey")
.attr("transform",`translate(${tempScale(0)},0)`)
.attr("d", `M 0 ${margin.top} L 0 ${height - margin.bottom}`)
annotationGroup.append("path")
.attr("stroke","grey")
.attr("transform",`translate(0,${precipScale(0)})`)
.attr("d", `M ${margin.left} 0 L ${width - margin.right} 0`)
annotationGroup.selectAll("text.xaxis")
.data(["COLDER", "HOTTER"])
.join("text")
.attr("class", "xaxis")
.attr("x", (_,i) => margin.left + 15 + ((width - margin.right - margin.left - 15) * i))
.attr("y", height / 2)
.attr("dy", -20)
.style("text-anchor", (_,i) => i === 0 ? 'start' : 'end' )
.text(d => d)
annotationGroup.selectAll("text.yaxis")
.data(["MORE PRECIPICATION", "LESS PRECIPITATION"])
.join("text")
.attr("class", "yaxis")
.attr("y", (_,i) => margin.top + 15 + ((height - margin.top - margin.bottom - 30) * i))
.attr("x", width / 2)
.attr("dx", -10)
.style("text-anchor", 'end' )
.text(d => d)
.style("transform", "rotate(90)")
// TODO: labels above a certain value
return svg.node()
}
Insert cell
Insert cell
md`# Data, Libraries, and Constants`
Insert cell
Insert cell
Insert cell
Insert cell
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