Public
Edited
Dec 14, 2022
Insert cell
# Berlin's Green '
Insert cell
d3 = require("d3@7", "d3-geo-scale-bar@1.2", "d3-tile@1")
Insert cell
scaleBar = d3.geoScaleBar()
.top(1.15)
.left(0)
//.label("Yards")
.units({units: "500 Feet", radius: 20902259.664}) // Will do the same as the previous two lines

//.units({units: "350 Yards", radius: 6967419.888})
//.distance(width <= 400 ? 1200 : 1000)
.distance(500)
//.labelAnchor("middle")
//.tickSize(null)
//.tickValues(null)
Insert cell
chart = {
const width = 960,
height = 900;
const svg = d3.create("svg")
.attr("viewBox", [-175, -50, width+200, height+100]);//change x value to give margin on left side, add to width value to increase width of map view

// Use Mercator projection
var projection = d3
.geoMercator()
.fitSize([width - 50, height - 50], bbox);

var path1 = d3.geoPath().projection(projection);
var path2 = d3.geoPath().projection(projection);
var path3 = d3.geoPath().projection(projection);
var path4 = d3.geoPath().projection(projection);
var path5 = d3.geoPath().projection(projection);

var g = svg.append("g").attr("id", "paths");
//i'm not using the boundary lines, so I'm going to comment them out


// display roads
//show current transit sytems
//display connected parks
//display proposed sytem
//Movable object across an array of points along a single curve
//select parks for information
//hover over tram to get information on it

g.selectAll("path4") //d3 geopath
.data(parks.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path4) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "green")
.style("fill-opacity", ".3")
.style('stroke-opacity','.4')
.style("stroke-width", '.5')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2") //d3 geopath
.data(subLns.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path2) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '.75')
.style("stroke", "rgb(100,100,100)")

g.selectAll("path3") //d3 geopath
.data(bldgs.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path3) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "rgb(240,240,240)")
.style("fill-opacity", ".5")
.style('stroke-opacity','.4')
.style("stroke-width", '.5')
.style("stroke", "rgb(0,0,0)")

//subway stops
var c = svg.selectAll("circle") //d3 geopath
.data(subSts.features)
.enter() //there are more data than elements, this selects them
.append("circle") //appends path to data
.attr("cx", function(d) {return path1.centroid(d)[0]})
.attr("cy", function(d) {return path1.centroid(d)[1]})
.attr('r',3)
.attr('fill','black')
.style('fill-opacity','1')

//chargers circles
c.enter().append('circle')//use this code for the second and any subsequent circle adds///***
.data(chargers)///***
.enter() //there are more data than elements, this selects them
.append("circle") //appends path to data
.attr("cx", function(d) {return projection([d.long,d.lat])[0]})///***
.attr("cy", function(d) {return projection([d.long,d.lat])[1]})///***
.attr('r',3)
.attr('fill','cyan')
.style('fill-opacity','1')
.style('stroke-width','1')
.style('stroke','black')

//add citibike circles
c.enter().append('circle') //d3 geopath
.data(bikes)
.enter() //there are more data than elements, this selects them
.append("circle") //appends path to data
.attr('class','cb')
.attr("cx", function(d) {return projection([d.long,d.lat])[0]})
.attr("cy", function(d) {return projection([d.long,d.lat])[1]})
.attr('r',4)
.attr('fill','white')
.style('fill-opacity','1')
.style('stroke','black')
.style('stroke-width','.75')
.on('mouseover',bikeText)
.on('mouseout',removeText)

//subway text
var t = svg.selectAll("text")//creating a variable t and adding all text objects to it
.data(subSts.features)
.enter() //there are more data than elements, this selects them
.append("text") //appends path to data
.attr("x", function(d) {return path1.centroid(d)[0]})
.attr("y", function(d) {return path1.centroid(d)[1]-5})
.attr('font-family','helvetica')
.attr('font-size','.5em')
.attr('font-weight','400')
.style("fill", "rgb(110,110,110)")
.attr('text-anchor','middle')
.text(function(d) {return d.properties.name})

//add charger annotation
t.enter().append('text')//use this for second and all subsequent text adds
.data(chargers)
.enter() //there are more data than elements, this selects them
.append("text") //appends path to data
.attr("x", '-10')
.attr("y", function(d,i){return i*30})///****
.attr('font-family','helvetica')
.attr('font-size','.55em')
.attr('font-weight','bold')
.style("fill", "rgb(0,0,0)")
.attr('text-anchor','end')
.text(function(d) {return d.name})//****

t.enter().append('text')//use this for second and all subsequent text adds
.data(chargers)
.enter() //there are more data than elements, this selects them
.append("text") //appends path to data
.attr("x", '-10')
.attr("y", function(d,i){return i*30+10})///****
.attr('font-family','helvetica')
.attr('font-size','.55em')
.attr('font-weight','400')
.style("fill", "rgb(100,100,100)")
.attr('text-anchor','end')
.text(function(d) {return d.description})//****

