Public
Edited
Jan 23, 2023
28 forks
Importers
76 stars
Topographic MappingBubble mapChoroplethAccess to Family planningMD Counties Total Cases MapTendance de la production des déchets en Union EuropéenneAndy's Walgreens COVID-19 Tracker TrackerElection Maps for Incomplete ResultsA better U.S. house election results map?1983 Mayoral Election, Dot density mapsMastodon 🐘Cheat sheet bertinBertin.js: regular squaresWaterlinesNeumorphism Contour Density MapCartographic DoodlesStars and constellationsPlot: Grid choroplethHello Polygon MorphingMapping with pie charts
U.S. Geographic Data
How big are countries... like really!AttitudeB&W ChoroplethWeb Mercator Tile VisibilityMARTINI: Real-Time RTIN Terrain Mesh"Magnifying-Glass" projectionsTissot's indicatrixAntipodal mapMapping gridded data with a Voronoi diagramA Map of Every BuildingUrbano Monti’s Planisphere (1587)Bivariate choroplethDIY HillshadeMapbox Map MakerWorld tourHillshaderSimplified Earth with curved shapesHexbin mapInner glowNicolosi vs. StereographicData-driven projections: Darwin's worldSatellite ground track visualizerDirection to shoreHello, OpenLayers!U.S. airports VoronoiHello, NYC Geosearch API!Mapbox Fly-ToSpilhaus shoreline mapWalmart’s growthHow well does population density predict U.S. voting outcomes?Drawing maps from geodata with D3 & ObservableHexgrid maps with d3-hexgridTissot's indicatrixWorld airports VoronoiSwiss Elevation Line GraphsVector tilesVersor draggingOrthographicSolar TerminatorStreaming ShapefilesFake GlobesPeirce Quincuncial🍃 LeafletU.S.G.S. World Earthquake MapUsing Mapbox GL JSUsing Google Maps
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Plot.plot({
projection: "albers-usa",
width: exampleWidth,
height: exampleHeight,
marks: [
Plot.frame({stroke: "white", fill: "#111"}),
Plot.geo(nation, {stroke: "#fff", strokeWidth: 0.35})
]
})
Insert cell
us = d3.json("https://unpkg.com/us-atlas@3/counties-10m.json")
Insert cell
nation = topojson.feature(us, us.objects.nation)
Insert cell
Insert cell
Plot.plot({
projection: "albers-usa",
width: exampleWidth,
height: exampleHeight,
marks: [
Plot.frame({ stroke: "white", fill: "#111" }),
Plot.geo(countyShapes, { stroke: "#fff", strokeWidth: 0.35 })
]
})
Insert cell
countyShapes = topojson.feature(us, us.objects.counties)
Insert cell
Insert cell
fipsByName = new Map(
countyShapes.features.map((d) => {
const state = statesByFips.get(d.id.slice(0, 2)).name;
const county = d.properties.name;
const name = county + ", " + usStateCodes.getStateCodeByStateName(state);
return [name, d.id];
})
)
Insert cell
nameByFips = new Map(Array.from(fipsByName, ([name, fips]) => [fips, name]))
Insert cell
Insert cell
countyStates = countyShapes.features.map((d) => {
const state = statesByFips.get(d.id.slice(0, 2)).name;
const stateCode = usStateCodes.getStateCodeByStateName(state);
const county = d.properties.name;
const name = `${county}, ${stateCode}`;
return {fips: d.id, state, stateCode, county, name};
})
Insert cell
countyStates.filter(d => d.stateCode === "MD").sort((a, b) => a.county.localeCompare(b.county))
Insert cell
Insert cell
Plot.plot({
projection: "albers-usa",
width: exampleWidth,
height: exampleHeight,
marks: [
Plot.frame({stroke: "white", fill: "#111"}),
Plot.geo(stateShapes, {stroke: "#fff", strokeWidth: 0.35})
]
})
Insert cell
usStateCodes = import('https://cdn.skypack.dev/us-state-codes@1.1.2?min').then(d => d.default)
Insert cell
stateShapes = topojson.feature(us, us.objects.states)
Insert cell
statesByFips = new Map(Array.from(us.objects.states.geometries, d => [d.id, d.properties]))
Insert cell
// The borders of the states are merged so we can render a single line where they would otherwise overlap
statesMesh = topojson.mesh(us, us.objects.states, (a, b) => a !== b)
Insert cell
Insert cell
Plot.plot({
projection: "albers-usa",
width: exampleWidth,
height: exampleHeight,
marks: [
Plot.frame({stroke: "white", fill: "#111"}),
Plot.dot(usCities, {x: "longitude", y: "latitude", fill: "#fff", r: 1})
]
})
Insert cell
usCities = (await FileAttachment("ne_10m_populated_places.csv").csv())
.filter((d) => d["ADM0NAME"] === "United States of America")
.map((d) => ({
name: d.NAME,
state: d.ADM1NAME,
population: +d.POP_MAX,
latitude: +d.LATITUDE,
longitude: +d.LONGITUDE
}))
Insert cell
Insert cell
usCitiesGeo = ({
type: "FeatureCollection",
features: usCities.map(
({ longitude, latitude, ...properties }) => ({
type: "Feature",
id: properties.name,
properties,
geometry: { type: "Point", coordinates: [longitude, latitude] }
})
)
})
Insert cell
Insert cell
Insert cell
{
const f3 = d3.format(",.3r");
const f1 = d3.format(".1s");
return Plot.plot({
projection: "albers-usa",
width: exampleWidth,
height: exampleHeight,
marks: [
Plot.frame({ fill: "#111" }),
Plot.geo(countyShapes, {
stroke: "none",
strokeWidth: 0.35,
fill: (d) => density(d),
title: (d) => `${d.id}: ${f3(density(d))} hab/km²`
})
],
color: {
scheme: "ylgnbu",
domain: [0.2, 20000],
type: "log",
legend: true,
label: "population density (hab/km²)",
ticks: 4,
tickFormat: (d) => (d < 1 ? "≤1" : f1(d))
}
});
}
Insert cell
populationByCounty = new Map(Array.from(populationData, ({ POP, state, county }) => [`${state}${county}`, +POP]))
Insert cell
Insert cell
function density(d) {
const population = populationByCounty.get(d.id);
const area = d3.geoArea(d) * (510e6 / (4 * Math.PI)); // km²
return population / area;
}
Insert cell
Insert cell
populationData = useCache
? FileAttachment("populationData.csv").csv() // cache of the API call from October 2020

