Published
Edited
Apr 30, 2019
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
b311Clean = {
return z.parseNums(["id","Citizens_Connect_App","City_Worker_App",
"Constituent_Call","Employee_Generated","twitter","Self_Service","tot_count "], b311)
}
Insert cell
//thanks to Yichun for the reduce function used here!
data = {
var temp=[]
if(neighborhood=="All"){
for(var i=0; i < b311.columns.slice(2,8).length; i++){
temp.push({
"variable":b311.columns.slice(2,8)[i],
"value": z.getCol(b311.columns.slice(2,8)[i], b311Clean).reduce((a, b) => a + b)
})
}
return temp
}
var filterData=z.filter(r=> r.Name==neighborhood, b311Clean)
for(var i=0; i < b311.columns.slice(2,8).length; i++){
temp.push({
"variable":b311.columns.slice(2,8)[i],
"value":z.getCol([b311.columns.slice(2,8)[i]],filterData)[0]
})
}
return temp
}
Insert cell
Insert cell
//building off the Mike Bostock code from https://observablehq.com/@mbostock/u-s-population-by-age/2
chart = {
const svg = (this ? d3.select(this) : d3.create("svg"))
.attr("width", width)
.attr("height", height)
.attr("viewBox", `-70 0 ${width} ${height}`);

if (!this) {
svg.append("g")
.attr("fill", "steelblue")
.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("width", 0);

svg.append("g")
.attr("fill", "white")
.attr("text-anchor", "end")
.style("font", "12px sans-serif")
.selectAll("text")
.data(data)
.enter().append("text")
.attr("class", "label")
.attr("dy", "0.35em")
.attr("x", x(0) - 4);

svg.append("g")
.attr("class", "x-axis");

svg.append("g")
.attr("class", "y-axis");
}

svg.selectAll(".bar")
.data(data, d => d.variable)
.attr("x", x(0))
.attr("y", d => y(d.variable))
.attr("height", y.bandwidth())
.transition()
.delay((d, i) => i * 20)
.attr("width", d => x(d.value) - x(0));

svg.selectAll(".label")
.data(data, d => d.variable)
.attr("y", d => y(d.variable) + y.bandwidth() / 2)
.text(d => d.value.toLocaleString())
.transition()
.delay((d, i) => i * 20)
.attr("x", d => x(d.value) - 4);

svg.select(".x-axis")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(g => g.transition().call(d3.axisBottom(x).ticks(width / 80, "s")))
.call(g => g.select(".domain").remove());

svg.select(".y-axis")
.attr("transform", `translate(${margin.left},0)`)
.call(g => g.transition().call(d3.axisLeft(y).tickSizeOuter(0)));

return svg.node();
}
Insert cell
x = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.range([margin.left, width - margin.right-80])
Insert cell
y = d3.scaleBand()
.domain(data.map(d => d.variable))
.range([height - margin.bottom, margin.top])
.padding(0.1)
Insert cell
height = data.length * 40 + margin.top + margin.bottom
Insert cell
margin = ({top: 10, right: 0, bottom: 20, left: 40})
Insert cell
Insert cell
Insert cell
Insert cell
// project using Albers
bosAlbers = d3.geoAlbers()
.scale( 190000 )
.rotate( [71.057,0] )
.center( [0, 42.313] )
.translate( [width/2,height/2] )
Insert cell
// use D3 function to turn lat-long into positions on a screen
bos_geoPath = d3.geoPath()
.projection( bosAlbers );
Insert cell
tot311 = {
// Create empty object for holding dataset
const tot311ByNeigh = {};
b311Clean.forEach(d =>
tot311ByNeigh[d.id] = {total: d['tot_count ']})
return tot311ByNeigh;
}
Insert cell
// create appropriate purple color scale for chloropleth
color = d3.scaleQuantize()
.domain([1, 12])
.range(d3.schemePurples[9]);
Insert cell
//https://observablehq.com/@mbostock/u-s-state-map
viewof bostonMap = {
const width = 960;
const height = 600;
let value = null;

const svg = d3.select(DOM.svg(width, height))
.style("width", "100%")

const g = svg.append("g")

g.selectAll("path")
.data(topojson.feature(boston, boston.objects.boston_neigh).features) // Bind TopoJSON data elements
.enter().append("path")
.attr("d", bos_geoPath)
.attr("transform","translate(50,200)")
.style("fill", d => color(Math.log(tot311[d.properties.OBJECTID]['total'])))
.style("stroke", "black")
.on("click", d => {
const node = svg.node();
node.value = value = value === d.properties.OBJECTID ? null : d.properties.OBJECTID;
node.dispatchEvent(new CustomEvent("input"));
outline.attr("d", value ? bos_geoPath(d) : null);
});

svg.append("g")
.attr("transform","translate(700,500)")
.attr("fill", "#ccc")
.call(legend);

const outline = svg.append("path")
.attr("fill", "none")
.attr("stroke", "yellow")
.attr("transform","translate(50,200)")

return Object.assign(svg.node(), {value: null});
}
Insert cell

legend = g => {
//scale for size of legend box
const x = d3.scaleLinear()
.domain(d3.extent(color.domain()))
.rangeRound([0, 250]);

// colored gradient box for the legend
g.selectAll("rect")
.data(color.range().map(d => color.invertExtent(d)))
.join("rect")
.attr("height", 8)
.attr("x", d => x(d[0]))
.attr("width", d => x(d[1]) - x(d[0]))
.attr("fill", d => color(d[0]));

// legend title; shifted down along y axis so that it shows up on the SVG
g.append("text")
.attr("x", x.range()[0])
.attr("y", 50)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text("311s per neighborhood (log scale)");

// add on labeled tickmarks
g.call(d3.axisBottom(x)
.tickSize(13)
.tickFormat(d => d3.format(".2n")(d))
.tickValues(color.range().slice(1).map(d => color.invertExtent(d)[0])))
.select(".domain")
.remove();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
//thanks to Yichun for the reduce function used here!
data2 = {
var temp=[]
if(bostonMap2==null){
for(var i=0; i < b311.columns.slice(2,8).length; i++){
temp.push({
"variable":b311.columns.slice(2,8)[i],
"value": z.getCol(b311.columns.slice(2,8)[i], b311Clean).reduce((a, b) => a + b)
})
}
return temp
}
var filterData=z.filter(r=> r.id==bostonMap2, b311Clean)
for(var i=0; i < b311.columns.slice(2,8).length; i++){
temp.push({
"variable":b311.columns.slice(2,8)[i],
"value":z.getCol([b311.columns.slice(2,8)[i]],filterData)[0]
})
}
return temp
}
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