Public
Edited
Aug 20, 2022
Insert cell
Insert cell
stateUnemploymentDecade
Insert cell
Insert cell
Insert cell
Insert cell
unemploymentData
Insert cell
Insert cell
stateToDateToRate = new Map(
unemploymentData
// create one [key, value] array for each state
.map(d => ([
d.state,
new d3.InternMap(
// create one [key, value] array for each month
d.rates.map(({date, rate}) => ([date, rate]))
)
]))
// filter out PR since it is not in our map projection
.filter(([state, rates]) => state !== 'Puerto Rico')
)
Insert cell
Insert cell
minRate = d3.min(stateToDateToRate, ([state, rates]) => d3.min(rates.values()))
Insert cell
maxRate = d3.max(stateToDateToRate, ([state, rates]) => d3.max(rates.values()))
Insert cell
Insert cell
color = d3.scaleSequential()
.domain([minRate, maxRate])
.interpolator(d3.interpolateCividis)
Insert cell
Insert cell
dates = unemploymentData[0].rates.map(d => d.date)
Insert cell
date
Insert cell
viewof date = Scrubber(dates, {
autoplay: false,
loop: false,
format: d3.timeFormat('%B %Y')
})
Insert cell
Insert cell
{
const margin = {top: 0, right: 0, bottom: 0, left: 0};
const visWidth = 600 - margin.left - margin.right;
const visHeight = 400 - margin.top - margin.bottom;

const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
// draw map
const projection = d3.geoAlbersUsa()
.fitSize([visWidth, visHeight], usaGeo);

const path = d3.geoPath().projection(projection);

g.selectAll('path')
// Our map projection does not include Puerto Rico
.data(usaGeo.features.filter(d => d.properties.NAME !== 'Puerto Rico'))
.join('path')
.attr('d', path)
.attr('fill', d => color(stateToDateToRate.get(d.properties.NAME).get(date)))
.attr('stroke', 'white')

return svg.node();
}
Insert cell
Insert cell
date2
Insert cell
Insert cell
Insert cell
choropleth = {
const margin = {top: 0, right: 0, bottom: 0, left: 0};
const visWidth = 600 - margin.left - margin.right;
const visHeight = 400 - margin.top - margin.bottom;

const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
// draw map
const projection = d3.geoAlbersUsa()
.fitSize([visWidth, visHeight], usaGeo);

const path = d3.geoPath().projection(projection);

// draw the states
const states = g.selectAll('path')
// Our map projection does not include Puerto Rico
.data(usaGeo.features.filter(d => d.properties.NAME !== 'Puerto Rico'))
.join('path')
.attr('d', path)
.attr('stroke', 'white');

// a function that sets the fill attribute for the states for the given date
function update(date) {
states.attr('fill', d => color(stateToDateToRate.get(d.properties.NAME).get(date)));
}

// add the update function to the svg.node() object
// so that we can call it outside of this cell
svg.node().update = update;

return svg.node();
}
Insert cell
Insert cell
choropleth.update(date2)
Insert cell
Insert cell
Insert cell
Insert cell
radius = d3.scaleSqrt()
.domain([0,maxRate])
.range([0,25])
Insert cell
viewof date3 = Scrubber(dates, {
autoplay: false,
loop: false,
format: d3.timeFormat('%B %Y'),
// delay: 200,
})
Insert cell
Insert cell
symbolMap = {
const margin = {top: 0, right: 0, bottom: 0, left: 0};
const visWidth = 600 - margin.left - margin.right;
const visHeight = 400 - margin.top - margin.bottom;

const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);

const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
// draw map
const projection = d3.geoAlbersUsa()
.fitSize([visWidth, visHeight], usaGeo);

const path = d3.geoPath().projection(projection);

// draw the states
g.selectAll('path')
// Our map projection does not include Puerto Rico
.data(usaGeo.features.filter(d => d.properties.NAME !== 'Puerto Rico'))
.join('path')
.attr('d', path)
.attr('stroke', 'white')
.attr('fill', '#d3d3d3');
// draw the circles
// set the transform attribute to position the cirlces in the center of the states
// set the color of the circles
// we do not have to set the radius yet
const circles = g.selectAll('circle')
.data(usaGeo.features.filter(d => d.properties.NAME !== 'Puerto Rico'))
.join('circle')
.attr('fill','steelblue')
.attr('transform',d =>`translate(${path.centroid(d)})`)
// create the update function that sets the
// r attribute for the circles for the given date
function update(date) {
circles.attr('r',d => radius(stateToDateToRate.get(d.properties.NAME).get(date)))
}

// add the update function to the svg.node() object
// so that we can call it outside of this cell
svg.node().update = update;

return svg.node();
}
Insert cell
Insert cell
symbolMap.update(date3)
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