xxxxxxxxxx
274
/*
2017.10.21 -- CitiBike Usage Visualizer
by Aidan Nelson
Desciption: Visualization of my Citibike bike-sharing usage in the past year (Oct 2016 - Oct 2017). I
use citibike often, so there are a relatively large number of trip data points (525) in that time frame.
Citibike trip data
is from their website (after login, there is a 'trips' menu where you can download data) and station
information (containing longitude/latitude) is from citibike's JSON data. Mapping will happen using
Mappa, which interfaces between p5.js and various online mapping APIs.
Citibike information index JSON: http://gbfs.citibikenyc.com/gbfs/gbfs.json
Citibike station information JSON: https://gbfs.citibikenyc.com/gbfs/en/station_information.json
Mappa: https://github.com/cvalenzuela/Mappa
QUESTIONS:
1. Are these arrays of arrays an OK way to hold the station and trip data? A JSON file seems more logical,
in that each data-point (one trip, or one station) would be held together rather than in 3 separate columns
with a single row index, but I don't know what the logic behind storing and accessing this data is... it
basically feels semantically unwise to require someone accessing trip info to know that start_time is at
index 0 and start_station is at index 1, etc.
2. Does "push" copy information or just reference it? IE does "station_info.push(names);" copy the "names" array
into "station_info" array, or just place a reference there? I am wondering this because the "names" array
is, in this case, local to the loadJSON callback function, and if it were referenced, I don't know why it was
not deleted after the function ended...
3. loop protect -- where to add //noprotect? why? what is wrong w/ addCoordinates function?
TO DO:
1. figure out regular expressions: how to match entire station names, rather than parts of names?
IE how to avoid matching "jay st" with "jay st & york st"
2. infinite loop error
*/
// create arrays to hold trip and station info
let all_trips = [];
let station_info = [];
//create variables to hold the map, canvas, and "Mappa" instance
let myMap;
let canvas;
let mappa;
// options for mappa object
let options = {
//set starting coordinates to NYC
lat: 40.7128,
lng: -73.950,
//set zoom level
zoom: 12,
style: "http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png"
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
function preload() {
console.log("in preload");
loadStrings("cb_trips.txt", makeTripTable);
loadJSON("https://gbfs.citibikenyc.com/gbfs/en/station_information.json", makeStationTable);
//load song
soundFormats('mp3');
song = loadSound('bicycle_race.mp3');
}
function setup() {
console.log("in setup");
//test trip data by printing it out in a logical way:
// for (let i=0; i<all_trips[0].length; i++){
// console.log("I biked from " + all_trips[1][i] + " to " + all_trips[3][i] + ".");
// }
//test station data by printing it out in a logical way:
// for (let i = 0; i < station_info[0].length; i++) {
// console.log("The CitiBike station at " + station_info[0][i] + " is located at lat: " + station_info[1][i] + " / long: " + station_info[2][i]);
// }
// Create a canvas 640x640
// canvas = createCanvas(640, 640);
// mappa = new Mappa('Leaflet');
// //call mappa object to create a tilemap at lat,long, zoom level
// myMap = mappa.tileMap(options);
// myMap.overlay(canvas); //create map overlay of a canvas
// Associate redrawMap callback function with an "onChange" event of the map
// myMap.onChange(redrawMap);
setTimeout(addCoordinatesToTrips, 2000, all_trips, station_info);
// console.log(station_info[0].length);
//play the song
// song.setVolume(0.1);
// song.play();
}
function draw() {
// console.log(all_trips[5].length);
// console.log(all_trips[6].length);
// console.log(all_trips[0].length);
}
//function to redraw points
function redrawMap() {
clear();
//iterate through all_trips list
for (let i = 0; i < all_trips[0].length; i++) {
//for each trip, iterate through station list
for (let j = 0; j < station_info[0].length; j++) {
//if the trip start station matches current station (by name), draw blue ellipse at that point
if (all_trips[1][i] == station_info[0][j]) {
let pnt = myMap.latLngToPixel(station_info[1][j], station_info[2][j]);
// console.log(pnt);
fill(0, 0, 255);
ellipse(pnt.x, pnt.y, 5, 5);
}
//if the trip end station matches current station (by name), draw red ellipse at that point
if (all_trips[3][i] == station_info[0][j]) {
let pnt = myMap.latLngToPixel(station_info[1][j], station_info[2][j]);
// console.log(pnt);
fill(255, 0, 0);
ellipse(pnt.x, pnt.y, 5, 5);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
function addCoordinatesToTrips(trips, stations) {
// let startCoordinates = [];
// let endCoordinates = [];
// // let pnt = {lat:0,lng:0};
// //iterate through the array of trips, pulling coordinates for each station from station array
// // console.log(trips[0].length);
// for (let i = 0; i < trips[0].length; i++) {
// //need to check / figure out matching
// // console.log(stations[0].length);
// for (let j = 0; j < stations[0].length; j++) {
// //attempt to match starting station using "^abc$" regular expression format to match entire
// //string as per: https://stackoverflow.com/questions/6298566/regex-match-whole-string
// // let regex = "^" + stations[0][j] + "$";
// // if (match(trips[1][i], regex)) {
// // // console.log("Match: " + trips[1][i] + " //// " + stations[0][j]);
// // //create point object to hold latitude and longitude of the station
// // // let pnt = {
// // // lat: stations[1][j],
// // // lng: stations[2][j]
// // // };
// // // console.log(pnt);
// // //add that point to the start coordinates
// // // startCoordinates.push(pnt);
// // }
// // //attempt to match ending station
// // if (match(trips[3][i], regex)) {
// // // console.log("Match: " + trips[3][i] + " //// " + stations[0][j]);
// // //create point object to hold latitude and longitude of the station
// // // let pnt = {
// // // lat: stations[1][j],
// // // lng: stations[2][j]
// // // };
// // // console.log(pnt);
// // //add that point to the end coordinates
// // // endCoordinates.push(pnt);
// // }
// console.log("i: " + i + " / j: " + j);
// }
// }
// //add the following arrays to the trips array
// trips.push(startCoordinates);
// trips.push(endCoordinates);
//
// console.log("in addCoordinates");
// noprotect
for (let i = 0; i < 500; i++) { // noprotect
// console.log("i: " + i);
// noprotect
for (let j = 0; j < 800; j++) { // noprotect
console.log("i: " + i + " / j: " + j);
}
}
console.log('end');
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
//this function takes citibike trip data and adds it to an array of arrays
//such that index i will correspond to a single trips data
function makeTripTable(cb_trips) {
console.log("in makeTable");
//set up 'columns' as arrays containing all data:
let start_time = [];
let start_station = [];
let end_time = [];
let end_station = [];
let trip_duration = [];
//iterate through all_data, add each line to respective arrays:
let line_index = 1;
//iterate through cb_trips
for (let i = 0; i < cb_trips.length; i++) {
//depending on which line_index we are at, add current string to one of the above arrays
if (line_index % 5 == 0) {
// console.log("5");
trip_duration.push(trim(cb_trips[i]));
// console.log(trip_duration);
} else if (line_index % 4 == 0) {
// console.log("4");
end_station.push(trim(cb_trips[i]));
// console.log(end_station);
} else if (line_index % 3 == 0) {
// console.log("3");
end_time.push(trim(cb_trips[i]));
// console.log(end_time);
} else if (line_index % 2 == 0) {
// console.log("2");
start_station.push(trim(cb_trips[i]));
// console.log(start_station);
} else {
// console.log("1");
start_time.push(trim(cb_trips[i]));
// console.log(start_time);
}
line_index++;
if (line_index > 5) {
line_index = 1;
}
}
//add above arrays to output array
all_trips.push(start_time);
all_trips.push(start_station);
all_trips.push(end_time);
all_trips.push(end_station);
all_trips.push(trip_duration);
}
function makeStationTable(cb_stations) {
console.log("in makeStationTable");
//set up some arrays to hold info
let names = [];
let lat = [];
let lng = [];
//set up a short link to the station data
let stations = cb_stations.data.stations;
//iterate through info, adding to arrays
for (let i = 0; i < stations.length; i++) {
names.push(stations[i].name);
lat.push(stations[i].lat);
lng.push(stations[i].lon);
}
//add arrays from above into station_info
station_info.push(names);
station_info.push(lat);
station_info.push(lng);
}