Public
Edited
May 2, 2024
Fork of Untitled
Insert cell
Insert cell
workbook = FileAttachment("Version_2_MMG2023_2019-2021_Data_ToShare.xlsx").xlsx()
Insert cell
workbook.sheetNames
Insert cell
data = workbook.sheet(0, {
headers: true,
// range: "A1:J10"
})
Insert cell
data
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
mapboxgl = require('mapbox-gl@^1.5.1/dist/mapbox-gl.js');
Insert cell
deck = require.alias({
h3: {},
s2Geometry: {}
})('deck.gl@8.4.1/dist.min.js')
Insert cell
getDeckGLMap = (layers, pitch) => {
if (pitch === undefined) {
pitch = 0;
}

let container = html `<div style="height:700px"></div>`;

let deckgl = new deck.DeckGL({
container,
map: mapboxgl,
mapboxAccessToken: '',
mapboxApiAccessToken: mapboxToken,
mapStyle: 'mapbox://styles/mapbox/dark-v10',
layers: layers,
initialViewState: {
longitude: -95.6914,
latitude: 39.0481,
zoom: 3.5,
minZoom: 4,
maxZoom: 17,
pitch: pitch,
bearing: 0,
},
controller: true
});

return container;
}
Insert cell
getDeckGLMap([
new deck.ScatterplotLayer({
id: 'scatterplot-layer',
data: data,
pickable: true,
opacity: 1,
filled: true,
radiusScale: 1,
radiusMinPixels: 1,
radiusMaxPixels: 1,
getPosition: d => [d.Longitude, d.Latitude],
getRadius: d => 1,
getFillColor: d => [255, 140, 0]
})
])
Insert cell
getDeckGLMap([
new deck.GeoJsonLayer({
id: "food-insecurity-heatmap",
data: data, // Assuming 'data' is already loaded and filtered as needed
radius: 8000, // Adjust this based on the geographic density of your data
elevationRange: [0, 3000], // Adjust the max elevation to suit your data scale
elevationScale: 1000, // Controls how dramatic the 3D effect is
getColorWeight: d => d["# of Food Insecure Persons Overall"],
colorAggregation: "SUM",
getElevationWeight: d => d["# of Food Insecure Persons Overall"],
elevationAggregation: "SUM",
extruded: true, // This is what makes the layer 3D
getPolygon: d => d.geometry.coordinates,
pickable: true,
upperPercentile: 99.9,
lowerPercentile: 0,
colorRange: [ // Define a color range for the hexagons
[1, 152, 189],
[73, 227, 206],
[216, 254, 181],
[254, 237, 177],
[254, 173, 84],
[209, 55, 78]
],
})
])

Insert cell
gettDeckGLMap = (layers, pitch , bearing) => { // Set default pitch and bearing
let container = html`<div style="height:700px"></div>`;

let deckgl = new deck.DeckGL({
container,
map: mapboxgl,
mapboxAccessToken: '',
mapboxApiAccessToken: mapboxToken,
mapStyle: 'mapbox://styles/mapbox/dark-v10',
layers: layers,
initialViewState: {
longitude: -95.6914,
latitude: 39.0481,
zoom: 3.8,
minZoom: 4,
maxZoom: 17,
pitch: pitch = 45, // Adjusted for a tilted view
bearing: bearing = -10, // Adjusted to rotate the view
},
controller: true
});

return container;
}
Insert cell
countyShapes = data.map(row => JSON.parse(row.Geometry));

Insert cell
counties = FileAttachment("counties.geojson").json()


