Public
Edited
Dec 5, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chicago_boundaries = FileAttachment("Boundaries - Community Areas (current).geojson").json()
Insert cell
preds_stats = FileAttachment("preds_stats_2.csv").csv()
Insert cell
Insert cell
get_pred_median = new Map();
Insert cell
{
preds_stats.filter(function(d){
return ((d.stationOrder2 - d.stationOrder) == 1 &
d.Hour == hour_slider)
}).map(d=>get_pred_median.set(d.stationOrder, d.Prediction_Median))
}
Insert cell
Insert cell
preds_stats.filter(function(d){
return (d.stationOrder2 - d.stationOrder == 1 &
d.Hour == hour_slider)
})
Insert cell
// {
// preds_stats.filter(function(d){
// return ((d.stationOrder2 - d.stationOrder) == 1 &
// d.Hour == hour_slider)
// }).map(d=>get_pred_median.set(d.stationOrder, d.Prediction_Median))
// }
Insert cell
get_pred_std = new Map();
Insert cell
{
preds_stats.filter(function(d){
return (d.stationOrder2 - d.stationOrder == 1 &
d.Hour == hour_slider)
}).map(d=>get_pred_std.set(d.stationOrder, d.Prediction_Std_seconds))
}
Insert cell
get_station_from_order2 = new Map();
Insert cell
lines = new Map();
Insert cell
{
preds_stats.filter(function(d){
return (d.stationOrder2 - d.stationOrder == 1 &
d.Hour == hour_slider)
}).map(d=>get_station_from_order2.set(d.stationOrder2, d.StopName))
}
Insert cell
{
lines.set('Blue', 'B');
lines.set('Red', 'R');
lines.set('Brown', 'T');
lines.set('Purple', 'P');
lines.set('Pink', 'V');
lines.set('Green', 'G');
lines.set('Orange', 'O');
lines.set('Yellow', 'Y');
}
Insert cell
direction = new Map();
Insert cell
{
direction.set('SouthBound', 5)
direction.set('NorthBound', 1)
}
Insert cell
viewof line_choice = Inputs.select(['Blue', 'Red', 'Pink', 'Brown', 'Purple', 'Orange', 'Green', 'Yellow'], {value: 'Blue', label: 'Select Line:'})
Insert cell
viewof direction_choice = Inputs.radio(['SouthBound', 'NorthBound'], {value: 'SouthBound', label: 'Direction:'})
Insert cell
viewof hour_slider = Inputs.range([0,23], {step:1})
Insert cell
viewof station_start = Inputs.select(preds_stats.filter(d => d.Line == lines.get(line_choice) &
d.Prediction_Count > 100 &
d.dir_code == direction.get(direction_choice) &
d.Hour == hour_slider &
d.stationOrder2 - d.stationOrder == 1).map(d => d.stop_name),
{
value: 'O\'Hare',
label: 'Starting point: '
});
Insert cell
station_start_select = new Map(preds_stats.filter(d => d.Line == lines.get(line_choice) &
d.Prediction_Count > 100 &
d.dir_code == direction.get(direction_choice) &
d.Hour == hour_slider &
d.stationOrder2 - d.stationOrder == 1).map(d => [d.stop_name, d.CurrentStationId]))
Insert cell
preds_stats.filter(d => d.Line == lines.get(line_choice) &
d.Prediction_Count > 100 &
d.dir_code == direction.get(direction_choice) &
d.Hour == hour_slider &
d.stationOrder2 - d.stationOrder == 1)
Insert cell
map = {
const mapWidth = 900;
const mapHeight = 1000;

const projection = d3.geoTransverseMercator()
.rotate([90 + 10 / 60, -36 - 40 / 60])
.fitSize([mapWidth,mapHeight], chicago_boundaries);

var map = d3.create('svg')
.attr('width', 900)
.attr('height', mapHeight)
.attr('id', 'map');

var path = d3.geoPath()
.projection(projection);

//create chicago
var chicago = map.append('path')
.datum(chicago_boundaries)
.attr('d', path)
.style('stroke', 'black')
.style('fill', 'none');


//scale for radius size
var radius_scale = d3.scaleLinear().domain([0,120]).range([3, 20])

//overlay stations
var stations = map
.selectAll('circle.station')
.data(preds_stats.filter(d => d.Line == lines.get(line_choice) &
d.Prediction_Count > 100 &
d.dir_code == direction.get(direction_choice) &
d.Hour == hour_slider &
d.stationOrder2 - d.stationOrder == 1))
.join('circle')
.attr('class', 'station')
.attr('cx', (d) => projection([d.stop_lon, d.stop_lat])[0])
.attr('cy', (d) => projection([d.stop_lon, d.stop_lat])[1])
.attr('r', function(d){
if(get_pred_std.get(d.stationOrder) <= 30){
return 5;
}else if(get_pred_std.get(d.stationOrder) > 30 &
get_pred_std.get(d.stationOrder) <= 60){
return 10;
}else{
return 15;
}})
.attr('fill-opacity', 0.5)
.style('fill', line_choice)
.style('stroke', function(d){if(get_pred_std.get(d.stationOrder) >= 120){
return 'red';
}else if(d.stop_name == station_start){
return 'black';
}})

.style('stroke-width', 3)
.append('title')
.text(d => d.stop_name + ' - Median travel time to next stop: ' + get_pred_median.get(d.stationOrder) + '\n')
.append('title')
.text(d => d.stop_name + ' - Median standard deviation to next stop: ' + get_pred_std.get(d.stationOrder) + ' seconds');


//background for title
map.append('rect')
.attr('width', 900)
.attr('height', 20)
.attr('fill', 'white');

//title
map.append('text')
.attr('transform', 'translate(10, 17)')
.attr('font-weight', 400)
.style('font-size', '20px')
.text('Map Showing Prediction Standard Deviation Between Stations');


return map.node();
}
Insert cell
//Filter the data that needs to go to the bar graph

