Add train route distance info
This commit is contained in:
parent
5964899a00
commit
8ef67e0cee
|
@ -1,12 +1,14 @@
|
||||||
"""Travel."""
|
"""Travel."""
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
import yaml
|
import yaml
|
||||||
|
from geopy.distance import geodesic
|
||||||
|
|
||||||
from .types import Event
|
from .types import Event, StrDict
|
||||||
|
|
||||||
Leg = dict[str, str]
|
Leg = dict[str, str]
|
||||||
|
|
||||||
|
@ -63,3 +65,47 @@ def flight_number(flight: Leg) -> str:
|
||||||
def all_events(data_dir: str) -> list[Event]:
|
def all_events(data_dir: str) -> list[Event]:
|
||||||
"""Get all flights and rail journeys."""
|
"""Get all flights and rail journeys."""
|
||||||
return get_trains(data_dir) + get_flights(data_dir)
|
return get_trains(data_dir) + get_flights(data_dir)
|
||||||
|
|
||||||
|
|
||||||
|
RouteDistances = dict[tuple[str, str], float]
|
||||||
|
|
||||||
|
|
||||||
|
def train_leg_distance(geojson_data: StrDict) -> float:
|
||||||
|
"""Calculate the total length of a LineString in kilometers from GeoJSON data."""
|
||||||
|
# Extract coordinates
|
||||||
|
first_object = geojson_data["features"][0]["geometry"]
|
||||||
|
assert first_object["type"] in ("LineString", "MultiLineString")
|
||||||
|
|
||||||
|
if first_object["type"] == "LineString":
|
||||||
|
coord_list = [first_object["coordinates"]]
|
||||||
|
else:
|
||||||
|
first_object["type"] == "MultiLineString"
|
||||||
|
coord_list = first_object["coordinates"]
|
||||||
|
# pprint(coordinates)
|
||||||
|
|
||||||
|
total_length_km = 0.0
|
||||||
|
|
||||||
|
for coordinates in coord_list:
|
||||||
|
total_length_km += sum(
|
||||||
|
float(geodesic(coordinates[i], coordinates[i + 1]).km)
|
||||||
|
for i in range(len(coordinates) - 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
return total_length_km
|
||||||
|
|
||||||
|
|
||||||
|
def load_route_distances(data_dir: str) -> RouteDistances:
|
||||||
|
"""Load cache of route distances."""
|
||||||
|
route_distances: RouteDistances = {}
|
||||||
|
with open(os.path.join(data_dir, "route_distances.json")) as f:
|
||||||
|
for s1, s2, dist in json.load(f):
|
||||||
|
route_distances[(s1, s2)] = dist
|
||||||
|
|
||||||
|
return route_distances
|
||||||
|
|
||||||
|
|
||||||
|
def add_leg_route_distance(leg: StrDict, route_distances: RouteDistances) -> None:
|
||||||
|
s1, s2 = sorted([leg["from"], leg["to"]])
|
||||||
|
dist = route_distances.get((s1, s2))
|
||||||
|
if dist:
|
||||||
|
leg["distance"] = dist
|
||||||
|
|
|
@ -98,6 +98,8 @@
|
||||||
| <a href="https://uk.flightaware.com/live/flight/{{ full_flight_number | replace("U2", "EZY") }}">FlightAware</a>
|
| <a href="https://uk.flightaware.com/live/flight/{{ full_flight_number | replace("U2", "EZY") }}">FlightAware</a>
|
||||||
| <a href="{{ radarbox_url }}">radarbox</a>
|
| <a href="{{ radarbox_url }}">radarbox</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid-item">
|
||||||
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro train_row(item) %}
|
{% macro train_row(item) %}
|
||||||
|
@ -131,4 +133,9 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid-item text-end">
|
||||||
|
{% if item.distance %}
|
||||||
|
{{ "{:.1f} km / {:.1f} miles".format(item.distance, item.distance / 1.60934) }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
<style>
|
<style>
|
||||||
.grid-container {
|
.grid-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(8, auto);
|
grid-template-columns: repeat(9, auto);
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.train-grid-container {
|
.train-grid-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(8, auto);
|
grid-template-columns: repeat(9, auto);
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
{% set conference_column_count = 7 %}
|
{% set conference_column_count = 7 %}
|
||||||
{% set accommodation_column_count = 7 %}
|
{% set accommodation_column_count = 7 %}
|
||||||
{% set travel_column_count = 8 %}
|
{% set travel_column_count = 9 %}
|
||||||
<style>
|
<style>
|
||||||
.conferences {
|
.conferences {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
{% set conference_column_count = 7 %}
|
{% set conference_column_count = 7 %}
|
||||||
{% set accommodation_column_count = 7 %}
|
{% set accommodation_column_count = 7 %}
|
||||||
{% set travel_column_count = 8 %}
|
{% set travel_column_count = 9 %}
|
||||||
<style>
|
<style>
|
||||||
.conferences {
|
.conferences {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
14
web_view.py
14
web_view.py
|
@ -117,6 +117,15 @@ def travel_list() -> str:
|
||||||
if isinstance(item["depart"], datetime)
|
if isinstance(item["depart"], datetime)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
route_distances = agenda.travel.load_route_distances(app.config["DATA_DIR"])
|
||||||
|
|
||||||
|
for train in trains:
|
||||||
|
for leg in train["legs"]:
|
||||||
|
agenda.travel.add_leg_route_distance(leg, route_distances)
|
||||||
|
|
||||||
|
if all("distance" in leg for leg in train["legs"]):
|
||||||
|
train["distance"] = sum(leg["distance"] for leg in train["legs"])
|
||||||
|
|
||||||
return flask.render_template("travel.html", flights=flights, trains=trains)
|
return flask.render_template("travel.html", flights=flights, trains=trains)
|
||||||
|
|
||||||
|
|
||||||
|
@ -300,7 +309,6 @@ def human_readable_delta(future_date: date) -> str | None:
|
||||||
@app.route("/trip/<start>")
|
@app.route("/trip/<start>")
|
||||||
def trip_page(start: str) -> str:
|
def trip_page(start: str) -> str:
|
||||||
"""Individual trip page."""
|
"""Individual trip page."""
|
||||||
|
|
||||||
trip_list = [
|
trip_list = [
|
||||||
trip
|
trip
|
||||||
for trip in agenda.trip.build_trip_list()
|
for trip in agenda.trip.build_trip_list()
|
||||||
|
@ -341,7 +349,9 @@ def trip_page(start: str) -> str:
|
||||||
|
|
||||||
for route in routes:
|
for route in routes:
|
||||||
if "geojson_filename" in route:
|
if "geojson_filename" in route:
|
||||||
route["geojson"] = agenda.trip.read_geojson(route.pop("geojson_filename"))
|
route["geojson"] = agenda.trip.read_geojson(
|
||||||
|
app.config["PERSONAL_DATA"], route.pop("geojson_filename")
|
||||||
|
)
|
||||||
|
|
||||||
if trip.end:
|
if trip.end:
|
||||||
countries = {c.alpha_2 for c in trip.countries}
|
countries = {c.alpha_2 for c in trip.countries}
|
||||||
|
|
Loading…
Reference in a new issue