2A.eco - Exercice API SNCF corrigé¶
Links: notebook
, html, PDF
, python
, slides, GitHub
Manipulation d’une API REST, celle de la SNCF est prise comme exemple. Correction d’exercices.
from jyquickhelper import add_notebook_menu
add_notebook_menu()
Partie 0 - modules recommandés et connexion à l’API¶
Il vous faudra sûrement les modules suivant :
requests
datetime
pandas
matplotlib
Créer un login pour vous connecter à l’API de la SNCF https://data.sncf.com/api
Vous pouvez maintenant commencer. Ce notebook peut prendre du temps à s’éxécuter, surout à partir de la partie 3
# !!!!! Attention à bien mettre votre token ici !!!!!
token_auth = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
import os
from pyquickhelper.loghelper import get_password
if "XXXXXX" in token_auth:
token_auth = get_password("sncf", "ensae_teaching_cs,key")
Partie 1 - Trouver les gares accessibles via la SNCF¶
Trouver l’ensemble des gares disponibles sur l’API et créer un fichier csv avec les codes de la gare, son nom et ses coordonnées latitude et longitude, ainsi que les informations administratives de la région quand elles sont disponibles
Représentez les sur un graphique
import pandas as pd
import requests
def page_gares(numero_page) :
return requests.get(
('https://api.sncf.com/v1/coverage/sncf/stop_areas?start_page={}').format(numero_page),
auth=(token_auth, ''))
######################################
# on commence par la première page qui nous donne le nombre de résultats par page ainsi que le nombre total de résultats
page_initiale = page_gares(0)
item_per_page = page_initiale.json()['pagination']['items_per_page']
total_items = page_initiale.json()['pagination']['total_result']
dfs = []
# on fait une boucle sur toutes les pages suivantes
print_done = {}
for page in range(int(total_items/item_per_page)+1) :
stations_page = page_gares(page)
ensemble_stations = stations_page.json()
if 'stop_areas' not in ensemble_stations:
# pas d'arrêt
continue
# on ne retient que les informations qui nous intéressent
for station in ensemble_stations['stop_areas']:
station['lat'] = station['coord']['lat']
station["lon"] = station['coord']['lon']
if 'administrative_regions' in station.keys() :
for var_api, var_df in zip(['insee','name','label','id','zip_code'],
['insee','region','label_region','id_region','zip_code']):
try:
station[var_df] = station['administrative_regions'][0][var_api]
except KeyError:
if var_api not in print_done:
print("key '{0}' not here but {1}".format(var_api,
",".join(station['administrative_regions'][0].keys())))
print_done[var_api] = var_api
[station.pop(k,None) for k in ['coord','links','administrative_regions', 'type', 'codes']]
stations = ensemble_stations['stop_areas']
try:
dp = pd.DataFrame(stations)
except Exception as e:
# La SNCF modifie parfois le schéma de ses données.
# On affiche station pour avoir une meilleure idée que l'erreur retournée par pandas
raise Exception("Problème de données\n{0}".format(stations)) from e
dfs.append(dp)
if page % 10 == 0:
print("je suis à la page", page, "---", dp.shape)
import pandas
df = pandas.concat(dfs)
df.to_csv("./ensemble_gares.csv")
print(df.shape)
df.head()
je suis à la page 0 --- (25, 11)
je suis à la page 10 --- (25, 11)
je suis à la page 20 --- (25, 11)
je suis à la page 30 --- (25, 11)
je suis à la page 40 --- (25, 11)
je suis à la page 50 --- (25, 11)
je suis à la page 60 --- (25, 11)
je suis à la page 70 --- (25, 11)
je suis à la page 80 --- (25, 11)
je suis à la page 90 --- (25, 11)
je suis à la page 100 --- (25, 11)
je suis à la page 110 --- (25, 11)
je suis à la page 120 --- (25, 11)
je suis à la page 130 --- (25, 11)
je suis à la page 140 --- (25, 11)
je suis à la page 150 --- (25, 11)
je suis à la page 160 --- (25, 11)
je suis à la page 170 --- (25, 11)
(4314, 11)
name | label | timezone | id | lat | lon | insee | region | label_region | id_region | zip_code | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | Europe/Paris | stop_area:OCE:SA:87271387 | 0 | 0 | NaN | NaN | NaN | NaN | NaN | ||
1 | . | . | Europe/Paris | stop_area:OCE:SA:00 | 27.141247 | -3.404382 | NaN | NaN | NaN | NaN | NaN |
2 | _ | _ | Europe/Paris | stop_area:OCE:SA:87757005 | 0 | 0 | NaN | NaN | NaN | NaN | NaN |
3 | Aachen/Aix la Chapelle | Aachen/Aix la Chapelle (Aachen) | Europe/Paris | stop_area:OCE:SA:80153452 | 50.767759 | 6.091215 | Aachen | Aachen | admin:osm:relation:62564 | ||
4 | Abancourt | Abancourt (Abancourt) | Europe/Paris | stop_area:OCE:SA:87313759 | 49.685665 | 1.77418 | 60001 | Abancourt | Abancourt (60220) | admin:fr:60001 | 60220 |
df[df.name.str.contains('Lyon')]
name | label | timezone | id | lat | lon | insee | region | label_region | id_region | zip_code | |
---|---|---|---|---|---|---|---|---|---|---|---|
12 | Lyon-Gorge-de-Loup | Lyon-Gorge-de-Loup (Lyon) | Europe/Paris | stop_area:OCE:SA:87721175 | 45.766077 | 4.804731 | 69123 | Lyon | Lyon | admin:fr:69123 | |
13 | Lyon-Jean-Macé | Lyon-Jean-Macé (Lyon) | Europe/Paris | stop_area:OCE:SA:87282624 | 45.745198 | 4.841515 | 69123 | Lyon | Lyon | admin:fr:69123 | |
14 | Lyon-Part-Dieu | Lyon-Part-Dieu (Lyon) | Europe/Paris | stop_area:OCE:SA:87723197 | 45.760585 | 4.859435 | 69123 | Lyon | Lyon | admin:fr:69123 | |
15 | Lyon-Part-Dieu-Gare-Rou | Lyon-Part-Dieu-Gare-Rou (Lyon) | Europe/Paris | stop_area:OCE:SA:87697128 | 45.760585 | 4.859435 | 69123 | Lyon | Lyon | admin:fr:69123 | |
16 | Lyon-Perrache | Lyon-Perrache (Lyon) | Europe/Paris | stop_area:OCE:SA:87722025 | 45.748785 | 4.825941 | 69123 | Lyon | Lyon | admin:fr:69123 | |
17 | Lyon-Perrache-Gare-Rout | Lyon-Perrache-Gare-Rout (Lyon) | Europe/Paris | stop_area:OCE:SA:87697136 | 45.749712 | 4.82678 | 69123 | Lyon | Lyon | admin:fr:69123 | |
18 | Lyon-Saint-Exupery-Tgv | Lyon-Saint-Exupery-Tgv (Colombier-Saugnieu) | Europe/Paris | stop_area:OCE:SA:87762906 | 45.720928 | 5.075833 | 69299 | Colombier-Saugnieu | Colombier-Saugnieu (69124) | admin:fr:69299 | 69124 |
19 | Lyon-St-Paul | Lyon-St-Paul (Lyon) | Europe/Paris | stop_area:OCE:SA:87721159 | 45.766082 | 4.826904 | 69123 | Lyon | Lyon | admin:fr:69123 | |
20 | Lyon-St-Paul-la-Feuilée | Lyon-St-Paul-la-Feuilée (Lyon) | Europe/Paris | stop_area:OCE:SA:87698340 | 45.766342 | 4.829385 | 69123 | Lyon | Lyon | admin:fr:69123 | |
21 | Lyon-St-Paul-Quai-Bondy | Lyon-St-Paul-Quai-Bondy (Lyon) | Europe/Paris | stop_area:OCE:SA:87698332 | 45.766488 | 4.828105 | 69123 | Lyon | Lyon | admin:fr:69123 | |
22 | Lyon-Vaise | Lyon-Vaise (Lyon) | Europe/Paris | stop_area:OCE:SA:87721001 | 45.780142 | 4.80405 | 69123 | Lyon | Lyon | admin:fr:69123 | |
23 | Lyon-Vaise-Gare-Routièr | Lyon-Vaise-Gare-Routièr (Lyon) | Europe/Paris | stop_area:OCE:SA:87697045 | 45.781597 | 4.805428 | 69123 | Lyon | Lyon | admin:fr:69123 | |
20 | Paris-Gare-de-Lyon | Paris-Gare-de-Lyon (Paris) | Europe/Paris | stop_area:OCE:SA:87686006 | 48.844922 | 2.373462 | 75056 | Paris | Paris (75000-75116) | admin:fr:75056 | 75000;75116 |
18 | Urcay-Hotel-du-Lyon-d'O | Urcay-Hotel-du-Lyon-d'O (Urçay) | Europe/Paris | stop_area:OCE:SA:87409490 | 46.626818 | 2.589411 | 3293 | Urçay | Urçay (03360) | admin:fr:3293 | 03360 |
df = pd.read_csv("./ensemble_gares.csv", encoding = "ISO-8859-1")
print(df.columns)
print(df.shape)
# Exemple des informations sur une gare
df.iloc[317]
Index(['Unnamed: 0', 'name', 'label', 'timezone', 'id', 'lat', 'lon', 'insee',
'region', 'label_region', 'id_region', 'zip_code'],
dtype='object')
(4314, 12)
Unnamed: 0 17
name Baume-les-Dames
label Baume-les-Dames (Baume-les-Dames)
timezone Europe/Paris
id stop_area:OCE:SA:87718460
lat 47.354
lon 6.35967
insee 25047
region Baume-les-Dames
label_region Baume-les-Dames (25110)
id_region admin:fr:25047
zip_code 25110
Name: 317, dtype: object
# on crée un dictionnaire des correspondances entre les noms et les codes des gares
dict_label_gare_code = df[['label','id']].set_index('label').to_dict()['id']
dict_nom_gare_code = df[['name','id']].set_index('name').to_dict()['id']
print(df.columns)
# graphique dans le plan des gares
%matplotlib inline
import matplotlib.pyplot as plt
lng_var = df[(df['lat']>35) & (df['lat']<60)]["lon"].tolist()
lat_var = df[(df['lat']>35) & (df['lat']<60)]["lat"].tolist()
plt.scatter(x = lng_var , y = lat_var,marker = "o");
Index(['Unnamed: 0', 'name', 'label', 'timezone', 'id', 'lat', 'lon', 'insee',
'region', 'label_region', 'id_region', 'zip_code'],
dtype='object')

