Skip to content

Commit

Permalink
Return docstrings of backend endpoint functions; also add docstrings (#…
Browse files Browse the repository at this point in the history
…163)

* return docstrings of endpoint functions

* add docstrings

* further flesh out documentation

* mention backend in main readme

* clarify DoW example

* change numeric to float

* note who does the routing

* mention dependency

* describe argument
  • Loading branch information
Nate-Wessel authored Dec 3, 2024
1 parent 8f557f0 commit 2d2a607
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 12 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ The Travel Time Request App is a simple web application designed to help City st
This app was originally developed as a [class project by U of T students](https://www.youtube.com/watch?v=y6lnefduogo) in partnership with the City, though it has undergone substantial development by the Data & Analytics Unit since then.

## How to use the app

### Via the front-end user-interface

When you [visit the app](https://trans-bdit.intra.prod-toronto.ca/traveltime-request/), you will be prompted to add/create at least one of each of the following:
* a corridor, drawn on the map
* a time range, given in hours of the day, 00 - 23
Expand All @@ -21,7 +24,7 @@ Once each factor type has been validly entered it will turn from red to green. O

If you have any trouble using the app, please send an email to Nate Wessel ([email protected]) or feel free to open an issue in this repository if you are at all familiar with that process.

## Outputs
#### Outputs

The app can return results in either CSV or JSON format. The fields in either case are the same:

Expand All @@ -40,6 +43,11 @@ The app can return results in either CSV or JSON format. The fields in either ca
| `mean_travel_time_minutes` | The mean travel time in minutes is given as a floating point number rounded to three decimal places. Where insufficient data was available to complete the request, the value will be null. |
| `mean_travel_time_seconds` | Same as above, but measured in seconds. |

### By querying the back-end API directly

The front-end UI pulls all data from the backend service available at https://trans-bdit.intra.prod-toronto.ca/tt-request-backend/. This API defines several endpoints, all of which return JSON-structured data. Those endpoints are documented at the link above.

Generally, the API returns much more data than is available through the UI and this allows some extended use-cases which are just starting to be documented in the [`analysis/`](./analysis) folder. These may include looking at travel time variability within a given window and conducting statistical comparisons between different time periods.

## Methodology

Expand All @@ -59,7 +67,7 @@ We aggregate corridors together spatially as necessary into larger corridors whe

### Other means of estimating travel times

The City also has [bluetooth sensors](https://github.com/CityofToronto/bdit_data-sources/blob/master/bluetooth/README.md) at some intersections which can be used to get a more reliable measure of travel time. These sensors pick up a much larger proportion of vehicles than the HERE data, making it possible to do a temporally fine-grained analysis. The sensors however are only in a few locations, especially in the downtown core and along the Gardiner and DVP expressways.
The City also has [bluetooth sensors](https://github.com/CityofToronto/bdit_data-sources/blob/master/bluetooth/README.md) at some intersections which can be used to get a more reliable measure of travel time. These sensors pick up a much larger proportion of vehicles than the HERE data, making it possible to do a temporally fine-grained analysis. The sensors however are only in a few locations, especially in the downtown core and along the Gardiner and DVP expressways.

## Development

Expand Down
62 changes: 52 additions & 10 deletions backend/app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,32 @@

@app.route('/')
def index():
"""Provide basic documentation about the available resources.
All endpoints return JSON-formatted data.
"""
return jsonify({
'description': 'Travel Time App backend root',
'endpoints': [str(rule) for rule in app.url_map.iter_rules()]
'description': 'Travel Time App backend',
'available_endpoints': [
{
'path': str(rule),
'docstring': app.view_functions[rule.endpoint].__doc__
} for rule in app.url_map.iter_rules()
]
})

# test URL /closest-node/-79.3400/43.6610
@app.route('/nodes-within/<meters>/<longitude>/<latitude>', methods=['GET'])
def closest_node(meters,longitude,latitude):
def closest_node(meters, longitude, latitude):
"""Return up to 20 nodes within a given radius (in meters) of a point.
Nodes are drawn from the Congestion Network, i.e. are fairly major intersections.
Arguments:
meters (float): distance around latitude and longitude to search
latitude (float): latitude of point to search around
longitude (float): longitude of point to search around
"""
try:
longitude = float(longitude)
latitude = float(latitude)
Expand All @@ -30,6 +48,13 @@ def closest_node(meters,longitude,latitude):
# test URL /node/30357505
@app.route('/node/<node_id>', methods=['GET'])
def node(node_id):
"""Returns information about a given node in the Here street network.
This uses the latest map version and may not recognize an older node_id.
arguments:
node_id (int): identifier of the node in the latest Here map version
"""
try:
node_id = int(node_id)
except:
Expand All @@ -40,7 +65,11 @@ def node(node_id):
#shell function - outputs json for use on frontend
@app.route('/link-nodes/<from_node_id>/<to_node_id>', methods=['GET'])
def get_links_between_two_nodes(from_node_id, to_node_id):
"""Returns links of the shortest path between two nodes on the HERE network"""
"""Returns links of the shortest path between any two nodes on the HERE network.
Results include link_dir IDs, link geometries, and lengths in meters.
Routing is done in PostgreSQL using `here_gis.get_links_btwn_nodes_{map_version}`
"""
try:
from_node_id = int(from_node_id)
to_node_id = int(to_node_id)
Expand Down Expand Up @@ -73,12 +102,21 @@ def get_links_between_two_nodes(from_node_id, to_node_id):
'/aggregate-travel-times/<start_node>/<end_node>/<start_time>/<end_time>/<start_date>/<end_date>/<include_holidays>/<dow_str>',
methods=['GET']
)
# - start_node, end_node (int): the congestion network / HERE node_id's
# - start_time, end_time (int): starting (inclusive), ending (exclusive) hours of aggregation
# - start_date, end_date (YYYY-MM-DD): start (inclusive), end (exclusive) date of aggregation
# - include_holidays(str, boolean-ish): 'true' will include holidays
# - dow_list(str): flattened list of integers, i.e. [1,2,3,4] -> '1234', representing days of week to be included (ISODOW)
def aggregate_travel_times(start_node, end_node, start_time, end_time, start_date, end_date, include_holidays, dow_str):
"""
Return averaged travel times given the specified parameters.
This function just parses arguments and otherwise wraps around `get_travel_times` which does the actual work...
Aggregates travel times, returning averaged travel times along the selected corridor during the specified dates and times.
Also returns some helpful diagnostic data such as the parsed query args, the route identified between the nodes, and some measures of sampling error.
Arguments:
start_node, end_node (int): HERE network node_id's from the current Here map version
start_time, end_time (int): starting (inclusive), ending (exclusive) hours. May include leading zeros. If the end_time is less than the start_time, the time will wrap midnight.
start_date, end_date (str, YYYY-MM-DD): start (inclusive), end (exclusive) dates. end_date must be greater than start_date.
include_holidays (str, boolean): 'true' will include holidays, 'false' will exclude them if applicable
dow_list (str): concatenated list of integers representing days of week to be included; ISODOW specification. E.g. [6,7] -> '67' for Saturday and Sunday only.
"""
try:
start_node = int(start_node)
end_node = int(end_node)
Expand Down Expand Up @@ -116,6 +154,7 @@ def aggregate_travel_times(start_node, end_node, start_time, end_time, start_dat
# test URL /date-bounds
@app.route('/date-range', methods=['GET'])
def get_date_bounds():
"""Returns the dates of the earliest and latest available travel time data."""
connection = getConnection()
with connection:
with connection.cursor() as cursor:
Expand All @@ -130,7 +169,10 @@ def get_date_bounds():
# test URL /holidays
@app.route('/holidays', methods=['GET'])
def get_holidays():
"Return dates of all known holidays in ascending order"
"""Return dates of all Ontario holidays in ascending order.
Holidays will fully cover the range of any available travel time data.
"""
connection = getConnection()
query = f"""
SELECT
Expand Down

0 comments on commit 2d2a607

Please sign in to comment.