Public
Edited
Mar 1, 2024
Insert cell
Insert cell
chemicals = (await FileAttachment("Chem Quantity Lost.csv").csv())
.map(loss => {
loss['type'] = 'CHEMICAL';

const givenPeriod = loss['period'];
if ( givenPeriod.includes('-') ) {
loss['period'] = givenPeriod.split(' ')[1];
}

return loss;
})
Insert cell
controlledSubstances = (await FileAttachment("Quantity Lost.csv").csv())
.map(loss => {
loss['type'] = 'CONTROLLED SUBSTANCES';

const givenPeriod = loss['period'];
if ( givenPeriod.includes('-') ) {
loss['period'] = givenPeriod.split(' ')[1];
}
return loss;
})
Insert cell
businessActivities = {
const list = Array.from(new Set(allLost.map(d => d.business_activity)));
list.unshift('ALL ACTIVITIES');
return list;
}
Insert cell
allLost = controlledSubstances.concat(chemicals)
Insert cell
usaGeo = FileAttachment("gz_2010_us_040_00_20m.json").json()
Insert cell
lossByStates = d3.rollup(
filteredData,
(d) => d.length,
(d) => d.state
)
Insert cell
maxLoss = d3.max(
Array.from(
lossByStates,
([state, count]) => ({
state, count
})
),
(d) => d.count
)
Insert cell
color = d3.scaleSequential()
.domain([0, maxLoss])
.interpolator(d3.interpolateReds)
Insert cell
lossByStates
Insert cell
filteredData = {
if ( businessActivity === 'ALL ACTIVITIES') {
return allLost;
} else {
return allLost.filter(d => d.business_activity === businessActivity)
}
}
Insert cell
viewof businessActivity = Select(businessActivities, {label: 'Business Activity', format: d => d})
Insert cell
{
const margin = ({top: 10, bottom: 50, left: 85, right: 10});
const height = 600 - margin.top - margin.bottom;
const width = 800 - margin.left - margin.right;

const projection = d3.geoAlbers()
.fitSize([width, height], usaGeo)
const path = d3.geoPath().projection(projection)
const svg = d3.create('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);

const precincts = g.selectAll('path')
.data(usaGeo.features)
.join('path')
.attr('d', path)
.attr('fill', d => {
const nameToCode = stateToCode[d.properties.NAME];
return color(lossByStates.get(nameToCode))
})
.attr('stroke', 'white')

return svg.node();
}
Insert cell
gz_2010_us_040_00_20m = FileAttachment("gz_2010_us_040_00_20m.json").json()
Insert cell
gz_2010_us_040_00_20m1 = FileAttachment("gz_2010_us_040_00_20m.json").json()
Insert cell
filteredDataByType = {
if ( substanceType === 'BOTH' ) {
return filteredData;
}

return filteredData.filter( d => d.type === substanceType)
}
Insert cell
subFilteredLossByStates = d3.rollup(
filteredDataByType,
(d) => d.length,
(d) => d.state
)
Insert cell
subfilteredMaxLoss = d3.max(
Array.from(
subFilteredLossByStates,
([state, count]) => ({
state, count
})
),
(d) => d.count
)
Insert cell
subfilteredColor = d3.scaleSequential()
.domain([0, subfilteredMaxLoss])
.interpolator(d3.interpolateReds)
Insert cell
viewof substanceType = Select(['CHEMICAL', 'CONTROLLED SUBSTANCES', 'BOTH'], {label: 'Substance Type', format: d => d})
Insert cell
{
const margin = ({top: 10, bottom: 50, left: 85, right: 10});
const height = 600 - margin.top - margin.bottom;
const width = 800 - margin.left - margin.right;

const projection = d3.geoAlbers()
.fitSize([width, height], usaGeo)
const path = d3.geoPath().projection(projection)
const svg = d3.create('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);

const precincts = g.selectAll('path')
.data(usaGeo.features)
.join('path')
.attr('d', path)
.attr('fill', d => {
const nameToCode = stateToCode[d.properties.NAME];
return subfilteredColor(subFilteredLossByStates.get(nameToCode))
})
.attr('stroke', 'white')

return svg.node();
}
Insert cell
dates = [...new Set (allLost.map(d => d.period))]
Insert cell
stateToDateToCount = d3.rollup(allLost, (v) => v.length, (d) => d.state, (d) => {
return d.period;
})
Insert cell
colorByTime = d3.scaleSequential()
.domain([0, 400])
.interpolator(d3.interpolateReds)
Insert cell
viewof date = Scrubber(dates, {
autoplay: false,
loop: false
})
Insert cell
{
const margin = ({top: 10, bottom: 50, left: 85, right: 10});
const height = 600 - margin.top - margin.bottom;
const width = 800 - margin.left - margin.right;

const projection = d3.geoAlbers()
.fitSize([width, height], usaGeo)
const path = d3.geoPath().projection(projection)
const svg = d3.create('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);

const precincts = g.selectAll('path')
.data(usaGeo.features)
.join('path')
.attr('d', path)
.attr('fill', d => {
const nameToCode = stateToCode[d.properties.NAME];
const stateValuesAtDate = stateToDateToCount.get(nameToCode).get(date);
console.log('what is name to code');
console.log(nameToCode);
return colorByTime(stateValuesAtDate)
})
.attr('stroke', 'white')

return svg.node();
}
Insert cell
stateToDateToCount.get('UT').get(date)
Insert cell
// dictionary to convert state name (which is how the geojson labels states) to state abbrevation (which is how the input data labels states)
stateToCode = {
return {
"Arizona": "AZ",
"Alabama": "AL",
"Alaska": "AK",
"Arkansas": "AR",
"American Samoa": "AS",
"California": "CA",
"Colorado": "CO",
"Connecticut": "CT",
"District of Columbia": "DC",
"Delaware": "DE",
"Florida": "FL",
"Georgia": "GA",
"Hawaii": "HI",
"Idaho": "ID",
"Illinois": "IL",
"Indiana": "IN",
"Iowa": "IA",
"Kansas": "KS",
"Kentucky": "KY",
"Louisiana": "LA",
"Maine": "ME",
"Maryland": "MD",
"Massachusetts": "MA",
"Michigan": "MI",
"Minnesota": "MN",
"Mississippi": "MS",
"Missouri": "MO",
"Montana": "MT",
"Nebraska": "NE",
"Nevada": "NV",
"New Hampshire": "NH",
"New Jersey": "NJ",
"New Mexico": "NM",
"New York": "NY",
"North Carolina": "NC",
"North Dakota": "ND",
"Ohio": "OH",
"Oklahoma": "OK",
"Oregon": "OR",
"Pennsylvania": "PA",
"Rhode Island": "RI",
"South Carolina": "SC",
"South Dakota": "SD",
"Tennessee": "TN",
"Texas": "TX",
"Utah": "UT",
"Vermont": "VT",
"Virginia": "VA",
"Washington": "WA",
"West Virginia": "WV",
"Wisconsin": "WI",
"Wyoming": "WY"
};
}
Insert cell
import {Select} from '@observablehq/inputs'
Insert cell
import {Scrubber} from "@mbostock/scrubber"
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