Les trajets depuis la Gare de Lyon¶
Partons à Lyon¶
Imaginez que vous vouliez un peu voyager hors de Paris, et il se trouve que justement on vous propose de passer quelques jours à Lyon. Vous partez le 17 novembre vers 19h50 pour ne pas trop écourter votre journée de travail (documentation de l’API).
Question 1¶
Commencez par récupérer les informations sur le trajet entre Paris Gare de Lyon et Lyon Perrache le 17 novembre à 19h57
Paris - Gare de Lyon (code de la gare : stop_area:OCE:SA:87686006)
Lyon - Gare Lyon Perrache (code de la gare : stop_area:OCE:SA:87722025)
Indice : utiliser la requête “journeys”
Autre indice : le format de la date est AAAAMMJJTHHMMSS (Année, mois, jour, heure, minutes, secondes)
Répondez aux questions suivantes
combien y a-t-il d’arrêts entre ces deux gares ? (utilisez la clé ‘journeys’)
combien de temps d’arrêt à chacune d’elles ?
Tout d’abord une fonction qui sera utile pour calculer des temps :
from datetime import datetime, timedelta
def convertir_en_temps(chaine) :
''' on convertit en date la chaine de caractères de l API'''
return datetime.strptime(chaine.replace('T',''),'%Y%m%d%H%M%S')
Et l’inverse :
def convertir_en_chaine(dt) :
''' on convertit en chaîne de caractères un datetime'''
return datetime.strftime(dt, '%Y%m%dT%H%M%S')
now = datetime.now()
convertir_en_chaine(now)
'20200418T165041'
convertir_en_temps(convertir_en_chaine(now))
datetime.datetime(2020, 4, 18, 16, 50, 41)
# informations sur le trajet qu'on choisit dans le futur
# l'API ne retourne pas de résultatq très loin dans le passé
now = datetime.now()
dt = now + timedelta(14) # dans deux semaines
date_depart = convertir_en_chaine(dt)
gare_depart = 'stop_area:OCE:SA:87686006'
gare_arrivee = 'stop_area:OCE:SA:87722025'
date_depart
'20200502T165041'
Ensemble des départs :
paris_lyon = requests.get(
('https://api.sncf.com/v1/coverage/sncf/journeys?'
'from={}&to={}&datetime={}').format(gare_depart, gare_arrivee, date_depart),
auth=(token_auth, '')).json()
Les gares du chemin entre Paris et Lyon sur ce trajet ainsi que le temps d’arrêt :
session = paris_lyon['journeys'][0]['sections'][1]
rows = []
if "stop_date_times" in session:
for i in session['stop_date_times']:
rows.append(dict(name=i['stop_point']['name'],
depart=convertir_en_temps(i['departure_date_time']),
arrivee=convertir_en_temps(i['arrival_date_time'])))
pandas.DataFrame(rows)
name | depart | arrivee | |
---|---|---|---|
0 | Paris-Gare-de-Lyon | 2020-05-02 16:58:00 | 2020-05-02 16:58:00 |
1 | Lyon-Part-Dieu | 2020-05-02 19:01:00 | 2020-05-02 18:56:00 |
2 | Lyon-Perrache | 2020-05-02 19:09:00 | 2020-05-02 19:09:00 |
Question 2¶
Vous êtes un peu pressé et vous avez peur de vous tromper en arrivant à la gare car d’autres TGV partent à peu près en même temps (à partir de 19h00) de la gare de Lyon. Si vous demandez à l’API, combien de résultats vous donne-t-elle ?
Soit l’API a changé, soit…
requests.get(
('https://api.sncf.com/v1/coverage/sncf/stop_points/'
'stop_area:OCE:SA:87686006/departures'), auth=(token_auth, '')).json()
{'pagination': {'start_page': 0,
'items_on_page': 0,
'items_per_page': 0,
'total_result': 0},
'links': [],
'disruptions': [],
'notes': [],
'feed_publishers': [],
'departures': [],
'context': {'timezone': 'Europe/Paris',
'current_datetime': '20200418T165041'},
'error': {'message': 'ptref : Filters: Unable to find object',
'id': 'unknown_object'},
'exceptions': []}
### les trains qui partent autour de 19h00
departs_paris = requests.get(
('https://api.sncf.com/v1/coverage/sncf/stop_points/stop_point:OCE:SP:'
'TGV-87686006/departures?from_datetime={}').format(
date_depart), auth=(token_auth, '')).json()
# Nombre de trains que l'API renvoie à partir de cet horaire-là
#print(len(departs_paris['departures']))
departs_paris
{'pagination': {'start_page': 0,
'items_on_page': 10,
'items_per_page': 10,
'total_result': 10},
'links': [{'href': 'https://api.sncf.com/v1/coverage/sncf/stop_points/{stop_point.id}',
'type': 'stop_point',
'rel': 'stop_points',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/commercial_modes/{commercial_modes.id}',
'type': 'commercial_modes',
'rel': 'commercial_modes',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/stop_areas/{stop_area.id}',
'type': 'stop_area',
'rel': 'stop_areas',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/physical_modes/{physical_modes.id}',
'type': 'physical_modes',
'rel': 'physical_modes',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/routes/{route.id}',
'type': 'route',
'rel': 'routes',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/commercial_modes/{commercial_mode.id}',
'type': 'commercial_mode',
'rel': 'commercial_modes',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/vehicle_journeys/{vehicle_journey.id}',
'type': 'vehicle_journey',
'rel': 'vehicle_journeys',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/lines/{line.id}',
'type': 'line',
'rel': 'lines',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/physical_modes/{physical_mode.id}',
'type': 'physical_mode',
'rel': 'physical_modes',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/networks/{network.id}',
'type': 'network',
'rel': 'networks',
'templated': True},
{'href': 'https://api.sncf.com/v1/coverage/sncf/stop_points/stop_point:OCE:SP:TGV-87686006/departures?from_datetime=20200502T165041',
'type': 'first',
'templated': False}],
'disruptions': [],
'notes': [],
'feed_publishers': [],
'departures': [{'display_informations': {'direction': 'Mulhouse (Mulhouse)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris <> Bourgogne Franche Comté <> Mulhouse',
'physical_mode': 'Train grande vitesse',
'headsign': '6713',
'label': 'Paris <> Bourgogne Franche Comté <> Mulhouse',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-182063-BV'},
{'type': 'CR-CI-CH', 'value': '0087-182063-BV'},
{'type': 'UIC8', 'value': '87182063'},
{'type': 'external_code', 'value': 'OCE87182063'}],
'name': 'Mulhouse',
'links': [],
'coord': {'lat': '47.741798', 'lon': '7.34285'},
'label': 'Mulhouse (Mulhouse)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87182063'},
'quality': 0,
'name': 'Mulhouse (Mulhouse)',
'id': 'stop_area:OCE:SA:87182063'},
'name': 'Paris-Gare-de-Lyon vers Mulhouse (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris <> Bourgogne Franche Comté <> Mulhouse',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '235600',
'opening_time': '053300',
'id': 'line:OCE:139'},
'id': 'route:OCE:139-TGV-87686006-87182063'},
'links': [{'type': 'line', 'id': 'line:OCE:139'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN006713F03003'},
{'type': 'route', 'id': 'route:OCE:139-TGV-87686006-87182063'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200502T191900',
'additional_informations': [],
'departure_date_time': '20200502T191900',
'base_arrival_date_time': '20200502T191900',
'base_departure_date_time': '20200502T191900',
'data_freshness': 'base_schedule'}},
{'display_informations': {'direction': 'Grenoble (Grenoble)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris <> Grenoble',
'physical_mode': 'Train grande vitesse',
'headsign': '6927',
'label': 'Paris <> Grenoble',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-747006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-747006-BV'},
{'type': 'UIC8', 'value': '87747006'},
{'type': 'external_code', 'value': 'OCE87747006'}],
'name': 'Grenoble',
'links': [],
'coord': {'lat': '45.191463', 'lon': '5.71453'},
'label': 'Grenoble (Grenoble)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87747006'},
'quality': 0,
'name': 'Grenoble (Grenoble)',
'id': 'stop_area:OCE:SA:87747006'},
'name': 'Paris-Gare-de-Lyon vers Grenoble (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris <> Grenoble',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '002100',
'opening_time': '051900',
'id': 'line:OCE:146'},
'id': 'route:OCE:146-TGV-87686006-87747006'},
'links': [{'type': 'line', 'id': 'line:OCE:146'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN006927F12012'},
{'type': 'route', 'id': 'route:OCE:146-TGV-87686006-87747006'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200502T194300',
'additional_informations': [],
'departure_date_time': '20200502T194300',
'base_arrival_date_time': '20200502T194300',
'base_departure_date_time': '20200502T194300',
'data_freshness': 'base_schedule'}},
{'display_informations': {'direction': 'Milano-Porta-Garibaldi (Milano)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris<>Milano PG',
'physical_mode': 'Train grande vitesse',
'headsign': '9241',
'label': 'Paris<>Milano PG',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0083-016451-00'},
{'type': 'CR-CI-CH', 'value': '0083-016451-00'},
{'type': 'UIC8', 'value': '83016451'},
{'type': 'external_code', 'value': 'OCE83016451'}],
'name': 'Milano-Porta-Garibaldi',
'links': [],
'coord': {'lat': '45.48496', 'lon': '9.18759'},
'label': 'Milano-Porta-Garibaldi (Milano)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:83016451'},
'quality': 0,
'name': 'Milano-Porta-Garibaldi (Milano)',
'id': 'stop_area:OCE:SA:83016451'},
'name': 'Paris-Gare-de-Lyon vers Milano-Porta-Garibaldi (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris<>Milano PG',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '233000',
'opening_time': '054500',
'id': 'line:OCE:645702'},
'id': 'route:OCE:645702-TGV-87686006-83016451'},
'links': [{'type': 'line', 'id': 'line:OCE:645702'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN009241F14014'},
{'type': 'route', 'id': 'route:OCE:645702-TGV-87686006-83016451'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200503T062900',
'additional_informations': [],
'departure_date_time': '20200503T062900',
'base_arrival_date_time': '20200503T062900',
'base_departure_date_time': '20200503T062900',
'data_freshness': 'base_schedule'}},
{'display_informations': {'direction': 'Grenoble (Grenoble)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris <> Grenoble',
'physical_mode': 'Train grande vitesse',
'headsign': '6905',
'label': 'Paris <> Grenoble',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-747006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-747006-BV'},
{'type': 'UIC8', 'value': '87747006'},
{'type': 'external_code', 'value': 'OCE87747006'}],
'name': 'Grenoble',
'links': [],
'coord': {'lat': '45.191463', 'lon': '5.71453'},
'label': 'Grenoble (Grenoble)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87747006'},
'quality': 0,
'name': 'Grenoble (Grenoble)',
'id': 'stop_area:OCE:SA:87747006'},
'name': 'Paris-Gare-de-Lyon vers Grenoble (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris <> Grenoble',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '002100',
'opening_time': '051900',
'id': 'line:OCE:146'},
'id': 'route:OCE:146-TGV-87686006-87747006'},
'links': [{'type': 'line', 'id': 'line:OCE:146'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN006905F12012'},
{'type': 'route', 'id': 'route:OCE:146-TGV-87686006-87747006'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200503T073900',
'additional_informations': [],
'departure_date_time': '20200503T073900',
'base_arrival_date_time': '20200503T073900',
'base_departure_date_time': '20200503T073900',
'data_freshness': 'base_schedule'}},
{'display_informations': {'direction': 'Mulhouse (Mulhouse)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris <> Bourgogne Franche Comté <> Mulhouse',
'physical_mode': 'Train grande vitesse',
'headsign': '6703',
'label': 'Paris <> Bourgogne Franche Comté <> Mulhouse',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-182063-BV'},
{'type': 'CR-CI-CH', 'value': '0087-182063-BV'},
{'type': 'UIC8', 'value': '87182063'},
{'type': 'external_code', 'value': 'OCE87182063'}],
'name': 'Mulhouse',
'links': [],
'coord': {'lat': '47.741798', 'lon': '7.34285'},
'label': 'Mulhouse (Mulhouse)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87182063'},
'quality': 0,
'name': 'Mulhouse (Mulhouse)',
'id': 'stop_area:OCE:SA:87182063'},
'name': 'Paris-Gare-de-Lyon vers Mulhouse (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris <> Bourgogne Franche Comté <> Mulhouse',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '235600',
'opening_time': '053300',
'id': 'line:OCE:139'},
'id': 'route:OCE:139-TGV-87686006-87182063'},
'links': [{'type': 'line', 'id': 'line:OCE:139'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN006703F07007'},
{'type': 'route', 'id': 'route:OCE:139-TGV-87686006-87182063'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200503T091900',
'additional_informations': [],
'departure_date_time': '20200503T091900',
'base_arrival_date_time': '20200503T091900',
'base_departure_date_time': '20200503T091900',
'data_freshness': 'base_schedule'}},
{'display_informations': {'direction': 'Grenoble (Grenoble)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris <> Grenoble',
'physical_mode': 'Train grande vitesse',
'headsign': '6911',
'label': 'Paris <> Grenoble',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-747006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-747006-BV'},
{'type': 'UIC8', 'value': '87747006'},
{'type': 'external_code', 'value': 'OCE87747006'}],
'name': 'Grenoble',
'links': [],
'coord': {'lat': '45.191463', 'lon': '5.71453'},
'label': 'Grenoble (Grenoble)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87747006'},
'quality': 0,
'name': 'Grenoble (Grenoble)',
'id': 'stop_area:OCE:SA:87747006'},
'name': 'Paris-Gare-de-Lyon vers Grenoble (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris <> Grenoble',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '002100',
'opening_time': '051900',
'id': 'line:OCE:146'},
'id': 'route:OCE:146-TGV-87686006-87747006'},
'links': [{'type': 'line', 'id': 'line:OCE:146'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN006911F06006'},
{'type': 'route', 'id': 'route:OCE:146-TGV-87686006-87747006'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200503T094300',
'additional_informations': [],
'departure_date_time': '20200503T094300',
'base_arrival_date_time': '20200503T094300',
'base_departure_date_time': '20200503T094300',
'data_freshness': 'base_schedule'}},
{'display_informations': {'direction': 'Annecy (Annecy)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris <> Chambéry / Annecy',
'physical_mode': 'Train grande vitesse',
'headsign': '6937',
'label': 'Paris <> Chambéry / Annecy',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-746008-BV'},
{'type': 'CR-CI-CH', 'value': '0087-746008-BV'},
{'type': 'UIC8', 'value': '87746008'},
{'type': 'external_code', 'value': 'OCE87746008'}],
'name': 'Annecy',
'links': [],
'coord': {'lat': '45.902059', 'lon': '6.121819'},
'label': 'Annecy (Annecy)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87746008'},
'quality': 0,
'name': 'Annecy (Annecy)',
'id': 'stop_area:OCE:SA:87746008'},
'name': 'Paris-Gare-de-Lyon vers Annecy (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris <> Chambéry / Annecy',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '233800',
'opening_time': '053200',
'id': 'line:OCE:147'},
'id': 'route:OCE:147-TGV-87686006-87746008'},
'links': [{'type': 'line', 'id': 'line:OCE:147'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN006937F07007'},
{'type': 'route', 'id': 'route:OCE:147-TGV-87686006-87746008'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200503T094700',
'additional_informations': [],
'departure_date_time': '20200503T094700',
'base_arrival_date_time': '20200503T094700',
'base_departure_date_time': '20200503T094700',
'data_freshness': 'base_schedule'}},
{'display_informations': {'direction': 'Milano-Porta-Garibaldi (Milano)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris<>Milano PG',
'physical_mode': 'Train grande vitesse',
'headsign': '9245',
'label': 'Paris<>Milano PG',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0083-016451-00'},
{'type': 'CR-CI-CH', 'value': '0083-016451-00'},
{'type': 'UIC8', 'value': '83016451'},
{'type': 'external_code', 'value': 'OCE83016451'}],
'name': 'Milano-Porta-Garibaldi',
'links': [],
'coord': {'lat': '45.48496', 'lon': '9.18759'},
'label': 'Milano-Porta-Garibaldi (Milano)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:83016451'},
'quality': 0,
'name': 'Milano-Porta-Garibaldi (Milano)',
'id': 'stop_area:OCE:SA:83016451'},
'name': 'Paris-Gare-de-Lyon vers Milano-Porta-Garibaldi (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris<>Milano PG',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '233000',
'opening_time': '054500',
'id': 'line:OCE:645702'},
'id': 'route:OCE:645702-TGV-87686006-83016451'},
'links': [{'type': 'line', 'id': 'line:OCE:645702'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN009245F35035'},
{'type': 'route', 'id': 'route:OCE:645702-TGV-87686006-83016451'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200503T104300',
'additional_informations': [],
'departure_date_time': '20200503T104300',
'base_arrival_date_time': '20200503T104300',
'base_departure_date_time': '20200503T104300',
'data_freshness': 'base_schedule'}},
{'display_informations': {'direction': 'Mulhouse (Mulhouse)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris <> Bourgogne Franche Comté <> Mulhouse',
'physical_mode': 'Train grande vitesse',
'headsign': '6705',
'label': 'Paris <> Bourgogne Franche Comté <> Mulhouse',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-182063-BV'},
{'type': 'CR-CI-CH', 'value': '0087-182063-BV'},
{'type': 'UIC8', 'value': '87182063'},
{'type': 'external_code', 'value': 'OCE87182063'}],
'name': 'Mulhouse',
'links': [],
'coord': {'lat': '47.741798', 'lon': '7.34285'},
'label': 'Mulhouse (Mulhouse)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87182063'},
'quality': 0,
'name': 'Mulhouse (Mulhouse)',
'id': 'stop_area:OCE:SA:87182063'},
'name': 'Paris-Gare-de-Lyon vers Mulhouse (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris <> Bourgogne Franche Comté <> Mulhouse',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '235600',
'opening_time': '053300',
'id': 'line:OCE:139'},
'id': 'route:OCE:139-TGV-87686006-87182063'},
'links': [{'type': 'line', 'id': 'line:OCE:139'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN006705F09009'},
{'type': 'route', 'id': 'route:OCE:139-TGV-87686006-87182063'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200503T112100',
'additional_informations': [],
'departure_date_time': '20200503T112100',
'base_arrival_date_time': '20200503T112100',
'base_departure_date_time': '20200503T112100',
'data_freshness': 'base_schedule'}},
{'display_informations': {'direction': 'Grenoble (Grenoble)',
'code': '',
'network': 'SNCF',
'links': [],
'color': '000000',
'name': 'Paris <> Grenoble',
'physical_mode': 'Train grande vitesse',
'headsign': '6917',
'label': 'Paris <> Grenoble',
'equipments': [],
'text_color': 'FFFFFF',
'commercial_mode': 'TGV',
'description': ''},
'stop_point': {'commercial_modes': [{'id': 'commercial_mode:INOUI',
'name': 'TGV INOUI'},
{'id': 'commercial_mode:tgv', 'name': 'TGV'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'equipments': [],
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'fare_zone': {'name': '0'},
'id': 'stop_point:OCE:SP:TGV-87686006',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-686006-BV'},
{'type': 'UIC8', 'value': '87686006'},
{'type': 'external_code', 'value': 'OCE87686006'}],
'name': 'Paris-Gare-de-Lyon',
'links': [],
'coord': {'lat': '48.844922', 'lon': '2.373462'},
'label': 'Paris-Gare-de-Lyon (Paris)',
'administrative_regions': [{'insee': '75056',
'name': 'Paris',
'level': 8,
'coord': {'lat': '48.8566969', 'lon': '2.3514616'},
'label': 'Paris (75000-75116)',
'id': 'admin:fr:75056',
'zip_code': '75000;75116'}],
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87686006'}},
'route': {'direction': {'embedded_type': 'stop_area',
'stop_area': {'codes': [{'type': 'CR-CI-CH', 'value': '0087-747006-BV'},
{'type': 'CR-CI-CH', 'value': '0087-747006-BV'},
{'type': 'UIC8', 'value': '87747006'},
{'type': 'external_code', 'value': 'OCE87747006'}],
'name': 'Grenoble',
'links': [],
'coord': {'lat': '45.191463', 'lon': '5.71453'},
'label': 'Grenoble (Grenoble)',
'timezone': 'Europe/Paris',
'id': 'stop_area:OCE:SA:87747006'},
'quality': 0,
'name': 'Grenoble (Grenoble)',
'id': 'stop_area:OCE:SA:87747006'},
'name': 'Paris-Gare-de-Lyon vers Grenoble (TGV)',
'links': [],
'physical_modes': [{'id': 'physical_mode:LongDistanceTrain',
'name': 'Train grande vitesse'}],
'is_frequence': 'False',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'direction_type': 'forward',
'line': {'code': '',
'name': 'Paris <> Grenoble',
'links': [],
'color': '000000',
'geojson': {'type': 'MultiLineString', 'coordinates': []},
'text_color': 'FFFFFF',
'codes': [],
'closing_time': '002100',
'opening_time': '051900',
'id': 'line:OCE:146'},
'id': 'route:OCE:146-TGV-87686006-87747006'},
'links': [{'type': 'line', 'id': 'line:OCE:146'},
{'type': 'vehicle_journey', 'id': 'vehicle_journey:OCE:SN006917F54054'},
{'type': 'route', 'id': 'route:OCE:146-TGV-87686006-87747006'},
{'type': 'commercial_mode', 'id': 'commercial_mode:tgv'},
{'type': 'physical_mode', 'id': 'physical_mode:LongDistanceTrain'},
{'type': 'network', 'id': 'network:sncf'}],
'stop_date_time': {'links': [],
'arrival_date_time': '20200503T114100',
'additional_informations': [],
'departure_date_time': '20200503T114100',
'base_arrival_date_time': '20200503T114100',
'base_departure_date_time': '20200503T114100',
'data_freshness': 'base_schedule'}}],
'context': {'timezone': 'Europe/Paris',
'current_datetime': '20200418T165041'},
'exceptions': []}
from jyquickhelper import JSONJS
JSONJS(departs_paris)
Quels sont les horaires de départ de ces trains ?
for i in range(len(departs_paris['departures'])) :
print(departs_paris['departures'][i]['stop_date_time']['departure_date_time'])
20200502T191900
20200502T194300
20200503T062900
20200503T073900
20200503T091900
20200503T094300
20200503T094700
20200503T104300
20200503T112100
20200503T114100
Parmi ces trains, combien de trains ont pour destination finale Lyon et qui partent le 17 novembre ?
nombre_trains_pour_lyon = 0
for depart in departs_paris['departures'] :
if "Lyon" in depart['display_informations']['direction'] :
if (convertir_en_temps(depart['stop_date_time']['arrival_date_time']) >
convertir_en_temps(date_depart) and
convertir_en_temps(depart['stop_date_time']['arrival_date_time']) <
datetime(2016,11,18,0,0,0)):
nombre_trains_pour_lyon += 1
print("le prochain départ pour Lyon sera le",
convertir_en_temps(depart['stop_date_time']['arrival_date_time']))
print("Il y a" , nombre_trains_pour_lyon, "train(s) pour Lyon dans les trains proposés",
"par l'API qui partent encore le 17 novembre")
Il y a 0 train(s) pour Lyon dans les trains proposés par l'API qui partent encore le 17 novembre
C’est quand qu’on va où ?¶
En fait, vous n’êtes plus très sûr de vouloir aller à Lyon. Mais bon maintenant vous êtes Gare de Lyon et il est 18h00.
Question 3¶
Combien de tgv partent entre 18h00 et 20h00 ?
Lequel arrive le plus tôt à sa destination finale ?
# on crée deux fonctions :
def trouver_destination_tgv(origine, datetime) :
'''Permet d avoir les 10 prochains départs d une gare donnée '''
return requests.get('https://api.sncf.com/v1/coverage/sncf/stop_points/{}/' \
'departures?from_datetime={}'.format(origine, datetime) ,
auth=(token_auth, '')).json()
def trouver_trajet_dispo_max_heure(gare_depart, date_heure_depart, date_heure_max) :
'''Permet d avoir toutes les informations sur des trajets partant
d une gare entre une date X et une date Y'''
destinations = []
# on interroge l'API tant qu'il renvoie des information
# sur les trains partant de Gare de lyon
while convertir_en_temps(date_heure_depart) < convertir_en_temps(date_heure_max) :
# on prend toutes les destinations qui partent à partir d'une certaine heure
destinations = destinations + trouver_destination_tgv(
gare_depart, date_heure_depart)['departures']
nombre_resultats = trouver_destination_tgv(
gare_depart, date_heure_depart)['pagination']['items_on_page']
if nombre_resultats <= 0:
break
# on trouve l'heure max de la première série de 10 solutions que l'application renvoie
# on remplace l'heure qu'on cherche par celle là
resultats = trouver_destination_tgv(gare_depart, date_heure_depart)
date_heure_depart = resultats['departures'][nombre_resultats-1][
'stop_date_time']['departure_date_time']
return destinations
# on trouve l'ensemble des trajets dont le départ est compris entre deux horaires
# informations sur le trajet qu'on choisit dans le futur
# l'API ne retourne pas de résultatq très loin dans le passé
now = datetime.now()
if now.hour < 6:
# pas trop tôt
now += timedelta(hours=4)
dt = now + timedelta(14) # dans deux semaines
date_heure = convertir_en_chaine(dt)
max_date_heure = convertir_en_chaine(dt + timedelta(hours=24))
print("entre", date_heure, "et", max_date_heure)
gare_initiale = 'stop_point:OCE:SP:TGV-87686006'
# on demande à avoir tous les trajets partant de gare de lyon
# entre deux heures précises
destinations_depuis_paris_max_20h = trouver_trajet_dispo_max_heure(
gare_initiale, date_heure, max_date_heure)
# on veut supprimer ceux pour lesquels le départ est après 20h00
dictionnaire_destinations = {}
i = 0
for depart in destinations_depuis_paris_max_20h :
print(depart['display_informations']['direction'],
depart['stop_date_time']['departure_date_time'])
if (convertir_en_temps(depart['stop_date_time']['departure_date_time']) <
convertir_en_temps(max_date_heure)):
i += 1
dictionnaire_destinations[i] = depart
print("Je peux prendre", len(dictionnaire_destinations.keys()),
"trains qui partent entre 18h et 20h de Gare de Lyon le 17 novembre 2016")
entre 20200502T165041 et 20200503T165041
Mulhouse (Mulhouse) 20200502T191900
Grenoble (Grenoble) 20200502T194300
Milano-Porta-Garibaldi (Milano) 20200503T062900
Grenoble (Grenoble) 20200503T073900
Mulhouse (Mulhouse) 20200503T091900
Grenoble (Grenoble) 20200503T094300
Annecy (Annecy) 20200503T094700
Milano-Porta-Garibaldi (Milano) 20200503T104300
Mulhouse (Mulhouse) 20200503T112100
Grenoble (Grenoble) 20200503T114100
Grenoble (Grenoble) 20200503T114100
Annecy (Annecy) 20200503T124500
Milano-Porta-Garibaldi (Milano) 20200503T144200
Grenoble (Grenoble) 20200503T144200
Besançon-Viotte (Besançon) 20200503T145000
Annecy (Annecy) 20200503T164400
Besançon-Viotte (Besançon) 20200503T164800
Mulhouse (Mulhouse) 20200503T171700
Grenoble (Grenoble) 20200503T174100
Annecy (Annecy) 20200503T174600
Je peux prendre 17 trains qui partent entre 18h et 20h de Gare de Lyon le 17 novembre 2016
# on cherche celui qui arrive le plus tôt à sa destination
def trouver_info_trajet(dep, arr, heure) :
res = requests.get('https://api.sncf.com/v1/coverage/sncf/journeys?from={}&to={}&datetime={}'.format(dep, arr, heure), \
auth=(token_auth, '')).json()
if 'journeys' not in res:
if 'error' in res and "no solution" in res["error"]['message']:
print("Pas de solution pour '{0} --> '{1}' h: {2}.".format(dep, arr, heure))
return None
return res['journeys'][0]
# on initiale l'heure à la fin de la journée : on veut réduire cette variable au maximum
# on veut 6h après le départ
heure_minimale = dt + timedelta(hours=8)
destination_la_plus_rapide = None
print("heure_minimale", heure_minimale, " len ", len(dictionnaire_destinations))
# parmi toutes les destinations possibles, on recherche le train qui arrive le plus tôt à sa destination finale
for code, valeurs in dictionnaire_destinations.items() :
''' on prend le code de la gare'''
code_destination = dictionnaire_destinations[code]['route']['direction']['id']
''' on regarde à quelle heure arrive le train'''
trajet = trouver_info_trajet('stop_area:OCE:SA:87686006',code_destination,
dictionnaire_destinations[code]['stop_date_time']['arrival_date_time'])
if trajet is None:
continue
if heure_minimale > convertir_en_temps(trajet['arrival_date_time']) :
heure_minimale = convertir_en_temps(trajet['arrival_date_time'])
destination_la_plus_rapide = dictionnaire_destinations[code]
heure_minimale 2020-05-03 00:50:41.995641 len 17
if destination_la_plus_rapide is not None:
print(destination_la_plus_rapide['display_informations']['direction'], heure_minimale)
else:
print("pas de résultat")
Mulhouse (Mulhouse) 2020-05-02 22:17:00
Et les correspondances ?¶
Question 4¶
On va essayer de voir jusqu’où on peut aller, en prenant des trains au départ de la Gare de Lyon :
Quelles sont toutes les gares atteignables en partant le 17 novembre, sans faire de changement et sans partir après minuit ?
Si on prend un de ces trains, jusqu’où peut-on aller, avec une correspondance, sans partir après 8h le lendemain matin ?
# on va trouver toutes les gares qui sont sur les trajets des
# trains retenus donc atteignables sans correspondance
def trouver_toutes_les_gares_du_trajet(gare_depart, gare_arrivee_finale, horaire_depart) :
return requests.get('https://api.sncf.com/v1/coverage/sncf/journeys?from={}&to={}' \
'&datetime={}'.format(gare_depart,gare_arrivee_finale,horaire_depart), \
auth=(token_auth, '')).json()
# Exemple pour la première gare de la liste
if len(dictionnaire_destinations) > 1:
gare_depart = dictionnaire_destinations[1]['stop_point']['id']
gare_arrivee = dictionnaire_destinations[1]['route']['direction']['id']
horaire_train = dictionnaire_destinations[1]['stop_date_time']['arrival_date_time']
trajet_recherche = trouver_toutes_les_gares_du_trajet(gare_depart,gare_arrivee,horaire_train)
session = trajet_recherche['journeys'][0]['sections'][0]
if "stop_date_times" in session:
for i in session['stop_date_times']:
print(i['stop_point']['name'])
Paris-Gare-de-Lyon
Dijon-Ville
Besançon-Franche-Comté
Belfort-Montbéliard-TGV
Mulhouse
# on fait la liste des gares où on
# peut aller sans correspondance
liste_gares_direct = []
for x in dictionnaire_destinations.keys():
# on prend les deux gares départ + finale
gare_depart = dictionnaire_destinations[x]['stop_point']['id']
gare_arrivee = dictionnaire_destinations[x]['route']['direction']['id']
horaire_train = dictionnaire_destinations[x]['stop_date_time']['arrival_date_time']
# on appelle la fonction définie précédemment
trajet_recherche = trouver_toutes_les_gares_du_trajet(gare_depart,gare_arrivee,horaire_train)
if 'error' in trajet_recherche:
continue
session = trajet_recherche['journeys'][0]['sections'][0]
if "stop_date_times" in session:
for i in session['stop_date_times']:
print(i['stop_point']['name'], i['arrival_date_time'])
liste_gares_direct.append(i['stop_point']['name'])
print("-------------")
#### là on a la liste des gares atteignables sans correspondance
liste_gares_direct = set(liste_gares_direct)
Paris-Gare-de-Lyon 20200502T191900
Dijon-Ville 20200502T205700
Besançon-Franche-Comté 20200502T212800
Belfort-Montbéliard-TGV 20200502T215200
Mulhouse 20200502T221700
-------------
Paris-Gare-de-Lyon 20200502T194300
Lyon-Saint-Exupery-Tgv 20200502T213600
Grenoble 20200502T224200
-------------
Paris-Gare-de-Lyon 20200503T062900
Lyon-Part-Dieu 20200503T083100
Chambéry-Chal.-les-Eaux 20200503T094000
Modane 20200503T104700
Bardonecchia-Stazione 20200503T111300
Oulx-Cesana-Clav-Sestri 20200503T112300
Torino PS (Turin) 20200503T122400
Milano-Porta-Garibaldi 20200503T135000
-------------
Paris-Gare-de-Lyon 20200503T073900
Lyon-Saint-Exupery-Tgv 20200503T093400
Grenoble 20200503T104200
-------------
Paris-Gare-de-Lyon 20200503T091900
Montbard 20200503T102500
Dijon-Ville 20200503T110100
Besançon-Franche-Comté 20200503T113100
Belfort-Montbéliard-TGV 20200503T115500
Mulhouse 20200503T122000
-------------
Paris-Gare-de-Lyon 20200503T094300
Lyon-Saint-Exupery-Tgv 20200503T113500
Grenoble 20200503T124200
-------------
Paris-Gare-de-Lyon 20200503T094700
Mâcon-Loché-TGV 20200503T112400
Aix-les-Bains-le-Revard 20200503T125100
Annecy 20200503T132900
-------------
Paris-Gare-de-Lyon 20200503T104300
Lyon-Saint-Exupery-Tgv 20200503T123700
Chambéry-Chal.-les-Eaux 20200503T134000
Modane 20200503T145000
Bardonecchia-Stazione 20200503T151300
Oulx-Cesana-Clav-Sestri 20200503T152300
Torino PS (Turin) 20200503T161800
Vercelli 20200503T165500
Novara 20200503T171100
Milano-Porta-Garibaldi 20200503T175000
-------------
Paris-Gare-de-Lyon 20200503T112100
Dijon-Ville 20200503T125700
Besançon-Franche-Comté 20200503T132800
Belfort-Montbéliard-TGV 20200503T135200
Mulhouse 20200503T141700
-------------
Paris-Gare-de-Lyon 20200503T114100
Lyon-Saint-Exupery-Tgv 20200503T133400
Grenoble 20200503T144200
-------------
Paris-Gare-de-Lyon 20200503T114100
Lyon-Saint-Exupery-Tgv 20200503T133400
Grenoble 20200503T144200
-------------
Paris-Gare-de-Lyon 20200503T124500
Mâcon-Loché-TGV 20200503T142200
Chambéry-Chal.-les-Eaux 20200503T153900
Aix-les-Bains-le-Revard 20200503T155900
Annecy 20200503T162900
-------------
Paris-Gare-de-Lyon 20200503T144200
Lyon-Saint-Exupery-Tgv 20200503T163500
Chambéry-Chal.-les-Eaux 20200503T173700
St-Jean-de-Maurienne-A. 20200503T182200
Modane 20200503T184700
Bardonecchia-Stazione 20200503T191300
Oulx-Cesana-Clav-Sestri 20200503T192300
Torino PS (Turin) 20200503T201800
Milano-Porta-Garibaldi 20200503T215000
-------------
Paris-Gare-de-Lyon 20200503T144200
Lyon-Saint-Exupery-Tgv 20200503T163500
Grenoble 20200503T174500
-------------
Paris-Gare-de-Lyon 20200503T145000
Montbard 20200503T155500
Dijon-Ville 20200503T163200
Besançon-Franche-Comté 20200503T170500
Besançon-Viotte 20200503T172000
-------------
Paris-Gare-de-Lyon 20200503T164400
Mâcon-Loché-TGV 20200503T182200
Chambéry-Chal.-les-Eaux 20200503T194000
Aix-les-Bains-le-Revard 20200503T195900
Annecy 20200503T202800
-------------
Paris-Gare-de-Lyon 20200503T164800
Montbard 20200503T175500
Dijon-Ville 20200503T183200
Dole-Ville 20200503T185800
Besançon-Viotte 20200503T192400
-------------
Exemple : trouver toutes les correspondances possibles depuis le trajet entre les gares de Paris et de Perpignan¶
# pour le premier trajet gare de la liste trouvée à l'étape précédente
# on va chercher toutes les connexions des gares possibles, entre le moment de l'arrivée
# et 8 heures le lendemain matin
if len(dictionnaire_destinations) > 1:
gare_depart = dictionnaire_destinations[1]['stop_point']['id']
gare_arrivee = dictionnaire_destinations[1]['route']['direction']['id']
horaire_train = dictionnaire_destinations[1]['stop_date_time']['arrival_date_time']
horaire_max = convertir_en_chaine(dt + timedelta(hours=8))
print("horaire_max", horaire_max)
else:
horaire_train = None
horaire_max 20200503T005041
# en partant de gare de lyon en direction de Perpignan
if horaire_train is not None:
trajet_recherche = trouver_toutes_les_gares_du_trajet(gare_depart,gare_arrivee,horaire_train)
dictionnaire_correspondances = {}
if (horaire_train is not None and
'stop_date_times' in trajet_recherche['journeys'][0]['sections'][0]):
for i in trajet_recherche['journeys'][0]['sections'][0]['stop_date_times']:
#print("la gare où on est descendu depuis Paris", i['stop_point']['name'])
if i['stop_point']['id'] == "stop_point:OCE:SP:TGV-87686006" :
#print("on ne prend pas la gare de Lyon - ce n'est pas une gare du trajet")
pass
else :
# on va appliquer à nouveau la fonction des trajets disponibles mais pour l'ensemble des gares
gare_dep_connexion = i['stop_point']['id']
nom_gare_dep = i['stop_point']['name']
heure_dep_connexion = i['arrival_date_time']
trajet_recherche_connexion = trouver_trajet_dispo_max_heure(gare_dep_connexion, heure_dep_connexion, horaire_max)
test_as_connexion_on_time = True
# pour chaque trajet possible depuis la gare où on est arrivé depuis paris, on va vérifier qu'on part bien
# avant 8h le lendemain
autre_gare = None
for vers_autre_gare in trajet_recherche_connexion :
heure_depart_depuis_autre_gare = vers_autre_gare['stop_date_time']['departure_date_time']
destination_trajet = vers_autre_gare['display_informations']['direction']
if convertir_en_temps(heure_depart_depuis_autre_gare) < convertir_en_temps(horaire_max) :
dictionnaire_correspondances[(nom_gare_dep,heure_depart_depuis_autre_gare)] = destination_trajet
test_as_connexion_on_time = False
# print(nom_gare_dep,heure_depart_depuis_autre_gare, "gare finale du trajet", destination_trajet)
autre_gare = vers_autre_gare
if autre_gare and test_as_connexion_on_time:
dictionnaire_correspondances[(nom_gare_dep,autre_gare['stop_date_time']['departure_date_time'])] = ""
else:
print("impossible de trouver 'stop_date_times'")
# on garde toutes les gares où on peut aller depuis une des gares de correspondance, avec un départ avant 8H
dictionnaire_correspondances
{('Dijon-Ville', '20200502T210100'): 'Mulhouse (Mulhouse)',
('Besançon-Franche-Comté', '20200502T213100'): 'Mulhouse (Mulhouse)',
('Belfort-Montbéliard-TGV', '20200502T215500'): 'Mulhouse (Mulhouse)'}
# Pour les trajets qui partent avant 8h des gares, on va chercher toutes les gares qui sont sur le trajet
gares_avec_connexion = []
for k,v in dictionnaire_correspondances.items() :
if len(v) == 0 :
pass
else :
if k[0] not in dict_nom_gare_code:
print("'{0}' pas trouvé dans {1}".format(k[0], ", ".join(
sorted(_ for _ in dict_nom_gare_code if isinstance(_, str) and _[:4] == k[0][:4]))))
continue
if v not in dict_label_gare_code:
print("'{0}' pas trouvé dans {1}".format(v, ", ".join(
sorted(_ for _ in dict_label_gare_code if isinstance(_, str) and _[:4] == v[:4]))))
continue
dep = dict_nom_gare_code[k[0]]
arr = dict_label_gare_code[v]
gares_entre_dep_arr = trouver_toutes_les_gares_du_trajet(dep, arr,k[1])
for gare in gares_entre_dep_arr['journeys'][0]['sections'][1]['stop_date_times']:
#print("gare depart:", k[0], gare['stop_point']['name'])
gares_avec_connexion.append(gare['stop_point']['name'])
# la liste des gares atteignables avec 1 correspondance
gares_avec_connexion = set(gares_avec_connexion)
'Besançon-Franche-Comté' pas trouvé dans Besançon-Franche-Comté, Besançon-Mouillère, Besançon-Viotte
'Belfort-Montbéliard-TGV' pas trouvé dans Belfort-Montbéliard-TGV, Belfort-Ville
print(gares_avec_connexion)
{'Belfort-Montbéliard-TGV', 'Mulhouse', 'Besançon-Franche-Comté', 'Dijon-Ville'}
# on crée la liste des gares atteignables seulement avec une correspondance (pas directement atteignable)
gares_atteintes_avec_connexion = [a for a in gares_avec_connexion if (a not in liste_gares_direct)]
print(gares_atteintes_avec_connexion)
[]
Exemple : trouver toutes les correspondances possibles depuis les trains qu’on prend de la Gare de Lyon¶
Maintenant qu’on a fait un exemple, on le fait pour tous les trajets qui partent de la Gare de Lyon
!!! Attention cette celulle prend du temps (beaucoup beaucoup de temps)¶
gares_avec_connexion = []
for gare_initiale in dictionnaire_destinations:
# pour le premier trajet gare de la liste trouvée à l'étape précédente
# on va chercher toutes les connexions des gares possibles
print(gare_initiale, "/", len(dictionnaire_destinations))
gare_depart = dictionnaire_destinations[gare_initiale]['stop_point']['id']
gare_arrivee = dictionnaire_destinations[gare_initiale]['route']['direction']['id']
horaire_train = dictionnaire_destinations[gare_initiale]['stop_date_time']['arrival_date_time']
# Pour les trajets qui partent avant 8h des gares, on va chercher toutes les gares qui sont sur le trajet
trajet_recherche = trouver_toutes_les_gares_du_trajet(gare_depart, gare_arrivee, horaire_train)
dictionnaire_correspondances = {}
if 'journeys' not in trajet_recherche:
print("Pas de trajet entre '{0}' et '{1}' h={2}.".format(gare_depart, gare_arrivee, horaire_train))
continue
session = trajet_recherche['journeys'][0]['sections'][0]
if "stop_date_times" in session:
for i in session['stop_date_times']:
if i['stop_point']['id'] == "stop_point:OCE:SP:TGV-87686006" :
#print("on ne prend pas la gare de Lyon - ce n'est pas une gare du trajet")
pass
else :
# on va appliquer à nouveau la fonction des trajets disponibles mais pour l'ensemble des gares
gare_dep_connexion = i['stop_point']['id']
nom_gare_dep = i['stop_point']['name']
heure_dep_connexion = i['arrival_date_time']
trajet_recherche_connexion = trouver_trajet_dispo_max_heure(gare_dep_connexion, heure_dep_connexion, horaire_max)
test_as_connexion_on_time = True
# pour chaque trajet possible depuis la gare où on est arrivé depuis paris, on va vérifier qu'on part bien
# avant 8h le lendemain
for vers_autre_gare in trajet_recherche_connexion :
heure_depart_depuis_autre_gare = vers_autre_gare['stop_date_time']['departure_date_time']
destination_trajet = vers_autre_gare['display_informations']['direction']
if convertir_en_temps(heure_depart_depuis_autre_gare) < convertir_en_temps(horaire_max) :
dictionnaire_correspondances[(nom_gare_dep,heure_depart_depuis_autre_gare)] = destination_trajet
test_as_connexion_on_time = False
if test_as_connexion_on_time == True :
dictionnaire_correspondances[(nom_gare_dep,vers_autre_gare['stop_date_time']['departure_date_time'])] = ""
# on garde toutes les gares où on peut aller depuis une des gares de correspondance, avec un départ avant 8H
for k,v in dictionnaire_correspondances.items() :
if len(v) == 0:
continue
if k[0] not in dict_nom_gare_code:
print("'{0}' pas trouvé dans {1}".format(k[0], ", ".join(
sorted(_ for _ in dict_nom_gare_code if isinstance(_, str) and _[:4] == k[0][:4]))))
continue
if v not in dict_label_gare_code:
print("'{0}' pas trouvé dans {1}".format(v, ", ".join(
sorted(_ for _ in dict_label_gare_code if isinstance(_, str) and _[:4] == v[:4]))))
continue
dep = dict_nom_gare_code[k[0]]
arr = dict_label_gare_code[v]
gares_entre_dep_arr = trouver_toutes_les_gares_du_trajet(dep, arr, k[1])
if 'journeys' not in gares_entre_dep_arr:
print("Pas de trajet entre '{0}' et '{1}'.".format(k[0], v))
continue
session = gares_entre_dep_arr['journeys'][0]['sections'][1]
if "stop_date_times" in session:
for gare in session['stop_date_times'] :
gares_avec_connexion.append(gare['stop_point']['name'])
1 / 17
'Besançon-Franche-Comté' pas trouvé dans Besançon-Franche-Comté, Besançon-Mouillère, Besançon-Viotte
'Belfort-Montbéliard-TGV' pas trouvé dans Belfort-Montbéliard-TGV, Belfort-Ville
2 / 17
3 / 17
4 / 17
5 / 17
6 / 17
7 / 17
8 / 17
9 / 17
10 / 17
11 / 17
12 / 17
13 / 17
14 / 17
15 / 17
16 / 17
17 / 17
# la liste des gares atteignables avec 1 correspondance
gares_avec_connexion = set(gares_avec_connexion)
gares_connexion = [a for a in gares_avec_connexion if a not in liste_gares_direct]
print(gares_connexion)
[]
Question 5¶
Représenter toutes les gares atteignables avec un graphique de type scatter. Distinguer les gares atteintes en un seul trajet et celles atteintes avec une correspondance.
######### Type de chaque gare pour le graphique
dict_type_gares = {}
for a in liste_gares_direct :
dict_type_gares[a] = "direct"
for a in gares_connexion :
dict_type_gares[a] = "correspondance"
dict_type_gares['Paris-Gare-de-Lyon'] = 'depart'
dict_type_gares
{'Modane': 'direct',
'Bardonecchia-Stazione': 'direct',
'Chambéry-Chal.-les-Eaux': 'direct',
'Besançon-Viotte': 'direct',
'Dijon-Ville': 'direct',
'Novara': 'direct',
'Torino PS (Turin)': 'direct',
'Mâcon-Loché-TGV': 'direct',
'Lyon-Part-Dieu': 'direct',
'Annecy': 'direct',
'Belfort-Montbéliard-TGV': 'direct',
'Aix-les-Bains-le-Revard': 'direct',
'Vercelli': 'direct',
'St-Jean-de-Maurienne-A.': 'direct',
'Lyon-Saint-Exupery-Tgv': 'direct',
'Grenoble': 'direct',
'Montbard': 'direct',
'Besançon-Franche-Comté': 'direct',
'Oulx-Cesana-Clav-Sestri': 'direct',
'Mulhouse': 'direct',
'Paris-Gare-de-Lyon': 'depart',
'Milano-Porta-Garibaldi': 'direct',
'Dole-Ville': 'direct'}
On représente tout ça sur un graphique
# on va les représenter grâce à la base des latitude / longitude
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.lines import Line2D
mpl.rcParams['axes.facecolor'] = "whitesmoke"
palette = plt.cm.spring
liste_couleurs = [palette(0), palette(0.5), palette(0.8)]
data_all = pd.read_csv("./ensemble_gares.csv", encoding = "ISO-8859-1")
connexions = []
lat = []
lon = []
labels = []
dict_lat = data_all.set_index('name')['lat'].to_dict()
dict_lon = data_all.set_index('name')['lon'].to_dict()
#dict_lab = data_all.set_index('name')['name'].str.replace("gare de","").to_dict()
for gare in dict_type_gares:
if gare not in dict_lat:
print("'{0}' pas trouvé dans dict_lat (problème d'accents?)".format(gare))
continue
if gare not in dict_lon:
print("'{0}' pas trouvé dans dict_lon (problème d'accents?)".format(gare))
continue
lat.append(dict_lat[gare])
lon.append(dict_lon[gare])
labels.append(gare)
'Chambéry-Chal.-les-Eaux' pas trouvé dans dict_lat (problème d'accents?)
'Besançon-Viotte' pas trouvé dans dict_lat (problème d'accents?)
'Mâcon-Loché-TGV' pas trouvé dans dict_lat (problème d'accents?)
'Belfort-Montbéliard-TGV' pas trouvé dans dict_lat (problème d'accents?)
'Besançon-Franche-Comté' pas trouvé dans dict_lat (problème d'accents?)
%matplotlib inline
### La carte
###################################################################################################
def liste_unique(liste) :
unicite = []
for x in liste :
if x in unicite :
pass
else :
unicite.append(x)
return unicite
lab_un = liste_unique(labels)
lat_un = liste_unique(lat)
lon_un = liste_unique(lon)
fig = plt.figure(figsize=(12,10))
for label, x, y in set(zip(labels, lon, lat)) :
if dict_type_gares[label] == "direct" :
plt.annotate(label, xy = (x - 0.05, y - 0.05), horizontalalignment = 'right', size = 13)
else :
plt.annotate(label, xy = (x + 0.05, y + 0.05), horizontalalignment = 'left', size = 13)
colors = []
for x in lab_un :
if dict_type_gares[x] == "depart" :
colors.append(liste_couleurs[0])
if dict_type_gares[x] == "direct" :
colors.append(liste_couleurs[1])
if dict_type_gares[x] == "correspondance" :
colors.append(liste_couleurs[2])
plt.scatter(x = lon_un , y = lat_un, marker = "o", c = colors, s = 100, alpha = 0.5)
#### Legende
circ1 = Line2D([0], [0], linestyle="none", marker="o", alpha=0.5, markersize=10, markerfacecolor = liste_couleurs[0])
circ2 = Line2D([0], [0], linestyle="none", marker="o", alpha=0.5, markersize=10, markerfacecolor = liste_couleurs[1])
circ3 = Line2D([0], [0], linestyle="none", marker="o", alpha=0.5, markersize=10, markerfacecolor = liste_couleurs[2])
legende = plt.legend((circ1, circ2, circ3), ("Gare de départ", "Direct depuis Gare de Lyon le soir du 17 novembre",
"Avec une correspondance depuis une gare directe"), numpoints=1, loc="best")
legende.get_frame().set_facecolor('white')
plt.title("Gares atteignables avant minuit depuis la Gare de Lyon", size = 20);
