Public
Edited
Dec 13, 2022
Insert cell
# Berlin U & S Bahn Interactive update
Insert cell
bbox2 = FileAttachment("Berlin BB 10-13-22.geojson")
Insert cell
d3 = require("d3@6")
Insert cell
chart = {
const width = 1000,
height = 900;
const svg = d3.create("svg")
.attr("viewBox", [100, 10, width-150, height-150]);

// Use Mercator projection
var projection = d3
.geoMercator()
.fitSize([width - 100, height - 100], 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 g = svg.append("g").attr("id", "paths");

var clickYear = 2000
//i'm not using the boundary lines, so I'm going to comment them out
/*
g.selectAll("path1") //d3 geopath
.data(boundary.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", path1) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '.5')
.style("stroke", "rgb(0,0,0)")
*/


// 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("path2") //d3 geopath
.data(Current.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','.5')
.style("stroke-width", '.3')
.style("stroke", "black")





g.selectAll("path2") //d3 geopath
.data(berlinTransportStops1.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','stops')
.attr("d", path2) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "black")
.style("fill-opacity", ".6")
.style('stroke-opacity','.8')
.style("stroke-width", '.5')
.style("stroke", "black")

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

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','parks')
.attr("d", path3) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "green")
.style("fill-opacity", ".7")
.style('stroke-opacity','1')
.style("stroke-width", '.2')
.style("stroke", "black")

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



var c = svg.selectAll("path3") //d3 geopath
.data(bldgs)
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr('d',path3)
.style("fill", "blue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

var c = svg.selectAll("circle")
.data(berlinTransportStops1.features)
.enter()
.append("circle")
.attr("cx", function(d) {return path1.centroid(d)[0]})
.attr("cy", function(d) {return path1.centroid(d)[1]})
.attr('r',2)
.attr('fill','rgb(120,120,120)')
.style('fill-opacity','1')
.style("stroke-width", '0.5')
.style("stroke", "blue")

var t = svg.selectAll("text")
.data(layers)
.enter()
.append('text')
.attr('x',120)
.attr('y',function(d,i) {return 200+20*i})
.attr('fill','black')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text(function(d) {return d})
c.enter().append('circle')
.data(layers)
.enter()
.append('circle')
.attr('cx',110)
.attr('cy',function(d,i) {return 195+20*i})
.attr('r',5)
.attr('fill','aqua')
.style("stroke-width", '.5')
.style("stroke", "black")
.on('click',layersClick)
function layersClick(event,d){
console.log(d)
if(d=='1902'){
clickYear = 1902
d3.selectAll('path.outlines').remove()
d3.selectAll('path.stops').remove()
d3.selectAll('text.layersText').remove()

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'Bold')
.text('Untergrundbahn (Now U1 & U2)')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Berlins First Unntergrund or Underground Railway')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Opened Between Warshauer, Brucke and Potsdamer Platz')
}
if(d=='1910'){
clickYear = 1910
d3.selectAll('path.outlines').remove()
d3.selectAll('path.stops').remove()
d3.selectAll('text.layersText').remove()


g.selectAll("path2")
.data(Line2.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1.5')
.style("stroke", "rgb(0,0,0)")

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'Bold')
.text('U1 & U2 Extend further West & East')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('More Cities are connected by the underground rail')
}
if(d=='1920'){
clickYear = 1920
d3.selectAll('path.outlines').remove()
d3.selectAll('path.stops').remove()
d3.selectAll('text.layersText').remove()

g.selectAll("path2")
.data(Line3.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1.5')
.style("stroke", "rgb(0,0,0)")

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'Bold')
.text('The U3 is added')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Wittenbergplatz is now connected to uhlandstrabe & Theilplatz')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('')
}
if(d=='1930'){
clickYear = 1930
d3.selectAll('path.outlines').remove()
d3.selectAll('path.stops').remove()
d3.selectAll('text.layersText').remove()

g.selectAll("path2")
.data(Line4.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1.5')
.style("stroke", "rgb(0,0,0)")

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'Bold')
.text('Line 6 (now U6) opens and connects to 8 new cities)')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Berlins First electric railway opens in 1924')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('The U2 & U7 extend to new cities and the system scales up dramaticaly')
}

if(d=='1940'){
clickYear = 1940
d3.selectAll('path.outlines').remove()
d3.selectAll('path.stops').remove()
d3.selectAll('text.layersText').remove()
g.selectAll("path2")
.data(Line5.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1.5')
.style("stroke", "rgb(0,0,0)")

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'Bold')
.text('Bombing of berlin results in many stations to cease operations')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Berlin is divided into occupation zones controlled by allied powers that later becomes east and west berlin')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text(' East and west Germany were established and Berlin officially split into two.')
}

if(d=='1970'){
clickYear = 1970
d3.selectAll('path.outlines').remove()
d3.selectAll('path.stops').remove()
d3.selectAll('text.layersText').remove()
g.selectAll("path2")
.data(Line6.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1.5')
.style("stroke", "rgb(0,0,0)")

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'Bold')
.text('1961 marks the construction of berlin wall completely cut off west berlin from the rest of east germany')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('s-bahn ridership in west berlin significantly drops as west berliners boycotts east berlin controlled s-bahn')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('s-bahn opens service from Blankenburg to Hohen Neuendorf replace connection lost from the wall')
}

if(d=='1995'){
clickYear = 1970
d3.selectAll('path.outlines').remove()
d3.selectAll('path.stops').remove()
d3.selectAll('text.layersText').remove()
g.selectAll("path2")
.data(Line7.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1.5')
.style("stroke", "rgb(0,0,0)")

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'Bold')
.text('With German reunification closed railways begin restoration')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('')
}
if(d=='Current'){
clickYear = Current
d3.selectAll('path.outlines').remove()
d3.selectAll('text.layersText').remove()
g.selectAll("path2") //d3 geopath
.data(Current.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", '.5')
.style("stroke", "black")
svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'Bold')
.text('The system continues to grow and the restorations also continue')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('')

svg.append('text')
.attr('class','layersText')
.attr('x', '110')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('')
}
}
svg
.append('rect')
.attr('fill', "white")
.attr('opacity','.8')
.attr('stroke',"rgb(0,0,0)")
.attr('stroke-width',"1px")
.attr('x', 67)
.attr('y', 60)
.attr('width', 600)
.attr('height', 40)


function removespotText(event,d)
{d3.select(this).attr('fill','green')
d3.selectAll('text.spots').remove()
d3.selectAll('line.spotLine').remove()
}




return svg.node();
}
Insert cell
layers = ['1902', '1910', '1920','1930','1940','1970','1995','Current']
Insert cell
Line7 = FileAttachment("1995.geojson").json()
Insert cell
berlinTransportStops1 = FileAttachment("Berlin Transport Stops@1.geojson").json()
Insert cell
bldgs = FileAttachment("Berlin Parks@2.geojson").json()
Insert cell
bldgs2 = FileAttachment("LU-Residential 4 @1.geojson").json()
Insert cell
Current = FileAttachment("Railways.geojson").json()
Insert cell
waterways = FileAttachment("Berlin Waterways@1.geojson").json()
Insert cell
bbox = FileAttachment("Berlin BB 10-13-22.geojson").json()
Insert cell
Insert cell
Spots = d3.csv(Spotslink,d3.autoType)
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