Two approaches to visualizing MTA NYCT A Divsion ATS data in Google Earth
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from csv import DictReader | |
from collections import defaultdict | |
import xml.etree.ElementTree as etree | |
from datetime import datetime | |
import pytz | |
from gtfs import Schedule | |
from gtfs.entity import Stop | |
eastern = pytz.timezone('US/Eastern') | |
dr = DictReader(open('data.csv')) | |
schedule = Schedule('google_transit.db') | |
trains = defaultdict(list) | |
for row in dr: | |
trains[row['train_id']].append(row) | |
print len(trains) | |
style = etree.fromstring("""<Style id="train" xmlns="http://www.opengis.net/kml/2.2"> | |
<IconStyle> | |
<scale>0.5</scale> | |
<Icon> | |
<href>http://maps.google.com/mapfiles/kml/shapes/rail.png</href> | |
</Icon> | |
</IconStyle> | |
<LabelStyle> | |
<scale>0</scale> | |
</LabelStyle> | |
</Style>""") | |
kml = etree.Element("{http://www.opengis.net/kml/2.2}kml") | |
folder = etree.SubElement(kml, "{http://www.opengis.net/kml/2.2}Folder") | |
foldername = etree.SubElement(folder, "{http://www.opengis.net/kml/2.2}name") | |
foldername.text = "Trains" | |
folder.append(style) | |
count = 0 | |
for train, events in trains.iteritems(): | |
count += 1 | |
print "Processing train %s" % train | |
trainfolder = etree.SubElement(folder, "{http://www.opengis.net/kml/2.2}Folder") | |
trainfoldername = etree.SubElement(trainfolder, "{http://www.opengis.net/kml/2.2}name") | |
direction = ['Southbound', 'Northbound'][int(events[0]['direction_id'])-1] | |
trainfoldername.text = "%s %s Train %s" % (direction, events[0]['route_id'], events[0]['train_id']) | |
stops = defaultdict(list) | |
for event in events: | |
stops[event['stop_id']].append(event) | |
for stop, stop_events in stops.iteritems(): | |
assert len(stop_events) <= 2 | |
arr = dep = None | |
for event in stop_events: | |
if event['event_type'] == '1': | |
arr = event['timestamp'] | |
if event['event_type'] == '2': | |
dep = event['timestamp'] | |
if arr is None and dep is not None: | |
arr = dep | |
if dep is None and arr is not None: | |
dep = arr | |
placemark = etree.Element("{http://www.opengis.net/kml/2.2}Placemark") | |
name = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}name") | |
name.text = train | |
stop = Stop.query.get(stop) | |
description = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}description") | |
description.text = "%s on track %s" % (stop.stop_name, stop_events[0]['track_id']) | |
point = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}Point") | |
coordinates = etree.SubElement(point, "{http://www.opengis.net/kml/2.2}coordinates") | |
coordinates.text="%s,%s" % (stop.stop_lon, stop.stop_lat) | |
span = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}TimeSpan") | |
begin = etree.SubElement(span, "{http://www.opengis.net/kml/2.2}begin") | |
end = etree.SubElement(span, "{http://www.opengis.net/kml/2.2}end") | |
begin.text = eastern.localize(datetime.strptime(arr, | |
"%Y-%m-%d %H:%M:%S")).astimezone(pytz.utc).strftime("%Y-%m-%dT%H:%M:%SZ") | |
end.text = eastern.localize(datetime.strptime(dep, | |
"%Y-%m-%d %H:%M:%S")).astimezone(pytz.utc).strftime("%Y-%m-%dT%H:%M:%SZ") | |
style = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}styleUrl") | |
style.text = "#train" | |
trainfolder.append(placemark) | |
with file('out.kml', 'w') as outfile: | |
et = etree.ElementTree(kml) | |
et.write(outfile) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from csv import DictReader | |
from collections import defaultdict | |
import xml.etree.ElementTree as etree | |
from datetime import datetime | |
import pytz | |
from gtfs import Schedule | |
from gtfs.entity import Stop | |
eastern = pytz.timezone('US/Eastern') | |
dr = DictReader(open('data.csv')) | |
schedule = Schedule('google_transit.db') | |
trains = defaultdict(list) | |
for row in dr: | |
trains[row['train_id']].append(row) | |
print len(trains) | |
style = etree.fromstring("""<Style id="train" xmlns="http://www.opengis.net/kml/2.2"> | |
<IconStyle> | |
<scale>0.5</scale> | |
<Icon> | |
<href>http://maps.google.com/mapfiles/kml/shapes/rail.png</href> | |
</Icon> | |
</IconStyle> | |
<LabelStyle> | |
<scale>0</scale> | |
</LabelStyle> | |
</Style>""") | |
kml = etree.Element("{http://www.opengis.net/kml/2.2}kml") | |
folder = etree.SubElement(kml, "{http://www.opengis.net/kml/2.2}Folder") | |
foldername = etree.SubElement(folder, "{http://www.opengis.net/kml/2.2}name") | |
foldername.text = "Trains" | |
folder.append(style) | |
count = 0 | |
for train, events in trains.iteritems(): | |
count += 1 | |
print "Processing train %s" % train | |
trainfolder = etree.SubElement(folder, "{http://www.opengis.net/kml/2.2}Folder") | |
trainfoldername = etree.SubElement(trainfolder, "{http://www.opengis.net/kml/2.2}name") | |
direction = ['Southbound', 'Northbound'][int(events[0]['direction_id'])-1] | |
trainfoldername.text = "%s %s Train %s" % (direction, events[0]['route_id'], events[0]['train_id']) | |
for event in events: | |
placemark = etree.Element("{http://www.opengis.net/kml/2.2}Placemark") | |
name = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}name") | |
name.text = train | |
stop = Stop.query.get(event['stop_id']) | |
event_type = ['Arrived at', 'Departed from'][int(event['event_type'])-1] | |
description = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}description") | |
description.text = "%s station %s on track %s" % (event_type, stop.stop_name, event['track_id']) | |
point = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}Point") | |
coordinates = etree.SubElement(point, "{http://www.opengis.net/kml/2.2}coordinates") | |
coordinates.text="%s,%s" % (stop.stop_lon, stop.stop_lat) | |
ts = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}TimeStamp") | |
when = etree.SubElement(ts, "{http://www.opengis.net/kml/2.2}when") | |
dt = eastern.localize(datetime.strptime(event['timestamp'], | |
"%Y-%m-%d %H:%M:%S")) | |
when.text = dt.astimezone(pytz.utc).strftime("%Y-%m-%dT%H:%M:%SZ") | |
style = etree.SubElement(placemark, "{http://www.opengis.net/kml/2.2}styleUrl") | |
style.text = "#train" | |
trainfolder.append(placemark) | |
with file('out.kml', 'w') as outfile: | |
et = etree.ElementTree(kml) | |
et.write(outfile) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Before settling on creating a video with Processing, I tried visualizing the MTA NYCT ATS data by converting it to KML to view in Google Earth. The approach worked so long as I limited the number of trains processed, but when I processed the entire file, the resulting KML (around 25 MB) was so large that Google Earth would choke on it; it never rendered fully, and usually crashed.