Skip to content

Instantly share code, notes, and snippets.

@parthibanloganathan
Last active July 22, 2016 17:48
Show Gist options
  • Save parthibanloganathan/5873710 to your computer and use it in GitHub Desktop.
Save parthibanloganathan/5873710 to your computer and use it in GitHub Desktop.
Subway Info widget for Dashing

Subway Info

##Preview

Screenshot 1: https://raw.github.com/parthibanloganathan/dashing_widgets/master/public/mta1.png Screenshot 2: https://raw.github.com/parthibanloganathan/dashing_widgets/master/public/mta2.png

Description

Subway Info is a Dashing widget which displays information on trains in New York City. Information includes train line, direction, station and arrival time. You can customize it to include any combination of lines and stations. This may also be used in other cities as well if you have the appropriate GTFS files.

##Dependencies

Add the following gem to the Gemfile:

gem 'gtfs'

and run bundle install.

##Usage

To use the widget, copy mta.rb to the /jobs folder. Create a folder called mta under /widgets. Copy mta.coffee, mta.html and mta.scss into /widgets/mta.

Add the following code snippet to your dashboard .erb file under /dashboards:

<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
   <div data-id="mta" data-view="Mta"></div>
</li>

##Settings

This widget allows you to specify the stops and lines of interest to you. Specify these as strings in the arrays target_stops and target_lines. Please limit the number of stops and lines. For example, this widget was tested with 2 stations with 2 lines each.

You can also specify the refresh time for the display, the interval between data updates and how far in the future to look for incoming trains.

Look at the comments at the beginning of the job mta.rb to learn more about customizing the widget.

Note: The widget may be used with other GTFS files too. This is not restricted to New York City. Keep in mind that this has only been tested with GTFS data from the MTA.

To use your own GTFS file, replace the URL to the zip file in the following line:

  $source = GTFS::Source.build('http://www.mta.info/developers/data/nyct/subway/google_transit.zip')

Add your desired URL instead.

####Note: If you would like to use the train line images instead of numbers, use the following mta.coffee and mta.html. Also download the images (1, 2, 3, 4, 5, 6, A, C, E, N, Q, R) from here into the folder /public.

##Warnings

This widget takes around one minute to load on startup. Be patient. Once it starts, the widget is quick and responsive. The job must download and parse a GTFS file from the MTA. The file can be found at the MTA Developer downloads page. To access, click New York City Transit Subway under static data feeds. The GTFS files are updated by the MTA every so often. This widget checks for an update every 24 hours or every time the dashboard's host server starts Dashing.

