Public
Edited
Apr 24, 2024
Insert cell
md`# Developer Visualization`
Insert cell
jsonURL0 = "https://api.homehopeny.site/Boroughs/?limit=250&skip=0"
Insert cell
Districtdata = fetch(jsonURL0)
.then(response => {
if (!response.ok) throw new Error(response.status);
return response.json();
})
Insert cell
jsonURL1 = "https://api.homehopeny.site/Shelters/?limit=250&skip=0"
Insert cell
Shelterdata = fetch(jsonURL1)
.then(response => {
if (!response.ok) throw new Error(response.status);
return response.json();
})
Insert cell
jsonURL2 = "https://api.homehopeny.site/Pantries/?limit=250&skip=0"
Insert cell
Pantrydata = fetch(jsonURL2)
.then(response => {
if (!response.ok) throw new Error(response.status);
return response.json();
})
Insert cell
data = {return {"pantry":Pantrydata, "shelter":Shelterdata, "district":Districtdata}}
Insert cell
function calculateOcc() {
const Dict = {};
for(const keyT in data) {
const dataList = data[keyT]["results"];
Dict[keyT] = {};
dataList.forEach(dataItem => {
let borough = dataItem.borough.toUpperCase();
if(borough == "THE BRONX"){
borough = "BRONX";
}
if(borough == "STATEN IS") {
borough = "STATEN ISLAND";
}
if(!Dict[keyT][borough]){
Dict[keyT][borough] = 0;
}
Dict[keyT][borough]++;
});
}
return Dict;
}
Insert cell
OccurrencesDict = calculateOcc();
Insert cell
data1 = {
const boroughs = Object.keys(OccurrencesDict.pantry); // Assuming pantry has all boroughs
const result = boroughs.map(borough => {
const obj = { group: borough };
Object.keys(OccurrencesDict).forEach(group => {
obj[group] = OccurrencesDict[group][borough];
});
return obj;
});
return result;
}
Insert cell
subgroups = Object.keys(data1[0]).slice(1)
Insert cell
groups = d3.map(data1, function(d){return(d.group)})
Insert cell
color = d3.scaleOrdinal(d3.schemeSet2).domain(d3.range(subgroups.length))
Insert cell
x = d3.scaleBand()
.domain(d3.range(groups.length))
.rangeRound([margin.left, width - margin.right])
.padding(0.15)
Insert cell
height = 500
Insert cell
y = d3.scaleLinear()
.domain([0, stackedMax])
.range([height - margin.bottom, margin.top])
Insert cell
xAxis = d3.axisBottom(x)
.tickSize(0)
.tickPadding(8)
.tickFormat((d, i) => groups[i])
Insert cell
yAxis = d3.axisLeft(y).tickPadding(8)
Insert cell
legendBoxSize = 15
Insert cell
legendPadding = 5
Insert cell
legend = svg => {
const entry = svg
.append("g")
.selectAll(".entry")
.data(subgroups)
.join("g")
.attr(
"transform",
(d, i) => `translate(0,${(legendBoxSize) * i})`
)
.attr("class", "entry");

entry
.append("rect")
.attr("width", legendBoxSize)
.attr("height", legendBoxSize)
.attr("fill", (d, i) => color(i));

entry
.append("text")
.text(d => d)
.attr("x", legendBoxSize + legendPadding)
.attr("y", legendBoxSize / 2)
.attr("dy", "0.2em")
.style("font", "11px sans-serif");
}
Insert cell
margin = ({top: 20 + color.domain().length * (legendBoxSize + legendPadding), right: 20, bottom: 30, left: 50})
Insert cell
Data = d3.stack()
.keys(subgroups)(data1)
.map((data, i) => data.map(([y0, y1]) => [y0, y1, i])) // add an extra array element for the subgroup index
Insert cell
groupedMax = d3.max(Data, y => d3.max(y, d => d[1]))
Insert cell
stackedMax = d3.max(Data, y => d3.max(y, d => d[1]))
Insert cell
viewof layout = {
const form = html`<form>
<label style="margin-right:0.5em;"><input type=radio name=radio value="stacked" checked> Apiladas</label>
<label style="margin-right:0.5em;"><input type=radio name=radio value="grouped"> Agrupadas</label>
</form>`;
form.oninput = () => form.value = form.radio.value;
form.onchange = () => { // Safari…
form.value = form.radio.value;
form.dispatchEvent(new CustomEvent("input"));
};
form.value = form.radio.value;
return form;
}
Insert cell
chart1 = {
//const width =
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const subgroup = svg
.selectAll(".subgroup")
.data(Data)
.join("g")
.attr("class", "subgroup")
.attr("fill", (d, i) => color(i));

const rect = subgroup
.selectAll("rect")
.data(d => d)
.join("rect")
.attr("x", (d, i) => x(i))
.attr("y", height - margin.bottom)
.attr("width", x.bandwidth())
.attr("height", 0);

subgroup.on("mouseenter", function() {
svg
.selectAll(".subgroup")
.transition()
.style("fill-opacity", 0.15);
d3.select(this)
.transition()
.style("fill-opacity", 1);
});

subgroup.on("mouseleave", function() {
svg
.selectAll(".subgroup")
.transition()
.style("fill-opacity", 1);
});

svg
.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.style("font-size", "13px")
.call(xAxis);

const yAxisContainer = svg
.append("g")
.attr("transform", `translate(${margin.left},0)`)
.style("font-size", "13px")
.call(yAxis);

svg
.append("g")
.attr("transform", `translate(${width + margin.left - 210},0)`)
.call(legend);

function transitionGrouped() {
y.domain([0, groupedMax]);
yAxisContainer
.transition()
.duration(500)
.delay(500)
.call(yAxis);

rect
.transition()
.duration(500)
.delay((d, i) => i * 20)
.attr("x", (d, i) => x(i) + (x.bandwidth() / subgroups.length) * d[2])
.attr("width", x.bandwidth() / subgroups.length)
.transition()
.attr("y", d => y(d[1] - d[0]))
.attr("height", d => y(0) - y(d[1] - d[0]));
}

function transitionStacked() {
y.domain([0, stackedMax]);
yAxisContainer
.transition()
.duration(500)
.call(yAxis);

rect
.transition()
.duration(500)
.delay((d, i) => i * 20)
.attr("y", d => y(d[1]))
.attr("height", d => y(d[0]) - y(d[1]))
.transition()
.attr("x", (d, i) => x(i))
.attr("width", x.bandwidth());
}

function update(layout) {
if (layout === "stacked") transitionStacked();
else transitionGrouped();
}

return Object.assign(svg.node(), { update });
}
Insert cell
update = chart1.update(layout)
Insert cell
pieSumData = Object.entries(OccurrencesDict).map(([borough, values]) => ({
borough,
value: d3.sum(Object.values(values))
}));

