Public
Edited
Jan 27
1 fork
Insert cell
Insert cell
Insert cell
display = {
// basic svg components
const width = 1200, height = 610;
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto;");

var projection = d3.geoMercator().fitSize([width, height], areas);
var scheme1 = d3.interpolateOrRd;
var scheme2 = d3.interpolateGnBu;
var background = svg.append("g")
var diagram = svg.append("g")
var title = svg.append("g")
var description = svg.append("g")
var info = svg.append("g")
var legend = svg.append("g")
var source = svg.append("g")
if (map == 0) {
diagram.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", "none");
title.append("text")
.text('Map of Chicago');
description.append("text")
.text('Select the data you wish to view');
} if (map == 1) {
var bound = bounds(areas.features, "Pop1");
var color = d3.scaleSequential(bound, scheme1);

diagram.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", d => color(d.properties.Pop1));
title.append("text")
.text('Population Density');
description.append("text")
.text('Average population from 2017 to 2021');

source.append("text")
.attr('x', '50').attr('y', '450')
.text('American Community Survey (ACS: Table B01001; Decennial Census: Table P012)');

legend.append("g")
.attr("transform", "translate(50, 460)")
.append(() => Legend(color, {width: 300}));
} if (map == 2) {
var bound = bounds(areas.features, "Insecurity");
var color = d3.scaleSequential(bound, scheme1);

diagram.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", d => color(d.properties.Insecurity));

title.append("text")
.text('Food Insecurity');
description.append("text").attr("id", "description")
.text('Percentage of the residents experiencing food insecurity in 2020');

source.append("text")
.attr('x', '50').attr('y', '470')
.text('Map the Meal Gap (Map the Meal Gap 2020)');

legend.append("g")
.attr("transform", "translate(50, 470)")
.append(() => Legend(color, {width: 300, tickFormat: "%"}));
} if (map == 3) {
var bound = bounds(areas.features, "Insecurity");
var color = d3.scaleSequential(bound, scheme1);

background.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", d => color(d.properties.Insecurity));

diagram.selectAll("path")
.data(foodSources.features).enter().append("path")
.style("fill", scheme2(1))
.style("opacity", ".5");

title.append("text")
.text('Food Sources');
description.append("text").attr("id", "description")
.text('Collection of grocery stores, produce carts, farmer\'s markets, and urban farms');

source.append("text")
.attr('x', '50').attr('y', '470')
.text('Accessibility buffers around sources determined by shop size');

legend.append("g")
.attr("transform", "translate(50, 470)")
.append(() => Legend(color, {width: 300, tickFormat: "%"}));
} if (map == 4) {
var bound = bounds(areas.features, "Insecurity");
var color = d3.scaleSequential(bound, scheme1);

background.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", d => color(d.properties.Insecurity));
background.append("g").selectAll("buffer")
.data(foodSourceBuffers.features).enter().append("path")
.style("fill", scheme2(1))
.style("opacity", ".5");
title.append("text")
.text('Food Source Buffers');
description.append("text").attr("id", "description")
.text('Areas the collection of food sources provides accessible food to');

source.append("text")
.attr('x', '50').attr('y', '470')
.text('Coverage buffer based on shop type and size');

legend.append("g")
.attr("transform", "translate(50, 470)")
.append(() => Legend(color, {width: 300, tickFormat: "%"}));
} if (map == 5) {
var bound = bounds(foodDesert1.features, "Desert1");
var color = d3.scaleSequential(bound, scheme1);

background.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", scheme1(0));

diagram.selectAll("path")
.data(foodDesert1.features).enter().append("path")
.style("fill", d => color(d.properties.Desert1));
title.append("text")
.text('Food Desert (Before)');
description.append("text").attr("id", "description")
.text('Areas with minimal access to healthy, nutritious food');

source.append("text")
.attr('x', '50').attr('y', '470')
.text('Grocery stores, produce carts, farmer\'s markets, and urban farms');

legend.append("g")
.attr("transform", "translate(50, 470)")
.append(() => Legend(color, {width: 300, tickFormat: "%"}));
} if (map == 6) {
var bound = bounds(foodDesert1.features, "Desert1");
var color = d3.scaleSequential(bound, scheme1);
background.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", scheme1(0));

background.selectAll("clear")
.data(foodDesert1.features).enter().append("path")
.style("fill", d => color(d.properties.Desert1));

diagram.selectAll("path")
.data(cityLots.features).enter().append("path")
.style("fill", scheme2(1))
.style("opacity", ".5");
title.append("text")
.text('Urban Farms');
description.append("text").attr("id", "description")
.text('Collection of 667 vacant city-owned lots that can be turned into urban farms');

source.append("text")
.attr('x', '50').attr('y', '470')
.text('City-Owned Land Inventory (Department of Planning and Development)');

legend.append("g")
.attr("transform", "translate(50, 470)")
.append(() => Legend(color, {width: 300, tickFormat: "%"}));
} if (map == 7) {
var bound = bounds(foodDesert1.features, "Desert1");
var color = d3.scaleSequential(bound, scheme1);

background.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", scheme1(0));

background.selectAll("clear")
.data(foodDesert1.features).enter().append("path")
.style("fill", d => color(d.properties.Desert1));

background.selectAll("buffer")
.data(urbanFarmBuffer.features).enter().append("path")
.style("fill", scheme2(1))
.style("opacity", ".5");
title.append("text")
.text('Urban Farm Buffers');
description.append("text").attr("id", "description")
.text('Areas the additional urban farms will provide accessible food to');

source.append("text")
.attr('x', '50').attr('y', '470')
.text('Coverage buffer based on lot size');

legend.append("g")
.attr("transform", "translate(50, 470)")
.append(() => Legend(color, {width: 300, tickFormat: "%"}));
} if (map == 8) {
var bound = bounds(foodDesert2.features, "Desert2");
var color = d3.scaleSequential(bound, scheme1);

background.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", scheme1(0));

diagram.selectAll("path")
.data(foodDesert2.features).enter().append("path")
.style("fill", d => color(d.properties.Desert2));
title.append("text")
.text('Food Desert (After)');
description.append("text").attr("id", "description")
.text('Areas with minimal access to healthy, nutritious food');

source.append("text")
.attr('x', '50').attr('y', '470')
.text('Previous food sources with addition of proposed urban farms');

legend.append("g")
.attr("transform", "translate(50, 470)")
.append(() => Legend(color, {width: 300, tickFormat: "%"}));
} if (map == 9) {
var bound = bounds(areas.features, "Change");
var color = d3.scaleSequential(bound, scheme2);

diagram.selectAll("path")
.data(areas.features).enter().append("path")
.style("fill", d => color(d.properties.Change));
title.append("text")
.text('Food Desert Summary');
description.append("text").attr("id", "description")
.text('Percent change in accessibility for healthy, nutritious food with implementation of urban farm proposal');

legend.append("g")
.attr("transform", "translate(50, 470)")
.append(() => Legend(color, {width: 300, tickFormat: "%"}));
}
svg.selectAll("text")
.style('font-family', 'roboto+slab');

background.selectAll("path")
.attr("d", d3.geoPath().projection(projection))
.attr("transform", `translate(-100, 0)`)
.style("stroke", "white")
diagram.selectAll("path")
.attr("d", d3.geoPath().projection(projection))
.attr("transform", `translate(-100, 0)`)
.style("stroke", "white")
.on('mouseover', showInfo)
.on('mouseout', hideInfo);

if (map == 0) {
diagram.selectAll("path")
.style("stroke", scheme2(1))
}

function showInfo (event,d) {
if (map == 1) {
info.append("path")
.datum([[width - 350, 100], [width - 350, 160]]);
info.append("text")
.attr('class', 'title')
.text(d.properties.Name);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`Average population of ${Math.ceil(d.properties.Pop1)} residents`);
} if (map == 2) {
info.append("path")
.datum([[width - 350, 100], [width - 350, 180]]);
info.append("text")
.attr('class', 'title')
.text(d.properties.Name);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`${(d.properties.Insecurity * 100).toFixed(2)}% of residents experiencing food insecurity`);
} if (map == 3) {
info.append("text")
.attr('class', 'title')
.text(d.properties.Type);

if (d.properties.Type == 'Grocery Store') {
info.append("path")
.datum([[width - 350, 100], [width - 350, 240]]);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`Name: ${d.properties.Name}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 170)
.text(`Address: ${d.properties.Address}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 190)
.text(`Community Area: ${d.properties.Community}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 210)
.text(`Zip Code: ${d.properties["Zip Code"]}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 230)
.text(`Size: ${d.properties.Size} SF`);
} else if (d.properties.Type == 'Produce Cart') {
info.append("path")
.datum([[width - 350, 100], [width - 350, 160]]);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`Address: ${d.properties.Address}`);
} else if (d.properties.Type == 'Farmer\'s Market') {
info.append("path")
.datum([[width - 350, 100], [width - 350, 240]]);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`Name: ${d.properties.Name}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 170)
.text(`Address: ${d.properties.Address}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 190)
.text(`Type: ${d.properties["Market Type"]}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 210)
.text(`Day: ${d.properties.Day}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 230)
.text(`Time: ${d.properties["Start Time"]} - ${d.properties["End Time"]}`);
} else if (d.properties.Type == 'Urban Farm') {
info.append("path")
.datum([[width - 350, 100], [width - 350, 160]]);

info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`Address: ${d.properties.Address}`);
}
} if (map == 5) {
info.append("path")
.datum([[width - 350, 100], [width - 350, 180]]);
info.append("text")
.attr('class', 'title')
.text(d.properties.Name);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`${Math.ceil(d.properties.Pop2)} (${(d.properties.Desert1 * 100).toFixed(2)}%) residents have minimal access to food`);
} if (map == 6) {
info.append("path")
.datum([[width - 350, 100], [width - 350, 240]]);
info.append("text")
.attr('class', 'title')
.text(d.properties.Address);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`Community Area: ${d.properties.Community}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 170)
.text(`PIN: ${d.properties.PIN}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 190)
.text(`Managing Organization: ${d.properties["Managing Organization"]}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 210)
.text(`Zoning Classification: ${d.properties["Zoning Classification"]}`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 230)
.text(`Size: ${d.properties.Size} SF`);
} if (map == 8) {
info.append("path")
.datum([[width - 350, 100], [width - 350, 180]]);
info.append("text")
.attr('class', 'title')
.text(d.properties.Name);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`${Math.ceil(d.properties.Pop3)} (${(d.properties.Desert2 * 100).toFixed(2)}%) residents have minimal access to food`);
} if (map == 9) {
info.append("path")
.datum([[width - 350, 100], [width - 350, 200]]);
info.append("text")
.attr('class', 'title')
.text(d.properties.Name);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 150)
.text(`Change: ${(d.properties.Change * 100).toFixed(2)}%`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 170)
.text(`Before: ${(d.properties.Desert1 * 100).toFixed(2)}%`);
info.append("text")
.attr('class', 'description')
.attr('x', width - 325).attr('y', 190)
.text(`After: ${(d.properties.Desert2 * 100).toFixed(2)}%`);
}
info.selectAll("path")
.attr("d", polyline.polyline().attr("points", d => d))
.style("fill", "none")
.style("stroke", scheme1(0.8))
.style("stroke-width", "3")
info.selectAll("text.title")
.attr('x', width - 325).attr('y', 125)
.style('font-size', '24px')
.style('font-weight', 'bold')
.style('fill', scheme1(0.8))
.each(function(d) {wrap_text(d3.select(this), 150)});
info.selectAll("text.description")
.style('font-size', '16px')
.style('font-weight', 'regu')
.style('fill', scheme1(0.5))
.each(function(d) {wrap_text(d3.select(this), 200)});

if (map == 9) {
info.selectAll("path")
.style("stroke", scheme2(0.8))
info.selectAll("text.title")
.style('fill', scheme2(0.8))
info.selectAll("text.description")
.style('fill', scheme2(0.5))
}
}
function hideInfo() {
info.selectAll('path').remove();
info.selectAll('text').remove();
}

title.selectAll("text")
.attr('x', '50').attr('y', '400')
.style('font-size', '32px')
.style('font-weight', 'bold')
.style('fill', scheme1(0.8))
.each(function(d) {wrap_text(d3.select(this), 150)});
description.selectAll("text")
.attr('x', '50').attr('y', '430')
.style('font-size', '16px')
.style('font-weight', 'regular')
.style('fill', scheme1(0.5))
.each(function(d) {wrap_text(d3.select(this), 200)});

if (map == 0 || map == 9) {
title.selectAll("text")
.style('fill', scheme2(0.8))
description.selectAll("text")
.style('fill', scheme2(0.5))
}
source.selectAll("text")
.style('font-size', '10px')
.style('font-weight', 'regular')
.style('fill', scheme1(0.3))
.each(function(d) {wrap_text(d3.select(this), 330)});
return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// data = {
// var f = []
// var health = chicagoHealthAtlasData
// var map = areas.features
// var desert = foodDesert.features
// for (let i = 0; i < health.length; i++) {
// for (let j = 0; j < map.length; j++) {
// if (health[i].GEOID == map[j].properties.ID) {
// f.push({type:'Feature',
// properties: {
// Name: health[i].Name,
// ID: health[i].GEOID,
// Population1: health[i]["POP_2017-2021"],
// Population2: 0,
// Area1: map[j].properties["Shape Area"],
// Area2: 0,
// FoodInsecurity: health[i].FAI_2020 / 100
// },
// geometry: map[j].geometry})
// }
// }
// } for (let i = 0; i < f.length; i++) {
// for (let j = 0; j < desert.length; j++) {
// if (f[i].properties.ID == desert[j].properties.ID) {
// desert[j].properties.Community = f[i].properties.Name;
// desert[j].properties["Shape Area"] *= 10;
// desert[j].properties["Old Area"] = f[i].properties.Area1;
// f[i].properties.Area2 = desert[j].properties["Shape Area"];
// f[i].properties.Population2 = f[i].properties.Population1 * f[i].properties.Area2 / f[i].properties.Area1;
// f[i].properties.FoodDesert = f[i].properties.Population2 / f[i].properties.Population1;
// desert[j].properties.Population1 = f[i].properties.Population1;
// desert[j].properties.Population2 = f[i].properties.Population2;
// desert[j].properties.FoodDesert = f[i].properties.FoodDesert;
// }
// }
// } return {type: "FeatureCollection", features: f}
// }
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