//annotation lines for chargers
t.enter().append('line')
.data(chargers)
.enter()
.append("line")
.attr('x1','-10')
.attr('y1',function(d,i){return i*30-3})
.attr('x2',function(d) {return projection([d.long,d.lat])[0]})
.attr('y2',function(d,i){return i*30-3})
.attr('stroke-width','1')
.attr('stroke-dasharray','4,4')
.attr('stroke','rgb(100,100,100)')

t.enter().append('line')
.data(chargers)
.enter()
.append("line")
.attr('x1',function(d) {return projection([d.long,d.lat])[0]})
.attr('y1',function(d,i){return i*30-3})
.attr('x2',function(d) {return projection([d.long,d.lat])[0]})
.attr('y2',function(d) {return projection([d.long,d.lat])[1]})
.attr('stroke-width','1')
.attr('stroke-dasharray','4,4')
.attr('stroke','rgb(100,100,100)')


//draw site outline
g.selectAll("path5") //d3 geopath
.data(site.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path5) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style("fill-opacity", "1")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "rgb(0,0,0)")
.attr('stroke-dasharray','12 12')

//add labels to site line
svg
.append("text")
.attr('class','title')
.attr('x','400')
.attr('y','500')
.attr('font-family','helvetica')
.attr('font-size','1em')
.attr('font-weight','bold')
.style("fill", "rgb(0,0,0)")
.text('Times Square')

svg
.append("text")
.attr('class','title')
.attr('x','400')
.attr('y','517')
.attr('font-family','helvetica')
.attr('font-size','.7em')
.attr('font-weight','200')
.style("fill", "rgb(0,0,0)")
.text('The Future of Movement')

svg
.append("text")
.attr('class','title')
.attr('x','-75')
.attr('y','700')
.attr('font-family','helvetica')
.attr('font-size','.7em')
.attr('font-weight','200')
.style("fill", "rgb(0,0,0)")
.attr('text-anchor','middle')
.text('Citi Bike Stations')

svg
.append("line")
.attr('x1','400')
.attr('y1','495')
.attr('x2','378')
.attr('y2','495')
.attr('stroke-width','1.5')
.attr('stroke','rgb(0,0,0)')

svg
.append("line")
.attr('x1','-120')
.attr('y1','708')
.attr('x2','-10')
.attr('y2','708')
.attr('stroke-width','1.5')
.attr('stroke','rgb(0,0,0)')

function bikeText(event,d){

d3.select(this).attr('fill','black')
svg.append('text')//use this for second and all subsequent text add
.attr("x", '-75')
.attr("y", '720')
.attr('class','bikeStop')
.attr('font-family','helvetica')
.attr('font-size','.55em')
.attr('font-weight','bold')
.style("fill", "rgb(0,0,0)")
.attr('text-anchor','middle')
.text(d.name)

svg.append('text')//use this for second and all subsequent text add
.attr("x", '-75')
.attr("y", '730')
.attr('class','bikeStop')
.attr('font-family','helvetica')
.attr('font-size','.55em')
.attr('font-weight','400')
.style("fill", "rgb(50,50,50)")
.attr('text-anchor','middle')
.text(d.description)

svg.append("line")
.attr('x1','-10')
.attr('y1','720')
.attr('class','bikeLine')
.attr('x2',projection([d.long,d.lat])[0])
.attr('y2','720')
.attr('stroke-width','1')
.attr('stroke-dasharray','4,4')
.attr('stroke','rgb(100,100,100)')

svg.append("line")
.attr('x1',projection([d.long,d.lat])[0])
.attr('y1','720')
.attr('class','bikeLine')
.attr('x2',projection([d.long,d.lat])[0])
.attr('y2',projection([d.long,d.lat])[1])
.attr('stroke-width','1')
.attr('stroke-dasharray','4,4')
.attr('stroke','rgb(100,100,100)')
}

function removeText(event,d){//remove citi bike address information
d3.selectAll('text.bikeStop').remove()
d3.selectAll('line.bikeLine').remove()
d3.selectAll('circle.cb').attr('fill','white')
}

scaleBar
.projection(projection)
.size([width, height]);

svg.append("g")
.call(scaleBar);



return svg.node();
}
Insert cell
site = FileAttachment("site_boundary_02.geojson").json()
Insert cell
subSts = FileAttachment("sub_stops.geojson").json()
Insert cell
bldgs = FileAttachment("bldgs.geojson").json()
Insert cell
bbox = FileAttachment("site_boundary.geojson").json()
Insert cell
parks = FileAttachment("parks.geojson").json()
Insert cell
subLns = FileAttachment("subway_lines.geojson").json()
Insert cell
boundary = FileAttachment("nyc_boundary.geojson").json()
Insert cell
Insert cell
chargers = d3.csv(chargesLink,d3.autoType)
Insert cell
Insert cell
bikes = d3.csv(bikesLink,d3.autoType)
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