Public
Edited
Jan 30, 2023
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
choropleth = {
// Create the root element into which we'll render the map.
// We yield this early to ensure the div is sized by the time
// Leaflet accesses its offsetWidth and offsetHeight.
//
// This neat trick is courtesy Tom MacWright: https://observablehq.com/@tmcw/leaflet
const root = DOM.element("div", {
style: `width:${width}px; height:${width / 1.6}px`
});

yield root;

// Establish the map's center view and zoom level.
const map = new mapboxgl.Map({
container: root,
style: "mapbox://styles/mapbox/light-v10",
center: [-120.56827, 37.65],
zoom: 7,
projection: {
name: "lambertConformalConic",
center: [-120, 37],
parallels: [37 + 4 / 60, 38 + 26 / 60]
}
});

map.on("load", () => {
map.addSource("acs-2020-ca-sp3-tracts", {
type: "geojson",
data: caSP3Tracts
});

map.addLayer({
id: "acs-2020-ca-sp3-tracts",
type: "fill",
source: "acs-2020-ca-sp3-tracts",
paint: {
"fill-color": [
"let",
"value",
["*", ["/", ["get", "B02001004"], ["get", "B02001001"]], 100],
[
"case",
[">", ["var", "value"], 20],
"#f2f0f7",
[">", ["var", "value"], 10],
"#54278f",
[">", ["var", "value"], 5],
"#756bb1",
[">", ["var", "value"], 1],
"#9e9ac8",
"#cbc9e2"
]
],
"fill-opacity": 0.5
}
});
});

invalidation.then(() => map.remove());
}
Insert cell
Insert cell
Insert cell
caSP3Centroids = {
// Iterate over all polygons. For each, return a new Feature
// with a Point geometry corresponding to its centroid.
const centroids = caSP3Tracts.features.map((tract) =>
turf.feature(turf.centroid(tract).geometry, tract.properties)
);

return {
type: "FeatureCollection",
features: centroids
};
}
Insert cell
Insert cell
proportionalSymbolMap = {
const root = DOM.element("div", {
style: `width:${width}px; height:${width / 1.6}px`
});

yield root;

const map = new mapboxgl.Map({
container: root,
style: "mapbox://styles/mapbox/light-v10",
center: [-120.56827, 37.65],
zoom: 7,
projection: {
name: "lambertConformalConic",
center: [-120, 37],
parallels: [37 + 4 / 60, 38 + 26 / 60]
}
});

map.on("load", () => {
map.addSource("acs-2020-ca-sp3-centroids", {
type: "geojson",
data: caSP3Centroids
});

map.addLayer({
id: "acs-2020-ca-sp3-centroids",
type: "circle",
source: "acs-2020-ca-sp3-centroids",
paint: {
// Ensure we use the square root of the data value. This will ensure differences in
// symbol area accurately reflect differences in the magnitude of the data value.
// Scale all radii by a factor of four to increase visual prominence.
"circle-radius": [
"*",
[
"sqrt",
["*", ["/", ["get", "B02001004"], ["get", "B02001001"]], 100]
],
4
],
"circle-color": [
"let",
"value",
["*", ["/", ["get", "B02001004"], ["get", "B02001001"]], 100],
[
"case",
[">", ["var", "value"], 20],
"#f2f0f7",
[">", ["var", "value"], 10],
"#54278f",
[">", ["var", "value"], 5],
"#756bb1",
[">", ["var", "value"], 1],
"#9e9ac8",
"#cbc9e2"
]
]
}
});
});

invalidation.then(() => map.remove());
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
caSP3Dots = {
return {
type: "FeatureCollection",
features: caSP3Tracts.features.flatMap((tract) => {
// Compute the number of points to render within each Census tract.
const peoplePerPoint = 5;
const datum = tract.properties["B02001004"];
const numPoints = Math.floor(datum / peoplePerPoint);

// Obtain the bounding box of the Census tract.
const bbox = turf.bbox(tract);

// Generate numPoints random points within the Census tract.
const points = turf.randomPoint(numPoints, { bbox });

return points.features.flatMap((point) =>
turf.feature(point.geometry, tract.properties)
);
})
};
}
Insert cell
Insert cell
dotDensity = {
const root = DOM.element("div", {
style: `width:${width}px; height:${width / 1.6}px`
});

yield root;

const map = new mapboxgl.Map({
container: root,
style: "mapbox://styles/mapbox/light-v10",
center: [-120.56827, 37.65],
zoom: 7,
projection: {
name: "lambertConformalConic",
center: [-120, 37],
parallels: [37 + 4 / 60, 38 + 26 / 60]
}
});

map.on("load", () => {
map.addSource("acs-2020-ca-sp3-dots", {
type: "geojson",
data: caSP3Dots
});

map.addLayer({
id: "acs-2020-ca-sp3-dots",
type: "circle",
source: "acs-2020-ca-sp3-dots", // reference the data source
layout: {},
paint: {
"circle-radius": 1.5,
"circle-color": "#54278f",
"circle-opacity": 0.25
}
});
});

invalidation.then(() => map.remove());
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
caSP3HeatDots = {
return {
type: "FeatureCollection",
features: caSP3Tracts.features.flatMap((tract) => {
const datum = tract.properties["B02001004"];

// Obtain the bounding box of the Census tract.
const bbox = turf.bbox(tract);

// Generate as many random points within the Census tract
// as there are AIAN people.
const points = turf.randomPoint(datum, { bbox });

return points.features.flatMap((point) =>
turf.feature(point.geometry, tract.properties)
);
})
};
}
Insert cell
Insert cell
heatmap = {
const root = DOM.element("div", {
style: `width:${width}px; height:${width / 1.6}px`
});

yield root;

const map = new mapboxgl.Map({
container: root,
style: "mapbox://styles/mapbox/light-v10",
center: [-120.56827, 37.65],
zoom: 7,
projection: {
name: "lambertConformalConic",
center: [-120, 37],
parallels: [37 + 4 / 60, 38 + 26 / 60]
}
});

// Compute the max of the data attribute; we'll use this
// as the upper bound for the "heatmap-weight" property.
const max = Math.max(
...caSP3HeatDots.features.map((feature) => feature.properties["B02001004"])
);

map.on("load", () => {
map.addSource("acs-2020-ca-sp3-heatmap", {
type: "geojson",
data: caSP3HeatDots
});

map.addLayer({
id: "acs-2020-ca-sp3-heatmap",
type: "heatmap",
source: "acs-2020-ca-sp3-heatmap",
paint: {
// Increase the heatmap weight based on the data attribute.
"heatmap-weight": [
"interpolate",
["linear"],
["get", "B02001004"],
0,
0,
max,
1
],
"heatmap-color": [
"interpolate",
["linear"],
["heatmap-density"],
0,
"transparent",
0.2,
"#ffffff",
0.4,
"#9e9ac8",
0.6,
"#9e9ac8",
0.8,
"#756bb1",
1,
"#54278F"
],
"heatmap-opacity": 0.9,
"heatmap-radius": ["interpolate", ["linear"], ["zoom"], 0, 4, 15, 5]
}
});

map.addLayer({
id: "acs-2020-ca-sp3-points",
type: "circle",
source: "acs-2020-ca-sp3-heatmap",
minzoom: 11,
paint: {
"circle-color": "#54278F",
"circle-radius": 2,
"circle-opacity": ["interpolate", ["linear"], ["zoom"], 11, 0, 14, 1]
}
});
});

invalidation.then(() => map.remove());
}
Insert cell
Insert cell
Insert cell
Insert cell
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