Public
Edited
Feb 20
Insert cell
Insert cell
California Wildfire Damage.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
California_County_Boundaries.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
California_County_FIPS_GEOID@1.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
usData = await d3.json('https://cdn.jsdelivr.net/npm/vega-datasets@2.8.0/data/us-10m.json')
Insert cell
caData = topojson.feature(usData, usData.objects.states).features.filter((d) => d.id === 6);
Insert cell
caCountyIDs = california_county_fips_geoid.map(c => c.GEOID_TIGER)
Insert cell
countiesData = topojson.feature(usData, usData.objects.counties).features.filter(d => caCountyIDs.indexOf(d.id) >= 0)
Insert cell
width = 500
Insert cell
height = 500
Insert cell
projection = d3.geoIdentity().reflectY(true).fitSize([width, height], caData[0]);
Insert cell
path = d3.geoPath(projection);
Insert cell
countyFipsMap = new Map(california_county_fips_geoid.map(d => [d["County Name"], d.GEOID_TIGER]));
Insert cell
californiaWildfireDamage.forEach(d => {
d.GEOID_TIGER = countyFipsMap.get(d["Location"]) || "Unknown"; // assign geoid to each county for usdata
});
Insert cell
californiaWildfireDamage
Insert cell
import { Scrubber } from "@mbostock/scrubber";
Insert cell
wildfireMap = new Map(californiaWildfireDamage
.filter(d => d.GEOID_TIGER !== "Unknown")
.map(d => [d.GEOID_TIGER, +d["Area_Burned (Acres)"] || 0]));
Insert cell
function updateWildfireMap(year, metric) {
const filteredData = californiaWildfireDamage.filter(d => new Date(d.Date).getFullYear() === year);
return new Map(filteredData.map(d => [d.GEOID_TIGER, +d[metric] || 0]));
};

Insert cell
colorScales = ({
"Area_Burned (Acres)": d3.scaleSequential(d3.interpolateReds),
"Homes_Destroyed": d3.scaleSequential(d3.interpolateGreys),
"Businesses_Destroyed": d3.scaleSequential(d3.interpolateYlOrBr),
"Vehicles_Damaged": d3.scaleSequential(d3.interpolateBlues),
"Injuries": d3.scaleSequential(d3.interpolatePurples),
"Fatalities": d3.scaleSequential(d3.interpolateGreys), // Almost black
"Estimated_Financial_Loss (Million $)": d3.scaleSequential(d3.interpolateGreens),
})

Insert cell
years = Array.from(new Set(californiaWildfireDamage.map(d => new Date(d.Date).getFullYear()))).sort();
Insert cell
viewof yearFilter = Scrubber(years, { autoplay: false, delay: 1200, loop: false });
Insert cell
viewof metricSelection = html`<select>
<option value="Area_Burned (Acres)">Acres Burned</option>
<option value="Homes_Destroyed">Homes Destroyed</option>
<option value="Businesses_Destroyed">Businesses Destroyed</option>
<option value="Vehicles_Damaged">Vehicles Damaged</option>
<option value="Injuries">Injuries</option>
<option value="Fatalities">Fatalities</option>
<option value="Estimated_Financial_Loss (Million $)">Financial Loss</option>
</select>`

Insert cell
selection = Generators.input(viewof metricSelection);
Insert cell
{
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height]);

const counties = svg
.selectAll(".county")
.data(countiesData)
.join("path")
.attr("class", "county")
.attr("d", path)
.style("fill", d => {
const scale = colorScales[selection];
return scale ? scale(wildfireMap.get(d.id) || 0) : "#ccc"; // default to grey if undefined
})
.style("stroke", "#000")
.style("cursor", "pointer")
.on("mouseover", function () {
d3.select(this).style("stroke", "#fff").style("stroke-width", 2);
})
.on("mouseout", function () {
d3.select(this).style("stroke", "#000").style("stroke-width", 1);
})
.on("click", function (event, d) {
const wildfireMap = updateWildfireMap(yearFilter, selection);

const countyData = california_county_fips_geoid.find(c => c.GEOID_TIGER == d.id);
const countyName = countyData ? countyData["County Name"] : "Unknown";

const metricValue = wildfireMap.get(d.id) || 0;

console.log(`Clicked on: ${countyName}, ${selection}: ${metricValue}`);

d3.select("#tooltip")
.style("visibility", "visible")
.style("left", event.pageX + "px")
.style("top", event.pageY - 40 + "px")
.html(`<strong>${countyName}</strong><br>${selection}: ${metricValue}`);
});

function updateMap(year, metric) {
const wildfireMap = updateWildfireMap(year, metric);
const scale = colorScales[metric];
if (!scale) {
console.error(`No color scale found for metric: ${metric}`);
return;
}
scale.domain([0, d3.max(californiaWildfireDamage, d => +d[metric] || 0)]);
counties.style("fill", d => scale(wildfireMap.get(d.id) || 0));
}

updateMap(yearFilter, selection);

viewof metricSelection.oninput = () => updateMap(yearFilter, selection);
viewof yearFilter.oninput = () => updateMap(yearFilter, selection);

return svg.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