Public
Edited
Mar 5, 2024
Insert cell
Insert cell
Insert cell
Insert cell
bosNeighborhoods = d3.json('https://gist.githubusercontent.com/cesandoval/09b2e39263c748fbcb84b927cecc7c46/raw/ab71d3638efd2545ec99c2651c6f2ddcea9d2a07/boston.json')
Insert cell
bos311 = (await d3.csv('https://gist.githubusercontent.com/cesandoval/046a91586ae76889aeb5b3e9db53016e/raw/ffb0c410ce8503c8c839cde01235bafb39cb14ad/bostosn_311.csv', d => (d3.autoType(d))))
Insert cell
color = d3.scaleQuantize()
.domain([0, d3.max(bos311, d => +Math.log(d.twitter))])
.range(d3.schemePurples[9]);
Insert cell
// your code here
{
let width = 750
let height = 600
let top_buffer = 50

// Create Projection and geoPath
const bosProjection = d3.geoAlbers()
.scale( 190000 )
.rotate( [71.057,0] )
.center( [0, 42.313] )
.translate( [width/2,(height/2 + top_buffer)] )
const bos_geoPath = d3.geoPath()
.projection( bosProjection )
// Create empty object for holding 311 dataset
const tweetsbyneigh = {};
// Create object referenceable by neighborhood, give it value from tweets
bos311.forEach(d => (tweetsbyneigh[d.Name] = +d.twitter));
// Create SVG canvas
let svg = d3.select(DOM.svg(width, height))

// append new group for legend
svg.append("g")
.attr("transform", "translate(400,30)")
.call(legend);

// Call tooltip
tooltip

// Classic D3... Select non-existent elements, bind the data, append the elements, and apply attributes
svg.selectAll( "path" )
.data( topojson.feature(bosNeighborhoods, bosNeighborhoods.objects.boston_neigh).features )
.enter()
.append( "path" )
.attr( "fill", d => color(Math.log(tweetsbyneigh[d.properties.Name])) )
.attr( "stroke", "#333")
.attr( "d", bos_geoPath )
// Code added after tooltip is called
.on("mouseover", d => tooltip.style("visibility", "visible").text(d.properties.Name + ": " + tweetsbyneigh[d.properties.Name]))
.on("mousemove", d => tooltip.style("top", (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px").text(d.properties.Name + ": " + tweetsbyneigh[d.properties.Name]))
.on("mouseout", d => tooltip.style("visibility", "hidden"))
return svg.node()
}
Insert cell
{
// Create empty object for holding 311 dataset
const tweetsbyneigh = {};
// Create object referenceable by neighborhood, give it value from tweets
bos311.forEach(d => (tweetsbyneigh[d.Name] = +d.twitter+1));
return tweetsbyneigh
}
Insert cell
Insert cell
Insert cell
Insert cell
// your code here;
tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "1")
.style("visibility", "hidden")
.style("background","white")
.style("opacity","0.6")
.style("padding","5px")
.style("font-family", "'Open Sans', sans-serif")
.style("font-size", "12px");
Insert cell
Insert cell
// your code here
legend = g => {
const x = d3.scaleLinear()
.domain(d3.extent(color.domain()))
.rangeRound([0, 260]);

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]));

g.append("text")
.attr("x", x.range()[0])
.attr("y", -6)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text("Tweets per neighborhood (Log Scale)");

g.call(d3.axisBottom(x)
.tickSize(13)
.tickFormat(d => Math.exp
(d).toFixed(1))
.tickValues(color.range().slice(1).map(d => color.invertExtent(d)[0])))
.select(".domain")
.remove();
}
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