Analyse d’accessibilité multimodale
Avec R et OpenTripPlanner
Cette fiche présente une méthodologie d’analyse de l’accessibilité multimodale d’un territoire à partir des données ouvertes d’offre de transport et de mobilité et du logiciel OpenTripPlanner mobilisé depuis l’environnement R.
1 Introduction
L’analyse de l’accessibilité multimodale est au coeur des politiques de transport, et constitue l’un des enjeux majeurs de la planification territoriale. L’émergence de nouvelles données de suivi de l’offre de transport et d’outils adaptés à leur analyse permet aujourd’hui de porter un regard fin sur le domaine. C’est le cas de l’outil OpenTripPlanner qui fait l’objet de ce tutoriel.
Celui-ci a été construit dans le but d’accompagner son apprentissage via l’usage du langage R, et se distingue des documentations existantes par l’entrée thématique qu’il propose. Il repose sur un cas d’étude illustratif des potentialités d’analyse offertes par le croisement d’OTP et des nouvelles données ouvertes décrivant l’offre de transport : la métropole de Montpellier (Montpellier Méditerranée Métropole ou Montpellier 3M).
1.1 Accessibilité multimodale
L’accessibilité est un concept utilisé en géographie pour qualifier “la plus ou moins grande facilité avec laquelle [un] lieu peut être atteint à partir d’un ou de plusieurs autres lieux, par un ou plusieurs individus susceptibles de se déplacer à l’aide de tout ou partie des moyens de transport existants” (Laurent Chapelon in Encyclopédie Hypergeo).
Étudier l’accessibilité multimodale d’un lieu ou d’un ensemble de lieux revient donc à mesurer puis à comparer les possibilités de déplacement et leur pénibilité associée en tenant compte de l’ensemble des modes : transports en commun, marche, vélo, voiture, notamment.
1.2 Le projet OpenTripPlanner
OpenTripPlanner est un logiciel libre développé en Java permettant de créer et d’interroger un planificateur d’itinéraire multimodal personnalisé. Créé en 2009 pour TriMet, l’agence de transport en commun de Portland (Oregon), par l’équipe d’informaticiens du consultant Conveyal, OTP s’est ensuite développé, et englobe aujourd’hui une communauté mondiale d’utilisateurs et de développeurs.
L’analyse de l’accessibilité par des réseaux de transport multimodaux, opérant à différentes échelles et gérés par des autorités organisatrices variées, marque une étape importante dans le champ de la géographie des transports. Les déplacements optimaux déterminés par OTP correspondent au plus court chemin, c’est-à-dire à la minimisation du temps de déplacement pour l’usager? Ces temps sont calculés en utilisant les algorithmes de Dijkstra (Dijkstra et al. 2021), A* (Hart et al. 1968) et assimilés. L’intermodalité (combinaison de plusieurs modes et réseaux de transport) et l’intramodalité (combinaison de plusieurs véhicules au sein d’un même réseau de transport) sont également intégrées dans OTP, avec la gestion optimale des correspondances (minimisation du temps de marche entre deux arrêts et du temps d’attente). OTP se prête donc aux analyses territoriales de l’accessibilité, en simulant les meilleurs déplacements possibles pour l’usager en fonction des différents modes de transport à sa disposition pour un horaire donné.
Brièvement, OTP construit un graphe décrivant les itinéraires reliant l’ensemble des localisations d’un territoire donné, en transport en commun comme par la route, à partir de données GTFS (General Transit Feed Specification) pour le réseau de transport en commun (bus, métros, tramways, trains) et de données OpenStreetMap pour les modes de transport individuels qui utilisent le réseau viaire (voiture, vélo, piéton). Le logiciel dépend donc de données ouvertes renseignées dans des formats de fichier standards. Sur ce point, rappelons que les autorités organisatrices de la mobilité (AOM) ont l’obligation de transmettre leurs données de l’offre de transport (règlement européen 2017/1926, art. 25 de la LOM de 2019) sur le point d’accès national (PAN).
Le code source d’OTP est publié en accès libre sur la plateforme GitHub.
Notons l’existence de la bibliothèque r5r
qui utilise
le logiciel Java open source R5, dérivé d’OpenTripPlanner. Il a été mis
en place par l’équipe de consultant informatique Conveyal et adapté à R
par Pereira et al. (2021). Il propose des fonctionnalités
analogues à la bibliothèque opentripplanner
(calcul
d’accessibilité, matrice O/D, isochrones, etc.).
1.3 Ressources
Les principales ressources recommandées en complément de ce tutoriel sont disponibles aux liens suivants :
2 Les données de l’offre de transport
2.1 Les données GTFS
2.1.1 Présentation générale
L’offre de transport théorique dans un territoire peut être étudiée à partir de données croisant les itinéraires (organisation des parcours et localisation des arrêts) et les horaires de passage des véhicules.
Deux formats de données statiques sont privilégiés :
NeTEx (Network Timetable Exchange), répondant aux critères établis par le Comité européen de normalisation en électronique et en électrotechnique
GTFS (General Transit Feed Specification), répondant aux critères spécifiques des flux Google Transports en commun public. Les données doivent être validées par le validateur GTFS de Google.
2.1.2 Exemple des données de Montpellier 3M
Nous utiliserons dans ce tutoriel le cas de la métropole de Montpellier. La métropole est constituée de 31 communes comptant 499 761 habitants en 2020 (INSEE RP2020). Elle détient la compétence d’autorité organisatrice des mobilités (AOM) sur son ressort territorial et opère 4 lignes de tramway et 41 lignes de bus. Cet exemple servira d’illustration des méthodes présentées dans cette fiche afin de disposer d’un cas d’étude simplifié, mais d’autres échelles territoriales sont bien sûr possibles en ajoutant les données de l’offre en adéquation avec l’échelle d’analyse (offre régionale, ferroviaire, autres AOM locales, etc.). Les données renseignant l’offre de transport théorique de TAM (Transports de l’agglomération de Montpellier) sont fournies au format GTFS depuis le point d’accès national aux données de transport, et peuvent être converties au format GeoJSON et au format NeTEx directement depuis le site de téléchargement.
L’extraction des données utilisées pour ce tutoriel a été réalisée le 27 mars 2023. Elles décrivent l’offre de transport de façon statique pour la période s’écoulant du 16 mars 2023 au 14 mai 2023. Les données utilisées pour ce tutoriel ont été actualisées pour la dernière fois à la date du 25 mars 2023.
Le dossier contient différents fichiers au format texte, renseignant chacun une partie du système de transport sous la forme d’un tableau de données utilisant des virgules comme séparateurs de colonnes :
agency : le fichier contient des informations sur les compagnies (agences) de transport en commun opérant sur le réseau étudié (ex : identifiant, nom, site Web, téléphone, fuseau horaire…)
routes : le fichier catalogue les lignes du réseau de transport, qu’il décrit par le biais d’identifiants et de noms courts ou longs, par type de transport, par mode de ramassage et de descente, et d’autres informations plus ou moins formalisées. Une couleur peut être associée à une route afin d’en faciliter le repérage par les utilisateurs
trips : le fichier décrit les itinéraires réalisés sur les routes (lignes), notamment par le biais d’informations sur les sens de déplacement et les dates de service (blocks). Plusieurs trips peuvent donc avoir lieu sur une même route
stops : le fichier identifie, nomme, géolocalise (coordonnées lat/long) et caractérise (ex : type d’arrêt, identifiant de l’emplacement parent, accessibilité aux personnes en fauteuil roulant…) les arrêts du réseau
stop_times : le fichier renseigne, pour chaque itinéraire (trip) concerné, les heures de passage (arrivée et départ) à l’arrêt. Des informations sur les modes de rammassage/descente, l’affichage sur les panneaux et d’autres caractéristiques des arrêts sont proposées. L’ordonnancement des passages aux arrêts pour un itinéraire particulier est également consigné
transfers : le fichier est optionnel. Il permet de spécifier les règles de transit entre deux arrêts, en termes d’éloignement géographique et de durée de déplacement à pied, ou, comme avec les données de la TAM, sous la forme d’une variable catégorielle qui renseigne sur la possiblité de réaliser un transfert entre deux arrêts (transfert recommandé, programmé, possible sous contrainte de temps ou impossible)
calendar : le fichier recense les dates pour lesquelles un service est fonctionnel : une date de début et une date de fin indiquent la plage de dates d’activité du service, et, pour chaque jour de la semaine (lundi à dimanche), une variable renseigne sur la disponibilité (ou l’indisponibilité) du service pour l’ensemble des lundis (resp. mardis, mercredis, jeudis, vendredis, samedis et dimanches) de la plage
calendar_dates : le fichier renseigne sur les exceptions au service régulier consigné dans le fichier calendar. Il peut par exemple servir à indiquer les changements d’activité du service (ajout ou suppression) du fait d’un événement particulier, ou pour s’adapter à un calendrier scolaire.
De nombreuses dépendances existent donc entre les différents fichiers constituant la base de données GTFS, et ces fichiers peuvent être plus ou moins nombreux comme l’illustre le diagramme de classe proposé sur la page Wikipédia associée et reproduite ci-dessous.
2.2 Les données OpenStreetMap
L’utilisation du réseau viaire (routes, chemins) est indispensable pour calculer les itinéraires des modes individuels (voiture, piéton et cycliste) et des modes collectifs (pré et post-acheminement, gestion des correspondances). Pour cela, nous utiliserons les données issues du projet de cartographie collaborative OpenStreetMap (OSM).
La complétude et la précision des données varient d’un territoire, d’une échelle géographique et d’une temporalité à l’autre (Herfort et al. 2022). Il faut donc être vigilant à cet aspect en amont de leur utilisation dans le cadre d’une analyse d’accessibilité qui utilise le réseau viaire. En France, la plateforme recense l’ensemble des données géographiques publiques en open data en complément de l’information géographique volontaire. Une présentation des données OSM est par exemple proposée par Mericskay (2017).
2.2.1 Téléchargement des données depuis la Geofabrik
La société allemande Geofabrik GmbH propose au téléchargement des instantanés de la base de données OSM pour un espace géographique donné. L’échelle géographique la plus fine correspond aux anciennes régions françaises. Les données décrivant la métropole de Montpellier Méditerranée sont donc contenues dans le paquet décrivant le Languedoc-Roussillon.
La bibliothèque osmextract
permet de télécharger et
d’importer facilement des données OpenStreetMap de Geofabrik et
d’autres fournisseurs depuis R.
Nous allons utiliser le fichier décrivant les limites de la métropole
de Montpellier Méditerranée afin de créer un filtre spatial lors du
téléchargement des données OSM depuis la Geofabrik. Pour cela, nous
l’importons dans le projet en cours via la fonction
st_read()
de la bibliothèque sf
.
Le fichier GeoJSON décrivant le territoire de la métropole de Montpellier est disponible ici :
La fonction oe_get()
de la bibliothèque
osmextract
permet d’associer par le biais d’une relation
d’appartenance géographique un lieu d’entrée (option place
)
avec l’URL du fichier .osm.pbf correspondant (dans le cas de la
métropole de Montpellier, il s’agit de l’ancienne région
Languedoc-Roussillon), qu’elle enregistre dans une liste puis
télécharge. Le paramètre boundary
permet d’associer un
filtre spatial à la requête, et de ne télécharger que les objets
contenus dans les limites géographiques désignées (et renseignées au
format sf/sfc/bbox). Notons que la fonction appelle en interne la
fonction oe_vectortranslate()
qui converti le fichier
.osm.pbf en fichier geopackage (.gpkg) avant de le lire. Le
filtre spatial ne s’applique que sur le fichier .gpkg qu’elle
télécharge, et pas sur le fichier .osm.pbf étant lui aussi téléchargé.
Des options d’enregistrement du fichier peuvent être ajoutées, par
exemple afin de forcer la mise à jour si le fichier a été téléchargé
auparavant (paramètre force_download
) ou pour indiquer le
chemin d’accès du répertoire dans lequel enregistrer le fichier
(paramètre download_directory
) en remplacement de la valeur
par défaut (répertoire temporaire).
contours_3m <- st_as_sf(st_union(epci_3m))
osm_3m <- oe_get(place = contours_3m,
boundary = contours_3m,
force_download=TRUE,
download_directory=getwd())
Notons qu’il est possible d’extraire les données OSM au format .pbf depuis une source externe, comme le propose le site BBBike extract par exemple. Le site permet notamment de définir un cadre de délimitation (bounding box) pour les informations spatiales à télécharger, ce qui réduira a posteriori la taille du graphe construit pour lancer les requêtes OTP.
2.2.2 Description des données .osm.pbf
Le format des données ainsi téléchargées (Protocolbuffer Binary Format) est spécifique au projet OpenStreetMap, mais utilise le format de sérialisation de Google pour produire un fichier au format binaire. Il permet de regrouper des informations multiples (entités, objets, tuiles) de façon indépendante.
Par curiosité (mais cela n’est pas une étape nécessaire pour la mise
en oeuvre de la chaîne de traitements), on peut importer les couches
d’information géographique souhaitées une à une ou de façon groupée via
la fonction st_read()
, en spécifiant la couche (organisée
par type de géométrie) et en créant une requête sur les attributs, par
exemple en sélectionnant les routes (key = highway) dans la
couche.
2.3 Relations entre données GTFS et données OpenStreetMap
Si un arrêt de transport, localisé par le GTFS, se trouve dans un bâtiment, il est nécessaire d’être vigilant à sa connexion au graphe OpenStreetMap, sans quoi l’isolement de l’arrêt rendra impossible les parcours à pied (impossibilité de créer les pré- et post-acheminements ainsi que les correspondances à pied entre deux arrêts).
Par exemple, les cheminements piétons dans les gares ne sont pas systématiquement renseignés dans OpenStreetMap, ni les escaliers ou ascenseurs permettant de changer de quai. D’expérience, les gares les plus importantes sont correctement géoréférencées mais toutes ne le sont pas. Un arrêt isolé du graphe piéton ne permet pas au logiciel de comprendre qu’il peut entrer et sortir de la gare, ou réaliser une correspondance entre un TGV et un TER dans la même gare s’il doit s’y déplacer, faute d’un graphe piéton disponible.
Un arrêt de transport renseigné peut aussi avoir des coordonnées géographiques erronées qu’il est indispensable de modifier.
Il nous semble que deux solutions peuvent alors être envisagées :
Contribuer à OpenStreetMap pour ajouter les informations manquantes. Les données .osm.pbf, parmi d’autres formats disponibles, de la Geofabrik sont quotidiennement mises à jour
Modifier la localisation du point d’arrêt créé par le GTFS. Cela peut être intéressant pour déplacer un arrêt avec des coordonnées imprécises ou erronées. Ainsi, le point peut être replacé dans un espace connecté au graphe piéton, comme l’entrée de la gare. Les coordonnées des arrêts sont rangées dans le fichier stops.
3 Préparation de l’environnement R pour OTP
3.1 La bibliothèque
opentripplanner
OTP étant défini en Java, son fonctionnement nécessite l’entrée de
lignes de commandes Java. La bibliothèque opentripplaner
permet de définir les paramètres de ces fonctions depuis R et de les
traduire automatiquement en Java.
La version de la bibliothèque R utilisée pour ce tutoriel est la 0.5.2, publiée en janvier 2023 et téléchargée depuis le CRAN le 21 mai 2024. Son exécution nécessitera l’installation préalable de Java 8. Attention, des conflits avec des versions postérieures ou ultérieures de Java sont à attendre, il est donc recommandé de désinstaller ces versions en amont de l’installation de Java 8 et du lancement d’OTP.
Cette partie du tutoriel est basée sur la documentation proposée par Marcus Young, Malcom Morgan et Robin Lovelace, les développeurs du package.
3.2 Installation d’OTP
Nous allons donc utiliser OTP en local, en téléchargeant la version 1.5 du logiciel depuis R (il s’agit de la version compatible avec la version 0.5 de la librairie R, d’autres versions d’OTP plus récentes ont vu le jour depuis).
3.2.1 Création du répertoire
OTP est distribué sous la forme d’un unique fichier .jar (Java ARchive) exécutable de façon autonome. Dans un premier temps, nous allons créer le répertoire dans lequel l’enregistrer.
La fonction file.path()
permet de spécifier le chemin
d’accès vers un fichier en concaténant des chaînes de caractères. Par
défaut, le séparateur utilisé est “/
”.
3.2.2 Pré-construction du fichier .jar
La fonction otp_dl_jar()
de la bibliothèque
opentripplanner
télécharge le fichier JAR (Java
Archive) d’OTP. Par défaut, le fichier JAR est caché dans un
sous-répertoire de la bibliothèque. Si l’on souhaite spécifier la
localisation du fichier .jar, il faut en indiquer le chemin d’accès
(path =
) et spécifier que l’on ne souhaite pas utiliser le
cache par défaut (cache = FALSE
).
Il faudra penser à commenter cette ligne de code une fois le téléchargement réalisé afin de ne pas le ré-exécuter à chaque relance du script.
Si le téléchargement du fichier via R ne fonctionne pas, vous pouvez télécharger manuellement le fichier depuis le dépôt maven.
On indique ensuite dans un vecteur au format “caractères” le chemin d’accès complet vers l’archive d’OTP :
3.3 Préparation des fichiers d’entrée
En amont de la création du graphe sur lequel les calculs d’itinéraires seront réalisés par OTP, il est nécessaire de regrouper les fichiers d’entrée au sein du répertoire contenant le fichier JAR :
créer un sous-répertoire nommé
graphs
(/graphs)à l’intérieur du sous-répertoire
graphs
, créer un nouveau sous-répertoire nommédefault
(/graphs/default)dans le sous-répertoire
default
, déposer le fichier .osm.pbf du Languedoc-Roussillon et le fichier contenant les données GTFS au format zippé (gtfs.zip).
3.4 Création du graphe
Afin de construire les itinéraires, OTP reconstitue via la fonction
otp_build_graph()
un graphe des cheminements possibles à
partir des données d’entrée susmentionnées. Ce graphe permet de gagner
un temps substantiel pour démarrer de nouvelles sessions d’OTP, à la
manière d’une sauvegarde des réseaux.
Le paramètre otp
indique le chemin d’accès vers
l’archive Java d’OTP (fichier OTP .jar).
Le paramètre dir
indique le chemin d’accès vers le
répertoire contenant les fichiers nécessaires à la génération du
graphe.
Le paramètre memory
prend un nombre entier qui renseigne
la quantité de mémoire à attribuer à OTP (par défaut 2048 Mo). La
quantité de mémoire dépend de la taille de l’espace géographique à
l’étude, de la puissance de votre machine et de la version de Java
utilisée (idéalement du 64 bits, vous serez limités à quelques Go si
vous utilisez le 32 bits).
Le territoire métropolitain de Montpellier correspond à un espace géographique de taille intermédiaire, nous allons donc demander à utiliser 10 Go de mémoire (c’est-à-dire 10 000 Mo). Cette valeur est à définir en fonction des capacités de votre ordinateur et de votre aire d’étude.
Notons ici qu’OTP est optimisé pour réaliser des routages à l’échelle d’une ville et que ses performances se dégraderont avec de plus grandes zones.
Une fois le graphe construit, il est recommandé de passer la ligne en commentaire afin de ne pas relancer la procédure à chaque exécution du code.
3.5 Synthèse de l’organisation du dossier OTP
Nous pouvons résumer l’organisation du dossier OTP ainsi :
Un fichier router-config.json
, facultatif pour démarrer
une session OTP, pourra être ajouté dans un second temps pour modifier
des paramètres de déplacement (voir partie 4.5). Le fichier
Graph.obj
est lui, par contre, indispensable pour démarrer
une cession OTP. Il sera créé dans l’environnement R.
Pour reproduire le prochain exemple, le répertoire OTP et les données sont disponibles sur Zenodo :
4 Lancer OTP
4.1 Générer une instance locale du serveur OTP
Il est ensuite nécessaire d’installer une instance locale du
logiciel. Nous la créons grâce à la fonction otp_setup()
,
qui lance le calculateur d’itinéraires (default router) par
défaut via une interface Web. Cette procédure peut prendre quelques
minutes.
OTP dispose d’un serveur
Web Grizzly intégré qui s’exécute sur les ports 8080 (http) et 8081
(https). Les options port
et securePort
de la
fonction permettent d’indiquer des ports alternatifs si les ports par
défaut sont utilisés par d’autres applications en cours.
La session d’OTP est alors démarrée en local, et une fenêtre s’ouvre dans un navigateur Web afin d’accéder à l’interface graphique du logiciel.
L’interface graphique de l’application Web d’OTP permet de zoomer/dézoomer sur l’espace d’étude, de spécifier des dates et des durées de déplacement à pied, le mode de transport à considérer (et d’en paramétrer l’usage), ou encore de modifier le fond de carte.
4.2 Paramétrer une requête depuis l’interface graphique
Pour rechercher un itinéraire depuis OTP, il est possible de désigner les lieux d’origine et de destination par leurs couples de coordonnées de longitude et de latitude ou de renseigner des noms d’arrêts issus des données d’entrée.
Pour définir un point de départ, sans en connaître les coordonnées de longitude/latitude ou le nom d’arrêt au préalable, il est possible de le sélectionner directement depuis la fenêtre graphique comme suit :
Notons ici l’importance des bornes temporelles de validité des fichiers GTFS dans l’obtention d’une réponse à une requête. OTP ne sera en effet pas en capacité de trouver un déplacement pour des périodes en amont ou en aval des dates renseignées dans le fichier calendar.
D’autres paramétrages sont directement accessibles depuis l’interface, comme l’illustre l’exemple ci-dessous.
4.3 Connecter R à l’instance locale d’OTP
Afin d’automatiser les procédures, il est intéressant d’exécuter OTP depuis R, en lui soumettant des lignes de commande personnalisées.
La fonction otp_connect()
permet de tester et de créer
une connexion à OTP depuis R. Plusieurs paramètres peuvent être passés
en option, tels que le fuseau horaire (timezone) à partir
duquel construire les requêtes (par défaut, la valeur est celle de votre
machine), la version d’OTP (par défaut, la version renseignée est 1.5),
ou encore le port utilisé pour la connexion (par défaut, le numéro de
port utilisé est 8080).
4.4 Arrêter l’instance locale d’OTP
Le lancement d’OTP a automatiquement démarré Java, qui s’exécute hors
de l’environnement R. Il faut donc penser à arrêter OTP et Java lorsque
l’on quitte la session R à partir de laquelle une session OTP avait été
lancée. On utilise pour cela la fonction otp_stop()
.
Un message s’affiche, afin de valider la clôture de Java induite par
la commande otp_stop()
: “This will force Java to
close, Press [enter] to continue, [escape] to abort”. Notons ici
qu’en pressant sur [enter]
, toutes les applications
utilisant Java seront arrêtées.
4.5 Configurer les options de déplacement
4.5.1 Créer manuellement les fichiers de configuration
OTP permet de configurer les options de déplacement à prendre en compte lors du déploiement de l’application (version personnalisée d’OTP) à l’aide de trois types de fichiers au format JavaScript Object Notation (.json) :
build-config.json
renseigne les éléments indispensables à la génération du graphe, par exemple en spécifiant les fichiers GTFS sources pour différents systèmes de transports en commun fonctionnant sur le territoire ou en indiquant que l’on souhaite que les transferts entre arrêts d’une même station de transport (par exemple, de métro) soient privilégiés :
router-config.json
contient des options de configuration d’exécution mobilisées lors du setup (i.e.otp_setup()
) qui peuvent donc être modifiées une fois le graphe construit. On peut par exemple spécifier les durées maximales de recherche d’un itinéraire et de ses alternatives avec l’optiontimeouts
ou modifier le sens de circulation par défaut sur le réseau routier par l’optiondriveOnRight: false
:
otp-config.json
contient des commutateurs simples qui activent ou désactivent les fonctionnalités à l’échelle du système. La plupart des applications ne nécessitent pas la modification de ce fichier.
De nombreux paramètres peuvent ainsi être ajoutés dans le fichier de configuration du serveur OTP (voir la présentation en ligne). Des exemples de fichiers de configuration sont disponibles en ligne. Notons toutefois qu’OTP fournit des valeurs par défaut qu’il définit comme raisonnables. Les trois fichiers sont donc optionnels, tout comme les options à l’intérieur de chacun.
4.5.2 Modifier les paramètres via des fonctions R
La bibliothèque opentripplanner
propose plusieurs
fonctionnalités afin de faciliter la configuration de l’instance
OTP.
La fonction otp_make_config()
crée un fichier de
configuration, de type router
, build
ou
otp
.
Le fichier est organisé sous la forme de quatre listes, comprenant chacune un ensemble d’objets :
$routingDefaults
: liste la série de paramètres par défaut, par exemple la vitesse de marche ($routingDefaults$walkSpeed
)$boardTimes
: liste les paramètres de configuration des temps d’embarquement par mode de transport$alightTimes
: liste les paramètres de configuration des temps de démarrage par mode de transport$timeouts
: liste les délais maximums de calcul des 1er, 2e, 3e, etc. itinéraires.
NULL
à 120 secondes.
La fonction otp_validate_config()
génère des tests de
validité d’un l’objet de configuration. Un problème régulièrement
rencontré est l’erreur de typage des paramètres de la fonction
(integer, numeric, etc.).
Une fois le paramètrage du fichier de configuration finalisé, la
fonction otp_write_config()
permet de l’exporter au format
JSON.
Les configurations du routeur sont prises en compte lors du lancement du serveur OTP et ne peuvent être mobilisées alors qu’une session est en cours. Nous allons donc nous déconnecter puis nous reconnecter à l’instance locale d’OTP pour pouvoir en tenir compte lors de nos analyses.
otp_stop()
otp_setup(otp = path_otp, dir = path_data, router = "default")
my_otpcon <- otp_connect(timezone = "Europe/Paris", router = "default")
5 Création d’itinéraires
Les recherches d’itinéraires constituent un premier levier d’analyse de l’accessibilité d’un lieu ou d’un ensemble de lieux depuis un ou plusieurs points de départ.
5.1 Requête unique
La fonction otp_plan()
permet d’obtenir un ou des
itinéraires connectant un point d’origine (fromPlace
) à un
point d’arrivée (toPlace
). Tout comme sur l’interface
graphique, les lieux sont définis par un couple de coordonnées de
longitude et de latitude, à la différence qu’ici les latitudes sont
renseignées en premier et les longitudes ensuite. On combine
classiquement ces deux valeurs dans un vecteur via la fonction
c()
(combine).
Notons que pour utiliser des noms d’arrêts comme lieu de départ et
d’arrivée, il faut remplacer les arguments
fromPlace
/toPlace
par les arguments
fromID
/toID
.
L’argument otpcon
renseigne l’objet de connexion OTP
produit avec la fonction otp_connect()
.
L’argument mode
désigne les modes de transport à
considérer pour le calcul de l’itinéraire : TRANSIT
(déplacement en transport en commun, tous modes confondus),
BUS
(déplacement en bus), TRAM
(déplacement en
tramway), RAIL
(déplacement en train), WALK
(déplacement piéton), BICYCLE
(déplacement à vélo),
CAR
(déplacement en voiture), etc. Par défaut, le
déplacement est calculé pour un voyage en voiture.
Il est possible d’indiquer des combinaisons de modes de déplacement
(parmi les options
proposées par OTP). Par exemple, une combinaison
c("CAR", "TRANSIT")
permet de décrire des déplacements de
type kiss and ride, où un usager est déposé en voiture à une
station de transport en commun sans avoir lui-même à garer le véhicule
automobile. La combinaison c("CAR_PARK", "TRANSIT")
permet
quant à elle de décrire des déplacements pour lesquels l’usager se
déplace en voiture jusqu’à un parking relais à proximité d’un arrêt de
transport en commun puis emprunte ce réseau.
Le paramètre date_time
renseigne la date et l’heure de
départ au format POSIXct. Par défaut, la date et le jour courants sont
utilisés.
date_time = as.POSIXct("2023-04-19 14:15:00")
pourrait
requêter à 2h15 le matin au lieu de 14h15 l’après-midi. Si c’est le cas,
vous devez spécifier à chaque nouvelle session R
Sys.setlocale("LC_TIME", "en_US.UTF-8")
dans la console
(voir la résolution
du problème en ligne.
D’autres paramètres optionnels sont proposés, parmi lesquels :
maxWalkDistance
qui indique la distance maximale (en mètres) à parcourir à pied sur l’ensemble du déplacementarriveBy
qui permet de définir l’heure d’arrivée (arriveBy = TRUE
) via le paramètredate_time
plutôt que l’heure de départ (par défaut,arriveBy = FALSE
)numItineraries
qui permet de restreindre le nombre d’itinéaires en sortie.
route <- otp_plan(otpcon = my_otpcon,
fromPlace = c(3.87943, 43.60844),
toPlace = c(3.96915, 43.54009),
mode = "BICYCLE",
date_time = as.POSIXct("2023-04-19 10:15:00"))
Le résultat de la requête est un tableau de données
(dataframe
) décrit au format simple features de la
bibliothèque du même nom (sf
).
Le déplacement proposé est composé de trois étapes (legs), chacune étant caractérisée par un mode de transport, recensées dans l’ordre du cheminement. La somme de leurs distances et de leurs durées correspond ainsi à la distance (en mètres) et à la durée (en secondes) du déplacement total :
[1] 11833.17
[1] 2713
5.2 Requêtes multiples
L’intérêt d’instruire des requêtes OTP par lignes de commande est certainement de pouvoir générer des demandes multiples, par exemple, en étudiant les temps de déplacement nécessaires pour se déplacer d’une origine à une destination à différents moments de la journée, en définissant une liste de lieux de départ pour un même lieu d’arrivée ou encore pour des plages horaires différenciées.
Le format des paramètres fromPlace
et
toPlace
peut être varié : couple de paires de
longitude/latitude, matrice à deux colonnes décrivant les paires de
longitude/latitude ou encore objet sf
contenant des
géométries ponctuelles décrites dans le système de coordonnées WGS 84
(EPSG 4326).
coord_origine <- as.matrix(rbind(c(3.86459, 43.69760), c(4.01288, 43.66112)))
coord_dest <- c(3.89695, 43.59880)
route_2 <- otp_plan(otpcon = my_otpcon,
fromPlace = coord_origine,
toPlace = coord_dest,
mode = c("TRANSIT", "WALK"),
date_time = as.POSIXct("2023-04-19 10:15:00"))
La localisation des déplacements peut aisément être obtenue et
cartographiée. L’exemple ci-dessous utilise la fonction
annotation_map_tile()
de la bibliothèque
ggspatial
afin d’ajouter un fond à la carte générée via la
fonction geom_sf()
de la bibliothèque ggplot2
.
Nous activerons également la bibliothèque prettymapr
qui
est reliée à ggspatial
pour afficher cette fonction. La
fonction annotation_map_tile()
est accompagnée du paramètre
data = route_2
afin de centrer la carte sur les données
spatiales. Par défaut, le fond de carte affiché est celui
d’OpenStreetMap. La liste des fonds de carte disponibles est accessible
via la fonction rosm::osm.types()
.
library(ggplot2)
library(ggspatial)
library(prettymapr)
ggplot() +
annotation_map_tile (data = route_2) +
geom_sf(data = route_2, col = "red", linewidth = 1) +
annotate(geom = "point", x = coord_dest[1], y = coord_dest[2], colour = "black", size = 2)
L’usage de l’argument get_geometry = FALSE
dans la
fonction otp_plan()
permet, à l’inverse,
d’abandonner leur géométrie. Cette action permet notamment de
gagner en temps de calcul lorsque les lieux sur lesquels opérer les
requêtes sont nombreux et que l’on s’intéresse aux attributs des
déplacements.
route_3 <- otp_plan(otpcon = my_otpcon,
fromPlace = coord_origine,
toPlace = coord_dest,
mode = c("TRANSIT", "WALK"),
date_time = as.POSIXct("2023-04-19 10:15:00"),
get_geometry = FALSE)
library(dplyr)
route_3b <- route_3 %>%
distinct(fromPlace, route_option, .keep_all = TRUE) %>%
select(fromPlace, toPlace, duration)
library(tidyr)
time_matrix <- pivot_wider(data = route_3b, names_from = toPlace, values_from = duration)
On peut également choisir de ne garder au sein de la matrice que la durée de déplacement minimale pour chaque couple origine/destination. L’usage des coordonnées géographiques pour désigner les lieux d’origine et de destination n’est ni usuel, ni pratique. Nous allons donc également les modifier.
route_3c <- route_3 %>%
distinct(fromPlace, route_option, .keep_all = TRUE) %>%
select(fromPlace, toPlace, duration) %>%
group_by(fromPlace) %>% slice(which.min(duration))
route_3c$fromPlace <- c("Ori_1", "Ori_2")
route_3c$toPlace <- "Dest_1"
time_matrix_2 <- pivot_wider(data = route_3c,
names_from = toPlace,
values_from = duration)
Ces matrices peuvent par exemple être retranscrites graphiquement sous la forme de cercles proportionnels au temps de déplacement entre les lieux.
# passage de la matrice au format long pour faciliter sa mise en page
# graphique via la fonction melt de la bibliothèque reshape2
library(reshape2)
tabCont_time_matrix_2 <- melt(time_matrix_2)
# construction d'un graphique en cercles proportionnels
# avec la bibliothèque ggplot2
library(ggplot2)
ggplot(tabCont_time_matrix_2,
aes(x = variable,
y = fromPlace)) +
geom_point(aes(size = value), color = "blue") +
scale_size(range = c(2, 4),
breaks = c(4431, 4981),
labels = c("4431", "4981"),
name = "Temps (sec)",
guide = "legend") +
labs(title = "Durée estimée des déplacements",
x = "Destination",
y = "Origines") +
theme_minimal()
5.3 Cartes d’itinéraires interactives
Le code ci-dessous présente un exemple de cartographie interactive
réalisée avec la bibliothèque leaflet
pour R.
Nous représenterons le déplacement calculé dans l’objet
route
de la partie 5.1.
Pour centrer la carte, nous allons dans un premier temps utiliser les
données géospatiales décrivant les contours de la métropole de
Montpellier. Le package leaflet
fonctionnant avec des
données non projetées, nous utilisons la fonction
st_transform()
de la librairie sf
afin de
transformer le système de projection de la couche.
Les fonctions st_centroid()
et
st_coordinates()
de la librairie sf
permettent
respectivement de définir le centroïde du polygone et d’en récupérer les
coordonnées au sein d’une matrice. Les longitudes sont données dans la
première colonne et les latitudes dans la seconde.
Notons que le GeoJSON epci_3m
a été téléchargé et chargé
dans la partie 2.2.1.
epci_3m_4326 <- st_transform(epci_3m, 4326)
centro_3m <- st_centroid(epci_3m_4326)
lat_centro_3m <- median(st_coordinates(centro_3m)[,2])
lon_centro_3m <- median(st_coordinates(centro_3m)[,1])
Nous faisons ensuite appel aux fonctionnalités de la bibliothèque
leaflet
afin de construire la carte interactive de l’objet
route
que nous venons de créer :
setView()
permet de définir la vue de départ, en indiquant son centre géographique par un couple de coordonnées et un niveau de zoom allant de 0 (monde) à 18 (rue)addPolylines()
permet d’ajouter des objets géographiques de type polylignes. Par défaut, les géométries sont celles des données renseignées dans la fonctionleaflet
de génération de la carte interactive (ici l’objet route au formatsf
). On peut choisir d’ajouter des fenêtres contextuelles (pop-up), par exemple sous la forme d’une étiquette apparaissant au passage du curseur sur l’objet. Parmi les nombreux paramètres de mise en forme disponibles,color
etweight
permettent respectivement de contrôler la couleur et l’épaisseur (en pixels) des traitsaddProviderTiles()
permet d’ajouter un fond de carte interactif d’un des principaux fournisseurs (OpenStreeMap, CartoDB, Stamen, Thunderforest, etc.). La liste complète est accessible via la commandenames(providers)
.
library(leaflet)
leafMap <- leaflet(data = route) %>%
setView(lat = lat_centro_3m,
lng = lon_centro_3m,
zoom = 10) %>%
addPolylines(popup = ~paste("Durée : ", round(duration/60)," minute(s)"),
color = "#e31a1c",
weight = 4) %>%
addProviderTiles(providers$CartoDB.Positron)
leafMap
Nous pouvons également choisir de représenter les étapes du
déplacement par des couleurs différenciées selon le mode de transport.
Dans un premier temps, nous associons une couleur (de la palette
Set1
proposée dans la bibliothèque
RColorBrewer
) par mode. Il est possible de visualiser plus
en détail la deuxième étape du déplacement en entrant des coordonnées
géographiques définies dans le paramètre setView
(setView(lat = 43.608887, lng = 3.880381)
) et en augmentant
le niveau de zoom
(zoom = 18
).
mycol <- colorFactor(
palette = 'Set1',
domain = route$leg_mode
)
leafMap <- leaflet(data = route) %>%
setView(lat = 43.608887,
lng = 3.880381,
zoom = 18) %>%
addPolylines(popup = ~paste("Durée : ", round(duration/60)," minute(s)"),
color = ~mycol(leg_mode),
weight = 4) %>%
addProviderTiles(providers$CartoDB.Positron)
leafMap
Nous allons enfin choisir d’adapter le contenu des fenêtres
contextuelles aux étapes du déplacement, par exemple en affichant le
mode de transport et la durée de l’étape. Pour séparer ces deux types de
contenus informationnels (que nous afficherons en gras grâce à la balise
HTML <strong></strong>
), nous utiliserons la
balise HTML <br>
(break line) afin de créer
un saut de ligne.
leafMap <- leaflet(data = route) %>%
setView(lat = 43.608887,
lng = 3.880381,
zoom = 18) %>%
addPolylines(popup = ~paste("<strong>Durée de l'étape :</strong> ",
round(leg_duration/60),
" minute(s)<br>","<strong>Mode :</strong>",
leg_mode),
color = ~mycol(leg_mode),
weight = 4) %>%
addProviderTiles(providers$CartoDB.Positron)
Cliquer sur les tronçons pour obtenir les informations :
6 Analyses d’accessibilité sous contrainte temporelle
Nous proposons dans ce tutoriel deux types d’analyse d’accessibilité multimodale sous contrainte temporelle parmi l’ensemble des possibilités envisageables :
la cartographie d’isochrones de temps d’accès à un lieu et à un horaire donné
la cartographie du nombre de déplacements réalisables et des temps moyens d’accès à un lieu pour une plage horaire donnée.
6.1 Isochrones d’accessibilité
Les cartes d’isochrones délimitent des aires d’accessibilité équivalentes en temps de déplacement à partir d’un point de départ. Elles figurent généralement plusieurs zones d’accessibilité, afin de représenter les différentiels croissants de coût du déplacement à mesure que l’on s’éloigne du lieu d’intérêt.
6.1.1 Localiser les différentiels d’accès à un lieu selon un mode de déplacement
La fonction otp_isochrone()
génère des cartes
d’isochrones en fonction d’un mode de transport (ou de la combinaison de
plusieurs modes). Les paramètres de la fonction sont identiques à ceux
utilisés pour générer des itinéraires, à l’exception de l’argument
cutoffSec
qui permet de définir les bornes maximales de
chaque intervalle de temps, en secondes (les valeurs doivent donc être
multipliées par 60 pour représenter des temps en minutes, par 3 600 pour
représenter des temps en heures, etc).
iso_gareStRoch <- otp_isochrone(otpcon = my_otpcon,
fromPlace = c(3.880727, 43.604937),
mode = c("WALK", "TRANSIT"),
maxWalkDistance = 2000,
date_time = as.POSIXct("2023-04-25 08:00:00"),
cutoffSec = c(15, 30, 45, 60, 75, 90) * 60)
Nous pouvons utiliser les fonctionnalités de cartographie interactive
proposées par la bibliothèque leaflet
pour R afin de donner
à voir le résultat. Pour retrouver des temps de déplacement en minutes,
nous créons une variable transformant le temps de déplacement associé à
l’isochrone (donné en secondes) en le divisant par 60.
Les isochrones de distance représentant des intervalles de temps de déplacement, nous allons d’abord construire la variation de teintes représentant ces différences d’ordre de grandeur.
Nous utiliserons la fonction addPolygons()
afin de
figurer les isochrones sur le fond de carte, en introduisant de
nouvelles options de mise en forme :
stroke = FALSE
: permet de retirer les contours des polygonessmoothFactor
: définit le niveau de simplication des géométries en fonction du zoomfillOpacity
: contrôle le niveau d’opacité (resp. de transparence) du remplissage.
Avant de créer la carte, nous téléchargeons les lignes de tramway de la métropole de Montpellier (format shapefile) afin de faciliter l’interprétation des résultats :
leafMap <- leaflet(data = iso_gareStRoch) %>%
setView(lat = 43.604937, lng = 3.880727, zoom = 10) %>%
addPolygons(stroke = FALSE,
color = ~mycol_2(minutes),
smoothFactor = 0.2,
fillOpacity = 1) %>%
addProviderTiles(providers$CartoDB.Positron)
leafMap <- leafMap %>%
addPolylines(data = tramway,
opacity = 1,
weight = 4,
color = ~factor(num_exploi, levels = c(1, 2, 3, 4),
labels = c("blue", "#c51b8a", "green", "brown")))
leafMap
Nous allons également ajouter une légende afin de faciliter la lecture de la carte.
mycol_3 <- colorFactor(
palette = c("blue", "#c51b8a", "darkgreen", "brown"),
domain = tramway$num_exploi)
leafMap <- leaflet(data = iso_gareStRoch) %>%
setView(lat = 43.604937, lng = 3.880727, zoom = 10) %>%
addPolygons(stroke = FALSE,
color = ~mycol_2(minutes),
smoothFactor = 0.2,
fillOpacity = 1) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addLegend("bottomright", pal = mycol_2,
values = ~minutes,
title = "Temps d'accès",
labFormat = labelFormat(suffix = " min"),
opacity = 1)
leafMap <- leafMap %>%
addPolylines(data = tramway,
opacity = 1,
weight = 4,
color = ~factor(num_exploi, levels = c(1, 2, 3, 4),
labels = c("blue", "#c51b8a",
"darkgreen", "brown"))) %>%
addLegend("bottomleft", pal = mycol_3,
values = tramway$num_exploi,
title = "Lignes de tramway",
opacity = 1)
leafMap
6.1.2 Comparer cartographiquement les différentiels d’accès à un lieu entre deux modes
Nous pouvons aussi choisir de superposer les isochrones de temps de
déplacement à vélo sur la carte, et proposer à l’utilisateur de basculer
d’une représentation à une autre grâce au paramètre group
proposé par leaflet
.
iso_gareStRoch_velo <- otp_isochrone(otpcon = my_otpcon,
fromPlace = c(3.880727, 43.604937),
mode = "BICYCLE",
maxWalkDistance = 2000,
date_time = as.POSIXct("2023-04-25 08:00:00"),
cutoffSec = c(15, 30, 45, 60, 75, 90) * 60)
iso_gareStRoch_velo$minutes = iso_gareStRoch_velo$time / 60
Pour distinguer les deux modes de déplacement sur la carte, nous construisons une progression chromatique en teintes bleues :
À l’aide de l’option group
et des fonctionnalités de
contrôle des couches introduites par la fonction
addLayersControl()
, il est possible de modifier l’aspect de
la carte en fonction des choix d’affichage de l’utilisateur.
leafMap <- leaflet() %>%
setView(lat = 43.604937, lng = 3.880727, zoom = 10) %>%
addPolygons(data = iso_gareStRoch_velo,
stroke = FALSE,
color = ~mycol_4(minutes),
smoothFactor = 0.2,
fillOpacity = 1,
group = "VELO") %>%
addPolygons(data = iso_gareStRoch,
stroke = FALSE,
color = ~mycol_2(minutes),
smoothFactor = 0.2,
fillOpacity = 1,
group = "TRANSIT") %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addLayersControl(
overlayGroups = c("TRANSIT", "VELO", "TRAMWAY"),
options = layersControlOptions(collapsed = FALSE))
leafMap <- leafMap %>%
addPolylines(data = tramway,
opacity = 1,
weight = 4,
group = "TRAMWAY",
color = ~factor(num_exploi, levels = c(1, 2, 3, 4),
labels = c("blue", "#c51b8a", "green", "brown")))
leafMap
L’affichage de la légende peut également être rendu dépendant des
fonctionnalités de contrôle des couches via le paramètre
group
.
leafMap <- leaflet() %>%
setView(lat = 43.604937, lng = 3.880727, zoom = 10) %>%
addPolygons(data = iso_gareStRoch_velo,
stroke = FALSE,
color = ~mycol_4(minutes),
smoothFactor = 0.2,
fillOpacity = 1,
group = "VELO") %>%
addPolygons(data = iso_gareStRoch,
stroke = FALSE,
color = ~mycol_2(minutes),
smoothFactor = 0.2,
fillOpacity = 1,
group = "TRANSIT") %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addLayersControl(
overlayGroups = c("TRANSIT", "VELO", "TRAMWAY"),
options = layersControlOptions(collapsed = FALSE)
) %>%
addLegend("bottomright", pal = mycol_2,
values = iso_gareStRoch$minutes,
title = "Temps d'accès (TC/marche)",
labFormat = labelFormat(suffix = " min"),
opacity = 1,
group = "TRANSIT"
) %>%
addLegend("bottomleft", pal = mycol_4,
values = iso_gareStRoch_velo$minutes,
title = "Temps d'accès (vélo)",
labFormat = labelFormat(suffix = " min"),
opacity = 1,
group = "VELO")
leafMap <- leafMap %>%
addPolylines(data = tramway,
opacity = 1,
weight = 4,
group = "TRAMWAY",
color = ~factor(num_exploi, levels = c(1, 2, 3, 4),
labels = c("blue", "#c51b8a",
"darkgreen", "brown"))) %>%
addLegend("bottomleft", pal = mycol_3,
values = tramway$num_exploi,
title = "Lignes de tramway",
opacity = 1,
group = "TRAMWAY")
leafMap
6.2 Nombre de déplacements réalisables dans un intervalle de temps
L’analyse proposée ici vise à qualifier l’offre de transport en commun entre une ou plusieurs origine(s) en direction d’une destination à partir de la mesure du nombre de déplacements réalisables et de leurs durée. Cette analyse d’accessibilité sous contrainte horaire s’inscrit dans le cadre théorique et méthodologique de la time geography (par exemple : Chapelon 2016 ; Conesa 2012 ; L’Hostis et al. 2004).
À titre d’exemple, nous développons un programme permettant de compter tous les déplacements possibles via le réseau de la TAM à partir des 30 mairies de la métropole (hors Montpellier) pour une arrivée entre 7h et 9h à la gare Saint-Roch. L’objectif est d’évaluer la qualité de l’offre de transport théorique à l’heure de pointe du matin à partir des centres-villes des communes métropolitaines (les retards potentiels liés aux accidents de circulation, aux travaux, etc. ne sont pas pris en compte).
6.2.1 Préparation des données
La localisation des 30 mairies de la métropole de Montpellier (hors Montpellier) est recueillie à partir de la base de données des équipements de l’INSEE. Les mairies correspondent aux lignes portant le code A129 pour la variable TYPEQU. Dans ce tutoriel, nous utilisons une extraction de la base de données réalisée a priori, du fait de la lourdeur du fichier d’origine.
Les données utilisées dans cet exemple sont disponibles ici :
AAV2020 AN BV2012 DEP DEPCOM DOM EPCI DCIRIS LAMBERT_X LAMBERT_Y
1 12 2021 34022 34 34022 A 243400017 340220102 781729.9 6285175
2 12 2021 34058 34 34027 A 243400017 340270000 782250.0 6292750
3 12 2021 34172 34 34057 A 243400017 340570103 772475.6 6281921
4 12 2021 34058 34 34058 A 243400017 340580101 779478.3 6287040
5 12 2021 34172 34 34077 A 243400017 340770101 771637.0 6284634
6 12 2021 34088 34 34087 A 243400017 340870000 757131.6 6272537
QP QUALI_IRIS QUALI_QP QUALI_QVA QUALI_ZFU QUALI_ZUS QUALITE_XY QVA REG SDOM
1 CSZ 1 X X X X Bonne CSZ 76 A1
2 CSZ X X X X X Acceptable CSZ 76 A1
3 CSZ 1 X X X X Bonne CSZ 76 A1
4 CSZ 1 X X X X Bonne CSZ 76 A1
5 CSZ 1 X X X X Bonne CSZ 76 A1
6 CSZ X X X X X Bonne CSZ 76 A1
TYPEQU UU2020 ZFU ZUS
1 A129 34302 CSZ CSZ
2 A129 34133 CSZ CSZ
3 A129 34701 CSZ CSZ
4 A129 34206 CSZ CSZ
5 A129 34701 CSZ CSZ
6 A129 34214 CSZ CSZ
Nous transformons la couche d’informations géographiques décrivant
les mairies au format dataframe en simple feature
dataframe, c’est-à-dire dans un format explicitement géographique
grâce à la fonction st_as_sf
.
Les coordonnées géographiques étant en Lambert93 (code EPSG 2154),
nous les traduisons pour OTP en WGS84 (code EPSG 4326) via la fonction
st_transform
.
Nous choisissons la plage horaire pour laquelle OTP réalisera toutes ses requêtes. L’horaire de départ est 6h et l’horaire de fin 9h afin de nous assurer de récolter les déplacements permettant d’arriver entre 7h et 9h à la gare Saint-Roch.
Nous créons ensuite les listes de lieux d’origine et de destination.
6.2.2 Exécution de la boucle pour récolter l’offre de transport
Nous construisons une boucle qui réalise une itération par minute
supplémentaire de l’horaire de début jusqu’à l’horaire limite au cours
de laquelle nous effectuons des requêtes d’itinéraires en transport en
commun depuis les lieux d’origine vers le lieu de destination dont nous
enregistrons successivement les caractéristiques dans un tableau de
données que nous nommons routes
.
La durée de cette opération est fonction du nombre de traitements et
d’itérations qu’OTP doit réaliser. La fonction tryCatch()
permet à la boucle de fonctionner malgré une éventuelle erreur de
connexion au serveur OTP, due à des instabilités ponctuelles.
routes <- data.frame()
while(temps_debut < temps_limite){
tryCatch({
resultats <- otp_plan(otpcon = my_otpcon,
fromPlace = coord_origine,
toPlace = coord_dest,
mode = c("TRANSIT", "WALK"),
date_time = temps_debut,
maxWalkDistance = 1000,
get_geometry = FALSE)
temps_debut <- temps_debut + 60
routes <- rbind(routes, resultats)
}, error = function(e) {
print(paste("Erreur dans la boucle :", e$message))
})
}
6.2.3 Mise en forme des données
Puisque nous voulons compter le nombre de déplacements possibles avec une arrivée à destination entre 7h et 9h, la période de pointe, nous supprimons les déplacements hors-champ (arrivée avant 7h et après 9h).
routes <- routes[routes$endTime >= "2023-04-19 07:00:00" & routes$endTime < "2023-04-19 09:00:00", ]
La boucle d’itérations a récolté un grand nombre de doublons : d’une
minute à une autre, l’offre de transport renvoyée par OTP ne change pas
systématiquement. De ce fait, nous sélectionnons les seuls déplacements
uniques renvoyés par le serveur OTP avec la commande
distinct
. Le paramètre .keep_all = TRUE
permet
de garder l’ensemble des colonnes de routes
.
Enfin, nous calculons le nombre de déplacements à partir de chaque
mairie avec la commande n_distinct(endTime)
, et la durée
moyenne des déplacements avec mean(duration/60)
.
tableau_resultat <- tableau_resultat %>%
group_by(fromPlace) %>%
summarise(nb_deplacements = n_distinct(endTime),
duree_moy = mean(duration/60))
Le graphique ci-dessous représente la distribution des temps de déplacement moyens obtenus pour les différentes communes sous la forme d’un histogramme.
ggplot() + geom_histogram(aes(x = tableau_resultat$duree_moy),
bins = 9,
color = "black",
fill = "lightblue") +
labs(title = "Distribution des durées moyennes des déplacements obtenus pour les 30 communes",
x = "Durée moyenne des déplacements (min)",
y = "Nombre de mairies") +
theme_classic() # thème de fond (ici "classic")
Nous notons que la répartition des temps de déplacement moyens en transport en commun depuis les mairies des communes de la métropole de Montpellier Méditerrannée vers la gare Saint-Roch aux heures de pointe du matin est très irrégulière et présente des écarts importants (les valeurs étant comprises entre 30 et 84 minutes).
6.2.4 Cartographie
Nous souhaitons savoir si les différences de temps de déplacement
moyens s’organisent en fonction d’une logique d’éloignement géographique
des communes à la ville centre. Pour cela, nous transformons
préalablement l’objet tableau_resultat
au format
dataframe
vers le format
simple feature dataframe
, en mobilisant les coordonnées
géographiques des différents points de départ obtenues en extrayant le
contenu de la colonne fromPlace
via la fonction
word()
.
library(stringr)
tableau_resultat$x <- word(tableau_resultat$fromPlace, 1, sep = ",")
tableau_resultat$y <- word(tableau_resultat$fromPlace, 2, sep = ",")
tableau_resultat <- st_as_sf(tableau_resultat, coords = c("y", "x"),
crs = st_crs(4326))
Nous choisissons de représenter ces différentiels d’accessibilité sous forme d’une cartographie statique. Le nombre de déplacements réalisables par commune est figuré par le biais de cercles proportionnels. Les durées moyennes de ces déplacements sont discrétisées par classes d’intervalles égaux.
De nombreuses bibliothèques existent pour réaliser de la cartographie
avec R, dont la bibliothèque phare de création de graphiques avec R
ggplot2
.
mapsf
a toutefois été créée en 2021 dans le but
spécifique de faciliter la production de cartes thématiques conformes au
règle de la sémiologie graphique avec R, à partir d’objets
sf
. Les principales fonctionnalités de la bibliothèque sont
recensées dans un document
graphique en ligne.
La fonction mf_map()
de la bibliothèque
mapsf
est la fonction centrale du package qui permet de
construire une carte au format varié à partir des paramètres :
x
l’objet au formatsf
var
la variable à cartographiertype
le type de carte que l’on souhaite créer (prop
pour des symboles proportionnels,choro
pour une carte choroplèthe,typo
pour une palette de couleurs variées,symb
pour des symboles ponctuels différenciés…). Puisque nous souhaitons représenter conjointement une variable quantitative de stock et des intervalles de temps de déplacement, nous choisissons le typeprop_choro
qui permet de varier la taille des figurés et leur intensité chromatique de façon synchrone.
Nous ajontons le nombre d’habitants pour chaque commune (INSEE
RP2020) et calculons la densité de population. La surface de chaque
polygone est calculée avec st_area
avec l’unité m\(^2\) par défaut. Nous utilisons la
bibliothèque units
pour convertir automatiquement les
surfaces de chaque commune de m\(^2\) à
km\(^2\) avec set_units
.
L’expression attributes() = NULL
permet ensuite de
supprimer les unités de la colonne car elles peuvent causer des
problèmes lors des rendus graphiques (comme ggplot2
).
library(units)
epci_3m$popu <- c("9305", "6794", "2176", "23469", "4014", "1640",
"5613", "2839", "6423", "9438", "6490", "3293",
"7194", "8218", "12104", "2818", "3517", "7600",
"2183", "1039", "299096", "6007", "5628", "11843",
"10463", "8885", "17674", "6771", "2041", "1856", "3330")
epci_3m$popu <- as.numeric(epci_3m$popu)
epci_3m$surface_km2 <- st_area(epci_3m)
epci_3m$surface_km2 <- set_units(epci_3m$surface_km2, km^2)
epci_3m$densite <- epci_3m$popu/epci_3m$surface_km2
attributes(epci_3m$densite) = NULL
Notons que la cartographie paginée nécessite d’utiliser des coordonnées définies dans un système de projection cartographique adapté au territoire à l’étude, ici nous utiliserons le Lambert93 (code EPSG 2154).
tableau_resultat <- st_transform(tableau_resultat, 2154)
epci_3m <- st_transform(epci_3m, 2154)
gare_st_Roch <- data.frame(x = 3.880731, y = 43.604622)
gare_st_Roch <- st_as_sf(gare_st_Roch, coords = c("x", "y"), crs = 4326)
gare_st_Roch <- st_transform(gare_st_Roch, 2154)
gare_st_Roch$nom <- "Gare Saint-Roch"
library(mapsf)
mf_theme("iceberg")
mf_map(epci_3m,
type = "choro",
var = "densite",
breaks = "geom",
nbreaks = 5,
pal = "Reds",
leg_pos = "left",
leg_title = "Densité de population\n(habitants par km²)",
leg_frame = TRUE,
expandBB = c(0, 0, 0.1, 0))
mf_map(tableau_resultat,
type = "prop_choro",
var = c("nb_deplacements", "duree_moy"),
inches = 0.15,
border = "grey50",
lwd = 1,
leg_pos = c("right"),
leg_title = c("Nombre", "Temps moyen\n(en min)"),
breaks = "equal",
nbreaks = 9,
pal = "Greens",
leg_frame = c(TRUE, TRUE))
mf_base(gare_st_Roch,
add = TRUE,
col = "blue",
cex = 2,
pch = 15)
mf_label(gare_st_Roch,
var = "nom",
col = "blue",
halo = TRUE,
cex = 1,
bg = "white",
pos = c(4, 1),
r = 0.05)
mf_layout(
title = "Déplacements des 30 mairies vers la gare Saint-Roch (7h-9h)",
credits = paste0(
"Sources: OTP et TAM 2022 \n",
"mapsf ",
packageVersion("mapsf")
),
frame = TRUE)
Il est possible d’évaluer la performance de l’offre de transport par
rapport à la distance euclidienne qui sépare les mairies de la gare
Saint-Roch. Nous pouvons calculer cette distance avec l’expression
st_distance
de la bibliothèque sf
. Nous
ajoutons ensuite les distances
dans notre
tableau_resultat
.
distances <- st_distance(tableau_resultat$geometry, gare_st_Roch$geometry)
tableau_resultat$distance_euclidienne <- distances
Afin de faciliter la lecture des résultats, il nous faut les codes
INSEE de chacune des mairies. Les codes INSEE sont enregistrés dans le
tableau mairies
avec les même coordonnées géographiques que
tableau_resultat
. Nous devons réaliser une jointure
spatiale pour joindre toutes les colonnes des deux tableaux avec la
fonction st_join
. Nous devons au préalable attribuer la
valeur de 0.1
à st_precision
afin de faire
correspondre les coordonnées géographiques des deux tableaux en raison
de très légères différences (aussi petites soient-elles) dues à des
manipulations antérieures.
mairies <- st_transform(mairies, 2154)
st_precision(mairies) <- 0.1
st_precision(tableau_resultat) <- 0.1
jointure_spatiale <- st_join(tableau_resultat, mairies)
La conversion de mètre à kilomètre est réalisée par
set_units
puis nous supprimons l’unité avec
attributes() = NULL
car elle empêche la création du nuage
de points dans ggplot2
.
jointure_spatiale$distance_euclidienne <- set_units(jointure_spatiale$distance_euclidienne, km)
attributes(jointure_spatiale$distance_euclidienne) = NULL
Nous ponvons enfin réaliser le nuage de points afin de constater la
performance, pour chaque mairie, de l’offre de transport par rapport à
la distance qui la sépare de la gare. Nous utilisons la bibliothèque
ggrepel
pour que les étiquettes s’affichent avec plus de
lisibilité, grâce à l’expression geom_text_repel
qui
empêche leur chevauchement.
library(ggrepel)
dist <- ggplot(jointure_spatiale, aes(x = distance_euclidienne, y = duree_moy, label = DEPCOM)) +
geom_point() +
geom_text_repel(size = 3, box.padding = 0.3) +
xlab("Distance euclidienne (km)") +
ylab("Durée moyenne des déplacements (min)") +
labs(subtitle ="Performance des transports collectifs par rapport à la distance")
dist
Le graphique permet de constater qu’il y a globalement bien une relation entre la distance et la durée moyenne des déplacements (plus c’est loin, plus il faudra de temps). Toutefois, des différences importantes de temps de déplacement, à distance égale, existent : la mairie du Crès (34090) est presque aussi éloignée que celle de Pérols (34198) alors qu’un écart de 25 minutes de déplacement les différencie (Pérols possède une desserte en tramway contrairement au Crès).
N’oubliez pas d’arrêter le serveur OTP une fois vos analyses terminées!
7 Conclusion et perspectives
L’outil OTP et son intégration dans R permettent donc de mobiliser facilement les nouvelles données de l’offre de transport et de calcul d’itinéraires multimodaux pour porter un regard affiné sur l’accessibilité territoriale, à l’aide d’indicateurs d’analyses éprouvés en géographie et en aménagement : matrices O/D, isochrones de distance, nombre de déplacements possibles sous contrainte horaire, etc. De nombreuses perspectives sont ouvertes à l’issue de ce travail, telles que l’ajout d’autres opérateurs de transport collectif pour compléter l’offre de la TAM ou encore l’addition d’un modèle numérique de terrain afin de tenir compte de la pénibilité induite par certaines pentes dans le cas des déplacements à vélo.
Bibliographie
Annexes
Info session
setting | value |
---|---|
version | R version 4.4.0 (2024-04-24) |
os | Debian GNU/Linux 12 (bookworm) |
system | x86_64, linux-gnu |
ui | X11 |
language | en |
collate | fr_FR.UTF-8 |
ctype | fr_FR.UTF-8 |
tz | Europe/Paris |
date | 2024-06-04 |
pandoc | 3.1.11 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown) |
package | ondiskversion | source |
---|---|---|
dplyr | 1.1.4 | CRAN (R 4.4.0) |
DT | 0.33 | CRAN (R 4.4.0) |
ggplot2 | 3.5.1 | CRAN (R 4.4.0) |
ggrepel | 0.9.5 | CRAN (R 4.4.0) |
ggspatial | 1.1.9 | CRAN (R 4.4.0) |
leaflet | 2.2.2 | CRAN (R 4.4.0) |
mapsf | 0.10.1 | CRAN (R 4.4.0) |
opentripplanner | 0.5.2 | CRAN (R 4.4.0) |
prettymapr | 0.2.5 | CRAN (R 4.4.0) |
reshape2 | 1.4.4 | CRAN (R 4.4.0) |
sf | 1.0.16 | CRAN (R 4.4.0) |
stringr | 1.5.1 | CRAN (R 4.4.0) |
tidyr | 1.3.1 | CRAN (R 4.4.0) |
units | 0.8.5 | CRAN (R 4.4.0) |
Citation
Ullès J, Le Texier M (2024). “Analyse d’accessibilité multimodale.”, doi:10.48645/5qht-d313 https://doi.org/10.48645/5qht-d313,, https://rzine.fr/articles_rzine/20240529_ulles_letexier_otp/.
BibTex :
@Misc{,
title = {Analyse d’accessibilité multimodale},
subtitle = {Avec R et OpenTripPlanner},
author = {Jean-Clément Ullès and Marion {Le Texier}},
doi = {10.48645/5qht-d313},
url = {https://rzine.fr/articles_rzine/20240529_ulles_letexier_otp/},
keywords = {FOS: Other social sciences},
language = {fr},
publisher = {FR2007 CIST},
year = {2024},
copyright = {Creative Commons Attribution Share Alike 4.0 International},
}