// or load the data from the census API, and tweak its format
: d3.json("https://api.census.gov/data/2018/pep/population?get=POP&for=county:*").then(rows => {
const keys = rows.shift();
return Array.from(rows, row => Object.fromEntries(keys.map((key, i) => [key, row[i]])));
})
Insert cell
Insert cell
Insert cell
Insert cell
demographicsData = ({
2018: new Map(demographicsData2018.map(processDemographics).map(d => [`${d.state}${d.county}`, d])),
2016: new Map(demographicsData2016.map(processDemographics).map(d => [`${d.state}${d.county}`, d])),
2014: new Map(demographicsData2014.map(processDemographics).map(d => [`${d.state}${d.county}`, d])),
})
Insert cell
Insert cell
selectedFields = [
"B01003_001E", // estimated total population
// Sex demographics
// https://api.census.gov/data/2018/acs/acs5/groups/B01001.html
"B01001_002E", // Total Male
// TODO: age breakdowns for male
"B01001_026E", // Total Female
// TODO: age breakdowns for female
// Racial demographics
// https://api.census.gov/data/2018/acs/acs5/groups/B02001.html
"B02001_002E", // White (includes Hispanic or Latino?)
"B02001_003E", // Black or African American
"B02001_004E", // American Indian or Alaskan Native
"B02001_005E", // Asian
"B02001_006E", // Native Hawaiian or Pacific Islander
"B02001_007E", // Some other race
"B02001_008E", // Two or more races
"B02001_009E", // Two or more races (one is some other)
"B02001_010E", // Three or more races
// Hispanic or Latino Origin
// https://api.census.gov/data/2018/acs/acs5/groups/B03003.html
// "B03003_001E", // Total
"B03003_002E", // not Hispanic or Latino
"B03003_003E", // Hispanic or Latino
// GINI index of inequality
// https://api.census.gov/data/2018/acs/acs5/groups/B19083.html
"B19083_001E", // gini index
// Per-capita income in last 12 months (inflation adjusted for that year)
"B19301_001E", // All races
"B19301A_001E", // White
"B19301H_001E", // White (not hispanic)
"B19301I_001E", // Hispanic or Latino
"B19301B_001E", // Black or African American
"B19301C_001E", // American Indian or Alaskan Native
"B19301D_001E", // Asian
"B19301E_001E", // Native Hawaiian or Pacific Islander
"B19301F_001E", // Some other race
"B19301G_001E", // Two or more races
]
Insert cell
niceKeys = selectedFields.map(niceLabel)
Insert cell
Insert cell
// Uncomment this cell if you want to query the Census API
// demographicsDataApi = d3.json(`https://api.census.gov/data/2018/acs/acs5?get=NAME,${selectedFields.join(",")}&for=county`)
Insert cell
demographicsData2018 = FileAttachment("demographicsData2018.csv").csv({typed: true})
Insert cell
demographicsData2016 = FileAttachment("demographicsDataApi2016.csv").csv({typed: true})
Insert cell
demographicsData2014 = FileAttachment("demographicsDataApi2014.csv").csv({typed: true})
Insert cell
// Uncomment this cell if you want to query the Census API
// demographicsKeys = d3.json("https://api.census.gov/data/2018/acs/acs5/variables.json")
Insert cell
demographicsKeysFile = FileAttachment("demographicsKeys.json").json()
Insert cell
Insert cell
processDemographics = ({ ...d }) => {
d.state = String(d.state).padStart(2, "0");
d.county = String(d.county).padStart(3, "0");
for (const key of selectedFields) if (!d[key] || d[key] < 0) d[key] = -1;
return d;
}
Insert cell
Insert cell
niceLabel = (key) => {
const moe = key.slice(key.length - 1) == "M";
// if its a margin of error field, we don't have it in the lookup so we us the E(stimate) field instead
const d = demographicsKeysFile.variables[moe ? key.replace(/M$/, "E") : key];
const niceLabel = d.label
.split("!!")
.filter((d) => d !== "Estimate" && d !== "Total" && d.indexOf("Per capita") !== 0)
.join(" ");
const niceConcept = `${moe ? "Margin of error: " : ""}${d.concept.toLowerCase()}`;
return niceLabel ? `${niceConcept}: ${niceLabel.toLowerCase()}` : niceConcept;
}
Insert cell
Insert cell
Insert cell
Insert cell
nytDate = "2021-12-31"
Insert cell
nytOnDateByCounty = new Map(Array.from(nytOnDate, d => [d.fips, d]))
Insert cell
import { rawData as nytData } with { nytStartDate as startDate } from "@jashkenas/united-states-coronavirus-daily-cases-map-covid-19"
Insert cell
nytByDay = d3.group(nytData, d => d.date)
Insert cell
nytOnDate = nytByDay.get(nytDate)
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