Insert cell
Insert cell
modified_geojson20211 = FileAttachment("modified_geojson2021@1.geojson").json()
Insert cell
modified_geojson = FileAttachment("modified_geojson.geojson").json();
Insert cell
Insert cell
click = ({object, x, y}) => {
const tooltip = document.getElementById('tooltip'); // Ensure this ID matches your tooltip's ID in HTML
console.log("Clicked Object:", object);
if (object) {
const NUMBER_FI = "# of Food Insecure Persons Overall";
const NAME = "NAME";

const county = object.properties[NAME];
const numberFi = object.properties[NUMBER_FI];

const content = `
<div><strong>County, State:</strong> ${county}</div>
<div><strong># of Food Insecure Persons:</strong> ${numberFi}</div>
`;

tooltip.style.display = 'block';
tooltip.style.top = `${y}px`;
tooltip.style.left = `${x}px`;
tooltip.innerHTML = content;
} else {
tooltip.style.display = 'none';
}
}
Insert cell
showTooltip = (tooltip, object, x, y) => {
let content = `<div><strong>Object Info:</strong> ${object}</div>`;
tooltip.style.display = 'block';
tooltip.style.top = `${y}px`;
tooltip.style.left = `${x}px`;
tooltip.innerHTML = content;
}
Insert cell
hideTooltip = (tooltip) => {
tooltip.style.display = 'none';
}
Insert cell
getttDeckGLMap = (layers, pitch , bearing) => {
let container = html`
<div style="height:700px; position: relative;"></div>`;
let tooltip = html`
<div style="position: absolute; padding: 4px; background: rgba(0, 0, 0, 0.8); color: white; pointer-events: none; display: none; z-index: 9999;"></div>`;
container.appendChild(tooltip);

let prevClickedIndex = null; // Use let instead of const

let deckgl = new deck.DeckGL({
container,
map: mapboxgl,
mapboxAccessToken: "",
mapboxApiAccessToken: mapboxToken,
mapStyle: "mapbox://styles/mapbox/dark-v10",
layers: layers,
initialViewState: {
longitude: -95.6914,
latitude: 39.0481,
zoom: 3.8,
minZoom: 4,
maxZoom: 17,
pitch: (pitch = 45),
bearing: (bearing = -10)
},
controller: true,
onViewStateChange: ({ viewState }) => {
deckgl.setProps({ viewState });
},
// onClick: (event) => {
// let clickedObject = event.object;
// if (clickedObject) {
// // Showing the tooltip
// let x = event.layerX;
// let y = event.layerY;
// showToo
});
return container;
}
Insert cell
getDeckGLMap([
new deck.GeoJsonLayer({
id: "county-shapes",
data: modified_geojson20211,
filled: true,
stroked: false,
extruded: true,
wireframe: true,
getElevation: d => d.properties["# of Food Insecure Persons Overall"], // Use this property for elevation
getFillColor: d => {
// // Define a color scale mapping elevation values to colors
const colorScale = d3.scaleSequential(d3.interpolateHslLong("purple", "orange"))
.domain([30, 1271040]); // Set the domain based on the maximum elevation value

// // Calculate color based on elevation value
return colorScale(d.properties["# of Food Insecure Persons Overall"] || 0);
},
// getFillColor: d => [0, 0, 255], // Adjust the fill color as needed
getLineColor: d => [0, 0, 0], // Adjust the line color as needed
getLineWidth: 1,
pickable: true,
autoHighlight: true,
highlightColor: [255, 0, 0],
onHover: ({ object, x, y }) => {
},
onClick: ({ object, x, y }) => {
// Handle click events if needed
},
// Extract the polygonal coordinates from the "geometry" field
updateTriggers: {
getPolygon: [data?.features?.geometry?.coordinates] // Assuming all features have the same type of geometry
},
getPolygon: d => d.geometry.coordinates,
// Adjust the camera position and view angle
viewState: {
latitude: 0/* set latitude value */,
longitude: 0/* set longitude value */,
zoom: 20/* set zoom level */,
pitch: 5/* set pitch angle */,
bearing: 0/* set bearing angle */,
}
})
]);
// getttDeckGLMap([
// new deck.GeoJsonLayer({
// id: "county-shapes",
// data: modified_geojson20211,
// filled: true,
// stroked: false,
// extruded: true,
// wireframe: true,
// getElevation: d => d.properties["# of Food Insecure Persons Overall"], // Use this property for elevation
// getFillColor: d => {
// // Define a color scale mapping elevation values to colors
// const colorScale = d3.scaleSequential(d3.interpolateOranges)
// .domain([0, 100000]); // Set the domain based on the maximum elevation value