Insert cell
PieChart = {
const width = 600; // Set the width of the SVG
const height = 400; // Set the height of the SVG
const radius = Math.min(width, height) / 2; // Calculate the radius
// Create an SVG element
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);

const data = Object.entries(OccurrencesDict).map(([borough, values]) => ({ borough, value: d3.sum(Object.values(values))}));

// Sort the data array by rate in descending order
data.sort((a, b) => b.value - a.value);

// Define the color scale
const color = d3.scaleOrdinal()
.domain(data.map(d => d.borough))
.range(d3.schemeCategory10);

// Define the pie function
const pie = d3.pie()
.sort(null) // Disable sorting by start angle
.value(d => d.value);

// Define the arc function
const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius - 20);

// Append a group element for the pie chart
const pieGroup = svg.append("g")
.attr("transform", `translate(${width / 2}, ${height / 2+20})`);

// Generate the pie chart
const slices = pieGroup.selectAll("path")
.data(pie(data))
.join("path")
.attr("fill", d => color(d.data.borough)) // Use cancer type as color
.attr("d", arc);

// Add tooltips
slices.append("title")
.text(d => `${d.data.borough}: ${d.data.value}`);

// Add labels on pie slices
pieGroup.selectAll("text")
.data(pie(data))
.join("text")
.attr("transform", d => `translate(${arc.centroid(d)})`)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(d => d.data.borough);

// Add tooltip interaction
slices.on("mouseover", function() {
d3.select(this)
.transition()
.duration(200)
.attr("fill", d => d3.rgb(color(d.data.borough)).darker(0.3));
})
.on("mouseout", function() {
d3.select(this)
.transition()
.duration(200)
.attr("fill", d => color(d.data.borough));
});

// Add title
svg.append("text")
.attr("x", width / 2)
.attr("y", 20)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.style("font-weight", "bold") // Make the text bold
.text("The Proportion of Pantries, shelters and districts");

// Return the SVG element
return svg.node();
}

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more