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

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