bar_vis_data = preds_stats.filter(function(d){
return (d.CurrentStationId >= station_start_select.get(station_start) & //This is the start point
d.stop_name == station_start &
d.Line == lines.get(line_choice) &
d.Hour == hour_slider &
d.dir_code == direction.get(direction_choice) &
d.Prediction_Count > 100)}).sort((a, b) => a.stationOrder2 - b.stationOrder2)
Insert cell
preds_stats
Insert cell
preds_stats.filter(function(d){
return (d.CurrentStationId >= station_start_select.get(station_start) & //This is the start point (This will be dynamic to allow user selection)
d.stop_name == station_start & //This is the end point (This will be dynamic to allow user selection)
d.Line == lines.get(line_choice) &
d.Hour == hour_slider & //This is the hour that will be attached to the slider
d.dir_code == direction.get(direction_choice) &
d.Prediction_Count > 100)})
Insert cell
station_start_select.get(station_start)
Insert cell
final_bar_vis_data = [...new Map(bar_vis_data.map(item => [item['StopName'], item])).values()]
Insert cell
//Create the bar graph dynamically

bar_graph = Plot.plot({
marginBottom:40,
marginRight:40,
width:900,
className: 'barGraph',
title: 'Prediction Standard Deviations of Starting Point to Different Stops',
y: {
grid: true,
label: 'Standard Deviation'
},
x: {label: 'End Stop'},
color:
{domain: ['X <= 30 Seconds', '30 Seconds > X <= 60 Seconds', 'X > 60 Seconds'],
range: ['green', 'blue', 'red'],
legend: true},
marks: [
Plot.barY(final_bar_vis_data,
{x: "StopName", y: 'Prediction_Std_seconds', fill: function(d)
{if(d.Prediction_Std_seconds <= 30){
return 'Green';
}else if(d.Prediction_Std_seconds > 30 & d.Prediction_Std_seconds <= 60){
return 'Blue';
}else{
return 'Red';
}},
title: (d) => `${d.stop_name} to ${d.StopName} \nMedian Predicted Travel Time: ${d.Prediction_Median}`,
channels: {stationOrder2: 'stationOrder2'},
sort: {
x: 'stationOrder2'
}
}),
Plot.axisX({rotate: -10}),
Plot.ruleY([0])
]
});
Insert cell
Insert cell
{
const station = d3.select(map).selectAll('circle.station');
const barGraph = d3.select(bar_graph).selectAll('rect');


d3.select(map).selectAll('circle.station').filter(d => d.Prediction_Std_seconds <= 20).raise();




//bargraph
barGraph.on('click', function(event, d) {
d3.select(event.currentTarget).classed('highlight', true).raise();

station
.filter((dd) => dd.stationOrder2 == final_bar_vis_data[d + 1].stationOrder2) //stuck on this part
.classed('highlight', true).raise();
});

barGraph.on('pointerover', function(event, d) {
d3.select(event.currentTarget).classed('highlight', false);

station.classed('highlight', false);
});
}
Insert cell
bar_vis_data
Insert cell
p = preds_stats.filter(d => d.Line == lines.get(line_choice) &
d.Prediction_Count > 100 &
d.dir_code == direction.get(direction_choice) &
d.Hour == hour_slider &
d.stationOrder2 - d.stationOrder == 1)
Insert cell
p.filter(d => d.StopName == 'Rosemont')
Insert cell
preds_stats.filter(d => d.Line == lines.get(line_choice) &
d.Prediction_Count > 100 &
d.dir_code == direction.get(direction_choice) &
d.Hour == hour_slider &
d.stationOrder2 - d.stationOrder == 1)
Insert cell
get_station = new Map();
Insert cell
{
preds_stats.filter(d => d.Line == lines.get(line_choice) &
d.Prediction_Count > 100 &
d.dir_code == direction.get(direction_choice) &
d.Hour == hour_slider &
d.stationOrder2 - d.stationOrder == 1).map(d => get_station.set(d.CurrentStationId, d.stop_name))
}
Insert cell
bar_vis_data.filter(function(d, i){
if(d.stationOrder2 != i.stationOrder2){
return d;
}
});
Insert cell
[...new Map(bar_vis_data.map(item => [item['StopName'], item])).values()]
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