class Dashing.Mta extends Dashing.Widget
<p class="line" data-bind="line"></p>
<p class="name" data-bind="name"></p>
<p class="time" data-bind="time"></p>
<p class="direction" data-bind="direction"></p>
require 'gtfs'
require 'time'
# Add the stations and lines you want to get updates on
# Example:
# target_stops = ['116 St - Columbia University', '8 St - NYU']
# target_lines = ['1','2','N']
# This will give you info on the trains on the 1, 2 and N at 116th St - Columbia University and 8 St - NYU
# You can get these names by downloading http://www.mta.info/developers/data/nyct/subway/google_transit.zip and
# checking for valid stop names under the file called 'stops'
target_stops = [INSERT STOPS HERE]
target_lines = [INSERT LINES HERE]
# Change the refresh times if needed
# Updates list of trains arriving in the next 5 minutes (TIME) every 1 minute (UPDATE).
# Displays a particular train/stop combination data for 3 seconds (DISPLAY) before cycling to another
UPDATE = '1m'
TIME = 5 # Note that this is an integer, not a string (represents minutes)
DISPLAY = '3s'
request_flag = false
send_flag = false
source = nil
final_hash = Array.new
my_stop_ids = Array.new
stop_hash = Array.new
index = 0
stop_times = Array.new
# Retrieves GTFS data and builds primary data with lines of interest
SCHEDULER.every '24h', :first_in => 0 do |job|
# Defaults to strict checking of required columns
source = GTFS::Source.build('http://www.mta.info/developers/data/nyct/subway/google_transit.zip')
# Get stop_ids of our stops of interest (these are listed in the array target_stops)
source.stops.each do |stop|
if target_stops.include? stop.name
target_stop = Hash.new
target_stop['name'] = stop.name
target_stop['id'] = stop.id
stop_hash.push(target_stop)
my_stop_ids.push(stop.id)
end
end
# Get stop_times at stops with our stop_ids
stop_times = source.stop_times.select { |stop_time| my_stop_ids.include? stop_time.stop_id }
# Set request_flag to true so that we can start calculating schedules
request_flag = true
end
# Calculates trains leaving in the next few minutes which stop at the target_stations
SCHEDULER.every UPDATE, :first_in => '5s' do |job|
if request_flag == true
send_flag = false
final_hash = Array.new
# Get stop_times from our stops with trains departing in the next 10 minutes
stop_times.each do |stop_time|
split_dept_time = stop_time.departure_time.split(':')
dept_time = (3600*split_dept_time[0].to_i) + (60*split_dept_time[1].to_i) + (split_dept_time[2].to_i)
time = Time.now.to_a
now = 3600*time[2] + 60*time[1] + time[0]
# Time difference in seconds
diff = dept_time - now
# If train leaves in next 5 minutes
if 0 < diff && diff < TIME*60
# Get line and direction based on trip_id
# Then form objects containing final data to display
selected_trip = source.trips.select { |trip| trip.id == stop_time.trip_id }
# If line is one of our target lines, create data object
if target_lines.include? selected_trip[0].route_id
final_object = Hash.new
stop = stop_hash.select { |hashed_stop| hashed_stop['id'] == stop_time.stop_id }
final_object['name'] = stop[0]['name']
# There are numbers 1 and 0 before the time strings
# becausse we need to sort objects by time later.
# This is a hack, and needs to be refined.
mins = diff/60
if mins == 0
final_object['time'] = '0Leaving now'
elsif mins == 1
final_object['time'] = "1Arrives in #{mins} min"
else
final_object['time'] = "1Arrives in #{mins} mins"
end
final_object['line'] = selected_trip[0].route_id
final_object['direction'] = selected_trip[0].headsign
final_hash.push(final_object)
end
end
send_flag = true
final_hash.sort! { |obj1, obj2| obj1['time'] <=> obj2['time'] }
end
end
end
# Displays train/stop info, and cycles through the different data
SCHEDULER.every DISPLAY, :first_in => '5s' do |job|
line = ''
name = 'Loading'
direction = ''
time = ''
if send_flag == true
if index >= final_hash.size
index = 0
end
if final_hash.size > 0
line = final_hash[index]['line']
name = final_hash[index]['name']
direction = final_hash[index]['direction']
size = final_hash[index]['time'].size
time = final_hash[index]['time'][1..size]
end
index = index + 1
end
send_event('mta', {line: line, name: name, direction: direction, time: time})
end
// ----------------------------------------------------------------------------
// Sass declarations
// ----------------------------------------------------------------------------
$background-color: #FF9D00;
$text-color: #FFFDA3;
// ----------------------------------------------------------------------------
// Widget-text styles
// ----------------------------------------------------------------------------
.widget-mta {
background-color: $background-color;
.line {
font-size: 270%;
color: $text-color;
}
.name {
font-size: 140%;
color: $text-color;
}
.direction {
font-size: 100%;
color: $text-color;
}
.time {
font-size: 200%;
color: $text-color;
}
}
@jamesposs
Copy link

I had this working perfectly with MARTAs GTFS file. All of a sudden it will not work, even after a clean install.
Does anyone have any ideas?

scheduler caught exception: No such file or directory - /tmp/d20131216-12947-u2xra8/gtfs_Dec13/agency.txt /var/lib/gems/1.9.1/gems/gtfs-0.2.1/lib/gtfs/url_source.rb:18:in `rescue in load_archive' /var/lib/gems/1.9.1/gems/gtfs-0.2.1/lib/gtfs/url_source.rb:8:in`load_archive' /var/lib/gems/1.9.1/gems/gtfs-0.2.1/lib/gtfs/source.rb:25:in `initialize' /var/lib/gems/1.9.1/gems/gtfs-0.2.1/lib/gtfs/source.rb:48:in`new' /var/lib/gems/1.9.1/gems/gtfs-0.2.1/lib/gtfs/source.rb:48:in `build' /home/dash/dashboard/jobs/mta.rb:37:in`block in ' /var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/jobs.rb:230:in `call' /var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/jobs.rb:230:in`trigger_block' /var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/jobs.rb:204:in `block in trigger' /var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/scheduler.rb:430:in`call' /var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/scheduler.rb:430:in `block in trigger_job'

@McBadass
Copy link

First off, this is an awesome dashboard widget. I was able to configure it to work with Denver RTD, so thanks for the great foundation.

I am, however, seeing a whole lot of "Loading..." after it first updates. It shows a single train stop status, and then after that goes to loading for a long time (unless I'm just missing the brief stop statuses).

Here are my configuration settings for Denver RTD:

target_stops = ['Englewood Station']
target_lines = ['101C', '101D']

Here is the gtfs source I'm using: http://www.rtd-denver.com/GoogleFeeder/google_transit_Jan14_Runboard.zip

Any ideas? I'm planning on forking this to a Denver specific dashboard widget once I get this figured out.

@dennym
Copy link

dennym commented May 22, 2014

Isnt it missing some coffee magic? How does the send_event know that is supposed to send the line, direction, etc to the paragraphs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment