Public Transport#
The public transport module currently available on this library allow users to import GTFS feeds into supply models, including map-matching to the road network.
It does not, however, allow for traditional editing of transit networks, such as definition of new routes/services, changes to transit stops or stopping patterns.
Editing triggers#
The transit route system does not have the same level of editing capabilities as the roadway layer, but a series of triggers have been implemented to greatly reduce the amount of unecessary data leftover when deleting transit routes/patterns.
These triggers are the following:
When deleting a route:
Delete all patterns for that route
Delete all transit fare rules specific to that route
When deleting a pattern:
Delete all data from Transit_Pattern_Mapping regarding that pattern
Delete all trips from Transit_Trips for that pattern
Delete all links from Transit_Links for that pattern
Delete the sequence of links from Transit_Pattern_Links for that pattern
When deleting a trip:
Delete all scheduled arrivals and departures for that trip from Transit_Trips_Schedule
GTFS IMPORTER#
Since the main purpose of this model is to import GTFS feeds, key software operations are done on a class capable of reading a GTFS feed and querying it in memory.
You can also read a detailed explanation of the Transit Map-Matching algorithm
- class polaris.network.transit.lib_gtfs.GTFSRouteSystemBuilder(network, agency_id, file_path, day='', description='', capacities: dict | None = None)#
Bases:
WorkerThread
Container for GTFS feeds providing data retrieval for the importer
from polaris.network.network import Network network_path = 'D:/Argonne/GTFS/CHICAGO/chicago2018-Supply.sqlite' GTFS_path = 'D:/Argonne/GTFS/CHICAGO/METRA/2019-10-04.zip' my_network = Network() my_network.open(network_path) transit = my_network.transit() feed = transit.new_gtfs(file_path=GTFS_path description='METRA Commuter Rail', agency_identifier='METRA') # In case you created the feed without providing an agency ID or description feed.set_description('METRA Commuter Air Force') # For a least of all dates covered by this feed feed.dates_available() # If you set it with the wrong feed and want to change it feed.set_feed('D:/Argonne/GTFS/CHICAGO/METRA/2073-12-03.zip') # To prevent map-matching to be performed and execute a faster import feed.set_allow_map_match(False) feed.load_date('2019-10-15') # To save the transit raw-shapes to the database for later consult feed.create_raw_shapes() # To map-match the services in this feed feed.map_match() feed.execute_import()
- signal = <polaris.utils.python_signal.PythonSignal object>#
- __init__(network, agency_id, file_path, day='', description='', capacities: dict | None = None)#
Instantiates a transit class for the network
Args:
polaris network (
Network
): Supply model to which this GTFS will be imported agency_identifier (str
): ID for the agency this feed refers to (e.g. ‘CTA’) file_path (str
): Full path to the GTFS feed (e.g. ‘D:/project/my_gtfs_feed.zip’) day (str
, Optional): Service data contained in this field to be imported (e.g. ‘2019-10-04’) description (str
, Optional): Description for this feed (e.g. ‘CTA19 fixed by John after coffee’)
- archive_dir: str#
- graphs: Dict[int, Any]#
- set_capacities(capacities: dict)#
Sets default capacities for modes/vehicles.
- Args:
- capacities (
dict
): Dictionary with GTFS types as keys, each with a list of 3 items for values for capacities: seated, design and total i.e. -> “{0: [150, 300, 300],…}”
- capacities (
- set_maximum_speeds(max_speeds: DataFrame)#
Sets the maximum speeds to be enforced at segments.
- Args:
max_speeds (
pd.DataFrame
): Requires 4 fields: mode, min_distance, max_distance, speed. Modes not covered in the data will not be touched and distance brackets not covered will receive the maximum speed, with a warning
- dates_available() list #
Returns a list of all dates available for this feed
- Returns:
feed dates (
list
): list of all dates available for this feed
- set_allow_map_match(allow=True)#
Changes behavior for finding transit-link shapes
Defaults to True
- Args:
allow (
bool
optional): If True, allows uses map-matching in search of precise transit_link shapes. If False, sets transit_link shapes equal to straight lines between stops. In the presence of GTFS raw shapes it has no effect.
- map_match(route_types: List[int] | None = None) None #
Performs map-matching for all routes of one or more types
Defaults to map-matching Bus routes (type 3) only For a reference of route types, see https://developers.google.com/transit/gtfs/reference#routestxt
- Args:
route_types (
List[int]
orTuple[int]
): Default is [3], for bus only
- set_agency_identifier(agency_id: str) None #
Adds agency ID to this GTFS for use on import
- Args:
agency_id (
str
): ID for the agency this feed refers to (e.g. ‘CTA’)
- set_feed(feed_path: str) None #
Sets GTFS feed source to be used
- Args:
file_path (
str
): Full path to the GTFS feed (e.g. ‘D:/project/my_gtfs_feed.zip’)
- set_description(description: str) None #
Adds description to be added to the imported layers metadata
- Args:
description (
str
): Description for this feed (e.g. ‘CTA2019 fixed by John Doe after strong coffee’)
- set_date(service_date: str) None #
Sets the date for import without doing any of data processing, which is left for the importer
- load_date(service_date: str) None #
Loads the transit services available for service_date
- Args:
service_date (
str
): Day for which services are to be imported (e.g. ‘2019-10-04’)
- set_do_raw_shapes(do_shapes: bool)#
Sets the raw shapes importer to True for execution by the importer
- create_raw_shapes()#
Adds all shapes provided in the GTFS feeds to the TRANSIT_RAW_SHAPES table in the network file
This table is for debugging purposes, as allows the user to compare it with the result of the map-matching procedure.
All previously existing entries with this feed’s prefix ID are removed. For patterns with no corresponding shape on shapes.txt or in the absence of shapes.txt, the raw shape is generated by connecting stops directly.
- doWork()#
Alias for execute_import
- execute_import()#
- save_to_disk()#
Saves all transit elements built in memory to disk
- finished()#
- builds_link_graphs_with_broken_stops()#
Build the graph for links for a certain mode while splitting the closest links at stops’ projection
- Args:
mode_id (
int
): Mode ID for which we will build the graph for
Container for GTFS feeds providing data retrieval for the importer |
This class is designed to read standard GTFS feeds and might not work with poorly formatted feeds. For more information on GTFS, please refer to GTFS reference documentation.
Import process#
Although bus-on-traffic is not used by default on most of Polaris models, map-matching is still used by default for all routes (not only bus) whenever the GTFS feed being imported lacks route shapes. This is done in order to obtain route and transit_link shapes for display, as the old straight lines are less intuitive to some of those looking at model results.
Since the map-matching process is rather time-consuming, it is possible to turn it off and force the creation of straight-lines in the absence of route shapes with a single line of code
feed.set_allow_map_match(False)
Preventing excess speed#
During the development of multiple Polaris models, we have detected unusually high speeds for a number of route segments. As some of these segment speeds were in excess of 200 mph, a procedure to limit these speeds was put in place.
The process consists of delaying the arrival at a stop (and consequently at all subsequent stops in that trip) any time the segment speed is below a certain threshold.
The use of posted speeds is, however, impossible at that stage of the import process, as the route is yet to be map-matched to the network. For this reason, data analysis was conducted for all networks currently in existence to determine the threshold speeds to be used.
In time, these threshold speeds are mode-specific and vary according to the length of the route segment as to account for express routes.
As the distribution of segment lengths is likely to change significantly across modes and urban areas, the analysis was made for 20 bins with equal number of elements for each model/mode, rounded to the nearest 5m. We understand that this approach may cut off a possibly long tail for the segment length distribution, but we do not believe that this will have substantial effect on the GTFS processing outcome.
Chicago#
Chicago has routes for 3 GTFS modes, as follows:
GTFS mode 1 (Subway/metro)#
There are no clearly absurd route speeds, but some substantially higher speeds for the 99.5% percentile suggest that imposing some lower limits might be necessary.
Looking at the charts we have established that the appropriate speed limits to be imposed on import were approximate the following.
From Length |
to length |
Percentile |
Speed (mph) |
0 |
365 |
0.975 |
~21.9 |
365 |
480 |
0.975 |
~18.5 |
480 |
705 |
0.975 |
~23.3 |
705 |
785 |
0.975 |
~29.0 |
785 |
855 |
0.975 |
~31.3 |
855 |
1,020 |
0.985 |
~32.0 |
1,020 |
1,285 |
0.975 |
~31.9 |
1,285 |
1,600 |
0.980 |
~36.5 |
1,600 |
1,755 |
0.985 |
~39.5 |
1,755 |
MAX |
0.975 |
~55.5 |
There is a somewhat constant low maximum speed for segments shorter than 705m and another plateau of speed between 700 and 1,775m, so we simplify the table as follows:
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
700 |
0.970 |
22.9 |
10.2 |
700 |
1,285 |
0.970 |
31.3 |
14.0 |
1,285 |
MAX |
0.985 |
36.4 |
16.3 |
GTFS mode 2 (Suburban rail)#
From Length |
to length |
Percentile |
Speed (mph) |
0 |
815 |
0.975 |
~30.3 |
815 |
935 |
0.975 |
~33.2 |
935 |
1,430 |
0.975 |
~42.5 |
1,430 |
1,955 |
0.975 |
~37.0 |
1,955 |
2,405 |
0.975 |
~37.0 |
2,405 |
2,965 |
0.975 |
~37.0 |
2,965 |
3,885 |
0.970 |
~43.5 |
3,885 |
5,070 |
0.975 |
~53.0 |
5,070 |
8,500 |
0.975 |
~49.0 |
8,500 |
MAX |
0.975 |
~53.5 |
The variability for these modes is a little more extreme than for the other two, but we can establish a difference in general pattern for segments under 935m between 935 and 3,885 and over 3,885m. The resulting simplified limit table is:
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
1,000 |
0.975 |
31.6 |
14.1 |
1,000 |
4,000 |
0.975 |
42.5 |
19.0 |
4,000 |
MAX |
0.975 |
52.6 |
23.5 |
GTFS mode 3 (Bus)#
From Length |
to length |
Percentile |
Speed |
0 |
120 |
0.975 |
~23.0 |
120 |
155 |
0.970 |
~23.0 |
155 |
180 |
0.975 |
~23.0 |
180 |
195 |
0.975 |
~23.0 |
195 |
205 |
0.985 |
~23.0 |
205 |
210 |
0.985 |
~23.5 |
210 |
235 |
0.985 |
~26.0 |
235 |
270 |
0.970 |
~27.5 |
270 |
370 |
0.955 |
~31.0 |
370 |
MAX |
0.985 |
~49.0 |
As there is a clear constant pattern for maximum speed for the segments up to 210m, we have simplified the table and retrieved the precise values for the percentiles above.
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
210 |
0.975 |
22.7 |
10.2 |
210 |
270 |
0.975 |
26.9 |
12.0 |
270 |
370 |
0.955 |
30.4 |
13.6 |
370 |
MAX |
0.975 |
49.0 |
21.9 |
Atlanta#
Atlanta also has routes for 3 GTFS modes, as follows:
GTFS mode 0 (Tram/Light rail)#
The maximum speeds for light rail segments for Atlanta are incredibly well behaved, so we will use the maximum available speed (12.8 mph) as the threshold across all distance brackets:
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
MAX |
1.000 |
12.9 |
5.8 |
GTFS mode 1 (Subway/metro)#
The maximum speeds for rail/metro segments for Atlanta are also incredibly well behaved, so we will use only a few brackets to threshold across all distance brackets:
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
705 |
0.975 |
24.5 |
11.0 |
705 |
3,000 |
0.975 |
46.1 |
20.6 |
3,000 |
MAX |
0.985 |
53.3 |
23.8 |
GTFS mode 3 (Bus)#
From Length |
to length |
Percentile |
Speed |
0 |
130 |
0.985 |
~23.0 |
130 |
160 |
0.985 |
~25.0 |
160 |
190 |
0.975 |
~23.8 |
190 |
220 |
0.975 |
~23.8 |
220 |
250 |
0.975 |
~24.0 |
250 |
285 |
0.980 |
~24.5 |
285 |
325 |
0.970 |
~23.5 |
325 |
385 |
0.975 |
~25.5 |
385 |
500 |
0.985 |
~26.0 |
500 |
MAX |
0.975 |
~31.0 |
There are basically three distance segments that should be interpreted independently, which are consolidated below:
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
325 |
0.975 |
23.6 |
10.6 |
325 |
500 |
0.975 |
25.2 |
11.3 |
500 |
MAX |
0.985 |
29.4 |
13.1 |
Campo#
The Austin metro model has routes for 2 GTFS modes, as follows:
GTFS mode 0 (Tram/Light rail)#
The maximum speeds for light rail segments for Austin are pretty well behaved, but also very choppy. For this reason, we have decided to use 4 distance brackets of equal size and loosely correlated with what we see on the charts above and stipulated that the quantile to use is 0.975, as that is often the point where speeds tend to start becoming unreasonable in other cities.
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
2,500 |
0.975 |
15.1 |
6.8 |
2,500 |
5,000 |
0.975 |
16.5 |
7.4 |
5,000 |
10,000 |
0.975 |
32.8 |
14.7 |
10,000 |
MAX |
0.975 |
38.6 |
17.3 |
GTFS mode 3 (Bus)#
The behavior for transit speeds for Bus in Campo follows the example for Chicago, where some clearly absurd speeds are recorded as maximum for different distance brackets.
From Length |
to length |
Percentile |
Speed |
0 |
165 |
0.975 |
~24.2 |
165 |
215 |
0.985 |
~21.0 |
215 |
255 |
0.980 |
~20.5 |
255 |
305 |
0.975 |
~20.5 |
305 |
350 |
0.975 |
~20.5 |
350 |
400 |
0.980 |
~21.5 |
400 |
465 |
0.975 |
~20.5 |
465 |
575 |
0.980 |
~22.0 |
575 |
860 |
0.975 |
~22.5 |
860 |
MAX |
0.985 |
~26.5 |
Different than Chicago, however, the constant maximum speed pattern is observed for most of the distance segment brackets, which suggests three different brackets to be used:
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
600 |
0.975 |
21.4 |
9.6 |
600 |
1,000 |
0.975 |
22.6 |
10.1 |
1,000 |
MAX |
0.985 |
26.6 |
11.9 |
Detroit#
The Detroit model has routes for 2 GTFS modes, as follows:
GTFS mode 0 (Tram/Light rail)#
The maximum speeds for light rail segments for Detroit are pretty well behaved throughout all segment distance brackets, so we have established a unique maximum speed to be applied for all segments and equal to the maximum speed registered in the dataset.
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
MAX |
1.000 |
9.7 |
4.3 |
GTFS mode 3 (Bus)#
Again, Bus presents the most inconsistencies with regards to maximum speeds.
From Length |
to length |
Percentile |
Speed |
0 |
160 |
0.97 |
~21.0 |
160 |
185 |
0.975 |
~26.0 |
185 |
200 |
0.975 |
~28.0 |
200 |
220 |
0.965 |
~25.0 |
220 |
245 |
0.965 |
~27.0 |
245 |
275 |
0.985 |
~31.2 |
275 |
305 |
0.980 |
~34.1 |
305 |
355 |
0.985 |
~39.0 |
355 |
440 |
0.975 |
~45.0 |
440 |
MAX |
0.970 |
~53.0 |
Different than other cities, Detroit speeds increase gradually for growing segment length brackets, and therefore the limits set for it must recognize that, resulting in 6 segment length brackets.
From Length |
to length |
Percentile |
Speed (mph) |
Speed (m/s) |
0 |
160 |
0.975 |
22.4 |
10.0 |
160 |
245 |
0.975 |
27.5 |
12.3 |
245 |
305 |
0.985 |
33.9 |
15.2 |
305 |
355 |
0.985 |
39.5 |
17.7 |
355 |
440 |
0.975 |
44.9 |
20.1 |
440 |
MAX |
0.970 |
53.2 |
23.7 |
Other cities#
For all other cities, the limits to be observed are the following
GTFS mode 0 (Tram/Light rail)#
From Length |
to length |
Source |
Speed (mph) |
Speed (m/s) |
0 |
MAX |
Atlanta |
12.9 |
5.8 |
GTFS mode 1 (Subway/metro)#
From Length |
to length |
Source |
Speed (mph) |
Speed (m/s) |
0 |
705 |
Atlanta |
24.5 |
11.0 |
705 |
3,000 |
Atlanta |
46.1 |
20.6 |
3,000 |
MAX |
Atlanta |
53.3 |
23.8 |
GTFS mode 3 (Bus)#
From Length |
to length |
Source |
Speed (mph) |
Speed (m/s) |
0 |
325 |
Atlanta |
23.6 |
10.6 |
325 |
500 |
Atlanta |
25.2 |
11.3 |
500 |
MAX |
Atlanta |
29.4 |
13.1 |
Map-matching#
Due to the complex nature of the Map-matching procedure, particularly in face of the fact that the network models are simplified and often do not include roadways in which there are active transit services, access to the GTFS importer components might be needed for debugging and/or detailed analysis purposes.
As the importer improves this need should disappear, but the documentation of this component is crucial also to understand its impacts on the final model results.
Represents a stop pattern for a particular route, as defined in GTFS |
Although not relevant during regular software use, the other classes employed by the GTFS importer are documented below in order to aid debugging.
Post-Import processes#
Building walk and bike networks is necessary in order to ensure access and connectivity to the transit network, but needs to be explicitly executed.
GTFS EXPORTER#
The Polaris GTFS exporter is designed to pass the minimum requirements of the standard, and is continuously tested against the MobilityData validator.
To meet these requirements while generating GTFS feeds with as much of the original data as possible, a few simplifications/assumptions are made to each of the tables.
As a standard, all transit geo-data is converted to WGS84.
Agencies#
All agencies available in the model are included in the same GTFS feed, and the agency.txt file can therefore have multiple records. The timezone adopted for ALL agencies is the same
The timezone used for ALL agencies is obtained from an online service for the geographic center of the model zones. If no data can be retrieved, the timezone for Chicago is used. This exception, however, is not used when testing the software, which guarantees the resource should be robust.
An agency URL is also required, and we used the Polaris website as the placeholder.
Routes#
The Process of building route systems for Polaris replaces the route ID with an internal ID does not correspond to the ID in the source GTFS used to build the Polaris Transit Route System.
For this reason, and to as much of the original data as possible, the original ID information is concatenated with the route description when the data is exported, which gets formatted as a json.
Shapes#
The cumulative segment distances are kept in meters, despite the use of WGS84 for the point coordinates.