// // Calculate color based on elevation value
// return colorScale(d.properties["# of Food Insecure Persons Overall"] || 0);
// },
// getFillColor: d => [0, 0, 255], // Adjust the fill color as needed
// getLineColor: d => [0, 0, 0], // Adjust the line color as needed
// getLineWidth: 1,
// pickable: true,
// autoHighlight: true,
// highlightColor: [255, 0, 0],
// // onHover: ({ object, x, y }) => {
// // if (object) {
// // // Handle hover events if needed
// // console.log("Hovered Object:", object);
// // }
// // },
// onClick: ({ object, x, y }) => {
// // Handle click events if needed
// click(tooltip)
// },
// // Extract the polygonal coordinates from the "geometry" field
// updateTriggers: {
// getPolygon: [data?.features?.geometry?.coordinates] // Assuming all features have the same type of geometry
// },
// getPolygon: d => d.geometry.coordinates,
// // Adjust the camera position and view angle
// viewState: {
// latitude: 0/* set latitude value */,
// longitude: 0/* set longitude value */,
// zoom: 20/* set zoom level */,
// pitch: 5/* set pitch angle */,
// bearing: 0/* set bearing angle */,
// }
// })
// ]);
Insert cell
Insert cell
modified_geojson2020 = FileAttachment("modified_geojson2020.geojson").json()
Insert cell
hover = (tooltip, {x, y, object}) => {
console.log("Hovered Object:", object);
if (object) {
//haha this should not be the index of the original dataset, here is your problem :)
//console.log('this should be index ',object["index"]);
//const index = object["index"];
const datapoints = object.points.map(m => m.source);

const NUMBER_FI = "# of Food Insecure Persons Overall";
const RATE_FI = "Overall Food Insecurity Rate";
const COUNTY = "County, State";
const counties = datapoints.map(m => m[COUNTY]).join(", ");
const numberFi = d3.sum(datapoints, d => d[NUMBER_FI]);

//aggregating rates is tricky! you can't just average means between multiple counties
//because each county has different population, and thus means have different denominators.
//you need to calculate new mean based on total population and the total number of food-insecure
const population = d3.sum(datapoints, d => d[NUMBER_FI] / d[RATE_FI]);
const overallFi = numberFi / population;

const formatRate = (value) => typeof value === 'number' ? (value * 100).toFixed(0) + "%" : 'N/A';
const formatPopulation = (value) => typeof value === 'number' ? (value/1000).toFixed(0) + " k" : 'N/A';
const content = `
<div><strong>County, State:</strong> ${counties}</div>
<div><strong>Food Insecurity Rate:</strong> ${formatRate(overallFi)}</div>
<div><strong># of Food Insecure Persons:</strong> ${formatPopulation(numberFi)}</div>
`;
tooltip.style.display = 'block';
tooltip.style.top = `${y}px`;
tooltip.style.left = `${x}px`;
tooltip.innerHTML = content;
} else {
tooltip.style.display = 'none';
}
}
Insert cell
getDeckGLMap([
new deck.GeoJsonLayer({
id: "county-shapes",
data: modified_geojson2020,
filled: true,
stroked: false,
extruded: true,
wireframe: true,
getElevation: d => d.properties["# of Food Insecure Persons Overall"], // Use this property for elevation

getFillColor: d => [0, 0, 255], // Adjust the fill color as needed
getLineColor: d => [0, 0, 0], // Adjust the line color as needed
getLineWidth: 1,
pickable: true,
autoHighlight: true,
highlightColor: [255, 0, 0],
onClick: ({object, x, y}) => {
click({object, x, y})
},

// Extract the polygonal coordinates from the "geometry" field
updateTriggers: {
getPolygon: [data?.features?.geometry?.coordinates] // Assuming all features have the same type of geometry
},
getPolygon: d => d.geometry.coordinates,
// Adjust the camera position and view angle
viewState: {
latitude: 0/* set latitude value */,
longitude: 0/* set longitude value */,
zoom: 20/* set zoom level */,
pitch: 5/* set pitch angle */,
bearing: 0/* set bearing angle */,
}
})
]);
Insert cell
modified_geojson2019 = FileAttachment("modified_geojson2019.geojson").json()
Insert cell
2019 MAP
Insert cell
// Define a color scale mapping elevation values to colors
colorScale = d3.scaleSequential(d3.interpolateOranges)
.domain([0, 100000]); // Set the domain based on the maximum elevation value
Insert cell
getColor = (n) => colorScale(n).replace("rgb(","").replace(")","").split(",").map(m => +m)
Insert cell
colorScale(500)
Insert cell
gettDeckGLMap([
new deck.GeoJsonLayer({
id: "county-shapes",
data: modified_geojson2019,
filled: true,
stroked: false,
extruded: true,
wireframe: true,
getElevation: d => d.properties["# of Food Insecure Persons Overall"], // Use this property for elevation
getFillColor: d => {

// Calculate color based on elevation value
return getColor(d.properties["# of Food Insecure Persons Overall"] || 0);
},
// REMOVE THIS getFillColor: d => [0, 0, 255], // Adjust the fill color as needed
getLineColor: d => [0, 0, 0], // Adjust the line color as needed
getLineWidth: 1,
pickable: true,
autoHighlight: true,
highlightColor: [255, 0, 0],
onHover: ({ object, x, y }) => {
// Handle hover events if needed
},
onClick: ({ object, x, y }) => {
// Handle click events if needed
},
// Extract the polygonal coordinates from the "geometry" field
updateTriggers: {
getPolygon: [data?.features?.geometry?.coordinates] // Assuming all features have the same type of geometry
},
getPolygon: d => d.geometry.coordinates,
// Adjust the camera position and view angle
viewState: {
latitude: 0/* set latitude value */,
longitude: 0/* set longitude value */,
zoom: 20/* set zoom level */,
pitch: 5/* set pitch angle */,
bearing: 0/* set bearing angle */,
}
})
]);
Insert cell
mapboxToken = "pk.eyJ1IjoiYm9zdGFkc2J1c3NlbiIsImEiOiJjbHN1a2JsZzYyODA0Mm1uc285N25hdDR5In0.xpGMqGPiskiRgb4wCyBoTg"
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