🚇 Metro Travel

2024-03-26

Bon qu'est-ce que je souhaite faire et pour faire quoi ?

Actuellement, l'application prend en charge les lignes de métro de Paris, et permet de calculer un itinéraire entre deux stations en fonction du nombre de stations. C'est un peu simpliste, mais ça fonctionne.

J'aimerais ajouter la possibilité de jouer avec le trajet le plus rapide, et le moins de correspondance. Pour la première partie, il me faut le temps entre chaque station, et le temps de correspondance dans une station.

Pour avoir cette information, je vais devoir utiliser les données d'Île-de-France Mobilités, et plus particulièrement le General Transit Feed Specification (GTFS) dans sa version schedule.

Je vais devoir utiliser les données, c'est clairement du relationnel, et je vais devoir faire des jointures entre les différents fichiers. Est-ce que je vais devoir utiliser une BDD pour ça ? Franchement, je pense que les requêtes peuvent me simplifier la vie.

Je trouve un article qui donne les schémas à créer pour PostgreSQL et les étapes pour copier les données. C'est ce qu'il me faut.

Ce qui m'embête avec les données d'IDFM, c'est qu'il n'y a pas le fichier shape.txt, ça me permettrait de tracer les lignes plus facilement. J'ai par contre bien récupéré les tracés des lignes, qui comporte le route_id, c'est plutôt ok.

Si je résume, pour mon besoin, je charge les fichiers dans ma BDD. Grâce à ça, je peux faire des requêtes pour avoir le temps entre chaque station et chaque correspondance.

Pour me baser que sur le GTFS qu'est-ce qu'il me faut :

  • Calculer les stations adjacentes
  • Calculer les portions de lignes à afficher entre les stations

Essayons de voir comment je peux faire ça.

  1. Obtenir les stations adjacentes : j'utilise une jointure entre : stop_times, trips, routes. Je ne garde que les métros : route_type = 1. Je fais un distinct sur trip_headsign, direction_id, route_id, stop_id, stop_name.
  2. Obtenir les portions de lignes à afficher : Je le fais en JavaScript
  3. Obtenir les correspondances : j'utilise une jointure entre pathways et stops. Je garde le from_stop_id, to_stop_id, transversal_time.

Cela me parait plutôt bon comme plan, je me demande si je vais pas stocker directement la portion avec la station adjacente. D'ailleurs est-ce que j'utilise le même vocabulaire : stop à la place de station et routes à la place de lignes ?

Ce qui me donnerait quelque chose comme :

{
  "routes": [
    {
      "route_id": "route_id",
      "route_name": "route_name",
      "route_color": "route_color"
    }
  ],
  "stops": [
    {
      "name": "stop_name",
      "id": "stop_id",
      "route_id": "route_id"
    }
  ],
  "adjacents": [
    {
      "from_stop_id": "stop_id",
      "to_stop_id": "adjacent_stop_id",
      "time": 123,
      "path": [
        {
          "lat": 48.123,
          "lon": 2.123
        }
      ]
    }
  ]
}

Un problème que je vois, c'est quand je vais vouloir ajouter une station, j'aimerais :

  • ajouter un unique point sur la carte
  • s'il y a des liaisons, les ajouter

Mais, en l'état, je ne vois pas comment je choisis la station à afficher. Il me faut peut-être une liste de stations sans relation, qui est uniquement le point à afficher si la station est seule. Je vais chercher dans les données.

Il y a bien 2 versions :

Cool, ça répond à mon besoin et améliora l'application.

Donc comment je représente le json :

{
  "routes": [
    {
      "route_id": "route_id",
      "route_name": "route_name",
      "route_color": "route_color"
    }
  ],
  "stops": [
    {
      "name": "stop_name",
      "id": "stop_id",
      "route_id": "route_id"
    }
  ],
  "adjacents": [
    {
      "from_stop_id": "stop_id",
      "to_stop_id": "adjacent_stop_id",
      "time": 123,
      "path": [
        {
          "lat": 48.123,
          "lon": 2.123
        }
      ]
    }
  ],
  "stops_unique": [
    {
      "name": "stop_name",
      "lat": 48.123,
      "lon": 2.123
    }
  ]
}

J'ai l'impression qu'avec ça je peux répondre à tout ce que je veux faire.

Pour ce qui est d'intéragir avec la base de données, je fais un combo dont j'ai l'habitude : knex et pg.

En moins d'1 minute avec un copier/coller d'un autre projet, j'ai quelque chose d'opérationnel.

J'enchaine ensuite, avec la création de la migration, je m'aide du schéma de MobilityDB, je demande à Mistral en Local de me le convertir en knex schema builder. Cela fonctionne plutôt bien.

Pour les données, je crée des fonctions en TDD pour insérer les données. Puis, j'essaie de parser le csv en stream pour les insérer en base. Cela ne fonctionne pas comme je veux je regarderai demain.

Ressources