Mapping NYC subway stations
Jan 21 2012 · Random
I previously wrote about showing the transit layer with the Google Maps API, this is somewhat of a continuation, but narrower in scope; here I’ll talk about showing custom markers for New York City subway stations, making use of data from NYC Open Data (formerly the NYC Data Mine).
The reason for doing this at all, given that a Google Map already shows subway stations, is that the default indicators are fairly inflexible:
- You can’t use a custom icon to change how they look
- You can’t fire off custom event handlers when the user interacts with them
(this is true for all of the point of interest indicators: parks, schools, etc.)
Replacing the point of interest indications with markers turned out to be fairly simple and the data from NYC Open Data was (relatively) clean and readily usable, a pleasant surprise given my previous experience. For this little project, I exported the Subway Stations dataset; it can be exported in a number of formats, but JSON is probably the easiest to work client-side. With the data readily available as a JSON file, it can be loaded simply with an AJAX call to get the file and, once loaded, the subway stations can be plotted on the map by iterating through the list of stations in the JSON data.
It’s worth taking a look at the format of the JSON data, as the indexing of the nodes isn’t all that clear. There’s a meta element and data element at the root, the data element contains a zero-indexed array of subway stations, and each subway station contains a zero-indexed array of attributes, notably:
- 10 = station name
- 12 = dash-delimited list of train lines
- 9 = object with latitude, longitude, and geometry field
(Note that these values are referenced by the field name, not a numeric index).
The code to get the JSON data (using jQuery’s .ajax), iterate through the array of subway stations, extract the relevant pieces of information about the stations, and create map markers for them is shown below. A label is attached to the marker by making use of Marc Ridey’s Label class.
$.ajax({
url: 'http://whatever.com/subway-stops.json',
success: function (ret)
{
for(var i=0; i<ret.data.length; i++)
{
// extract station name, latitude, longitude, and dash-delimited list of train lines at station
var stationName = ret.data[i][10];
var lat = ret.data[i][9]['latitude'];
var lon = ret.data[i][9]['longitude'];
var trainLines = (ret.data[i][12]).split('-');
// make comma-delimited list of train lines
var trainLinesLbl = '';
for(var k=0; k<trainLines.length; k++)
{
trainLinesLbl += trainLines[k];
if(k < trainLines.length-1)
{
trainLinesLbl += ',';
}
}
// create marker
marker = new google.maps.Marker({
"position": new google.maps.LatLng(lat, lon),
"map": map,
"title": stationName + " [" + trainLinesLbl + "]",
"icon": "http://whatever.com/marker-subway.png"
});
// create label for marker
// uses Label created by Marc Ridey
var label = new Label({ map: map });
label.bindTo('position', marker, 'position');
label.bindTo('text', marker, 'title');
}
}
});
With some minor styling to the label and an icon from Map Icons Collection, here’s my result: