1 - Connexion au GIS et import des bibliothèques
GIS
du module gis
, qui représente notre organisation.
La connexion est ensuite à adapter selon votre environnement et votre méthode d'authentification. Voir l'aide en ligne pour plus d'informations.Si
vous êtes connectés en tant qu'admin, la cellule va vous renvoyer un
message rouge pour vous prévenir qu'il faut faire attention aux
opérations que vous utilisez. Cela n'empêche pas votre code de
s'exécuter correctement.Si votre environnement n'est pas directement connecté à votre SIG, vous devrez lui passer vos informations d'authentification via la cellule suivante, que vous devez bien sûr mettre à jour avec vos propres informations :2 - Téléchargement des données
2a - Récupération de la date
Nous pouvons récupérer la date d'avant-hier grâce à la bibliothèque
datetime
et à ses fonctions datetime.now()
et timedelta()
. Avec strftime()
,
nous la formatons selon la forme suivante : AAAA-MM-JJ (ex :
2024-07-04 pour le 4 juillet 2024) car c'est sous ce format que les
dates sont enregistrées dans les données auxquelles nous allons accéder.2b - Création d'un dossier cible et téléchargement des données
Nous appelons la fonction en passant en argument le nom que nous souhaitons donner à notre dossier, qui va venir ici chercher dynamiquement la date d'avant-hier récupérée ci-dessus.Si vous utilisez ArcGIS Notebooks, notez que cette fonction vient des extraits de code organisés par Esri auxquels vous avez accès dans votre environnement :Le dossier est maintenant créé et prêt à accueillir nos données. Je créée une nouvelle fonction qui me permet de télécharger des données à partir d'un url. Je récupère pour cela l'adresse à laquelle je retrouve le CSV des données de comptage sur datagouv :Après exécution de la fonction, je peux retrouver la donnée téléchargée directement dans le dossier que j'ai créé juste avant.
En attendant, je vous propose de regarder un peu plus en détail ce que contiennent les données et comment nous pouvons les nettoyer et les préparer avant de les publier sur notre portail.
3 - Lecture en DataFrame pandas
DataFrame
,
car cette structure de données offre plusieurs avantages en termes de
facilité de manipulation et de transformation des données.read_csv
de la bibliothèque pandas
(que nous avions importée dans la première cellule de ce Notebook),
puis nous affichons le DataFrame dans le Notebook afin de voir à quoi
ressemblent nos données.4 - Préparation et nettoyage des données
Nous allons maintenant voir ensemble plusieurs opérations sur les DataFrames afin de préparer les données avant leur publication.
4a - Suppression des valeurs manquantes (NaN)
dropna()
:4b - Renommage des colonnes et suppression des colonnes inutiles
rename()
,
dans laquelle je passe simplement en argument un dictionnaire contenant
en clés les noms actuels des colonnes que je souhaite renommer et en
valeurs les nouveaux noms :Lorsque
l'on manipule des jeux de données de taille relativement importante,
nous pouvons essayer de les réduire afin d'en améliorer les
performances. Une manière très simple d'arriver à cela est de supprimer
les colonnes dont nous n'avons pas besoin pour nos analyses ou pour
identifier nos données.drop()
afin de supprimer 3 colonnes de notre dataframe, dont nous passons les
labels en argument de la fonction sous forme de liste. Le paramètre axis
permet de choisir si l'on supprime des lignes (0) ou des colonnes (1).4c - Filtre selon la date
date_av_hier
calculée au début du Notebook : Voici un petit peu plus d'explications sur comment fonctionne le filtrage d'un DataFrame : df_trafic_drop_colonnes['date'] == date_av_hier
crée une série de valeurs booléennes (True ou False), où chaque élément
est True si la valeur dans la colonne date est égale à la variable date_av_hier
et False sinon.
df_trafic_drop_colonnes[df_trafic_drop_colonnes['date'] == date_av_hier]
utilise cette série de booléens pour filtrer df_trafic_drop_colonnes
, ne gardant que les lignes où la condition est True. En d'autres termes, seules les lignes dont la date correspond à date_av_hier
sont conservées.df_av_hier
.4d - Tri par valeur décroissante
sort_values
en indiquant la colonne sur laquelle nous appliquons le tri, ainsi que l'ordre de tri (ascending = False
permet d'obtenir un ordre décroissant).Je me permets aussi d'imprimer une fraction du DataFrame, ici uniquement les 5 premiers enregistrements grâce à la méthode
head()
(à l'inverse, tail()
permet d'imprimer uniquement les 5 derniers).Nos données sont maintenant prêtes pour la suite !5 - Transformation d'un DataFrame en Spatially enabled DataFrame
Avec l'API Python d'ArcGIS, il est possible de transformer les DataFrames classiques en Spatially
Enabled Dataframes si ceux-ci possèdent des informations de latitude et de longitude. Cela va nous permettre ensuite d'utiliser pleinement la composante spatiale de nos données.
5a - Création de deux colonnes latitude et longitude
Nous allons transformer notre dataframe pour qu'il corresponde aux prérequis. La méthode
str.split()
permet de séparer la chaîne contenant latitude et longitude, et nous
passons la virgule en argument afin qu'elle soit utilisée comme
délimitateur. expand = True
indique que chaque élément
résultant de cette division (ici, la latitude et la longitude) doit être
stocké dans une colonne séparée. Nous assignons ces valeurs à deux
nouvelles colonnes se nommant latitude et longitude.float
, hors elles sont pour l'instant de type object
(c'est en fait un string
spécifique à pandas). Cela est facilement vérifiable en accédant à la propriété dtypes
du DataFrame, qui renvoie le type de donnée de chaque colonne : Heureusement, nous pouvons très facilement convertir le format avec la méthode astype()
:5b - Transformation en SeDF
GeoAccessor
, à laquelle nous accédons dans le code avec le point d'accès .spatial
.Nous utilisons la méthode
from_xy()
du GeoAccessor, dans laquelle nous passons en argument le dataframe à
convertir, la colonne x contenant la longitude, la colonne y contenant
la latitude et le wikd contenant la référence spatiale :Vous
pouvez voir qu'une nouvelle colonne SHAPE a été ajoutée au DataFrame,
qui nous permet d'accéder aux informations géographiques de notre
donnée, et donc de l'afficher sur une carte ou de réaliser des
opérations d'analyses spatiales dessus.Nous pouvons vérifier quel type de géométrie (point, polyligne, polygone) possède notre donnée en appelant la propriété
geometry_type
:Notez
que grâce aux capacités de géocodage d'ArcGIS, il est possible de
convertir un DataFrame en Spatially enabled DataFrame directement grâce à
une colonne contenant uniquement une adresse avec la méthode from_df()
, si par exemple vous ne possédez pas les coordonnées X et Y précises.6 - Affichage du SeDF sur une carte
plot()
du SeDF me permet ensuite d'afficher mes données très facilement sur la
carte que je viens de créer en passant la carte en argument :Nous
avons vu comment créer un SeDF à partir d'un DataFrame, mais sachez
qu'il est également possible de lire d'autres formats de données : des
feature layers publiés sur le portail (méthode from_layer
), des classes d'entités (méthode from_featureclass
), depuis une table (from_table
) ou encore depuis des données parquet (from_parquet
) et des GeoDatFrame Geopandas (from_geodataframe
).
Voyons ensemble comment récupérer une couche d'entités (feature layer) publiée sur le portail et la lire en SeDF.
7a - Recherche du feature layer
De la même manière que dans le tutoriel précédent, nous utilisons la fonction search()
de l'API Python d'ArcGIS pour rechercher un feature layer sur notre
portail, et nous récupérons le premier item retourné par la liste.
Ici, je recherche une couche d'entités contenant les limites administratives de la commune de Bordeaux.
- Si vous êtes utilisateur ArcGIS Online, vous y aurez également accès grâce au paramètre
outside_org
. - Si vous êtes utilisateur ArcGIS Enterprise, vous devrez publier votre propre couche d'entités hébergées, par exemple à partir des données mises à disposition par l'open data de Bordeaux Métropole, que vous pouvez télécharger ici, en sélectionnant uniquement Bordeaux avant la publication. Vous devrez ensuite modifier l'id de la requête pour qu'il corresponde à celui de votre item publié.
7b - Lecture du feature layer en SeDF
from_layer
,
il est maintenant très facile de lire cette couche d'entités en tant
que SeDF. En argument de celle-ci, nous passons l'item du feature layer
récupéré juste au-dessus. Il faut préciser l'index de la couche en
accédant à la propriété layers
du feature layer (0 pour la première couche, 1 si on souhaite accéder à la deuxième, etc). Nous pouvons ré-accéder au type de géométrie, et constatons qu'il s'agit cette fois-ci d'un polygone.7c - Affichage sur la carte
8 - Analyse spatiale à partir de deux SeDF
8a - Accès à la géométrie du SeDF d'emprise de la commune
iloc[0]
, puis accédons à sa colonne SHAPE
qui contient la géométrie de notre donnée. Selon l'interface dans
laquelle vous travaillez, la cellule vous renverra soit un tracé de la
géométrie (image de gauche), soit la liste contenant les coordonnées de
tous les sommets de la géométrie (image de droite). Il s'agit du même
objet.8b - Requête sur le SeDF de trafic selon la géométrie des contours de la commune
GeoSeriesAccessor
nous permet de réaliser des opérations en utilisant la géométrie des sedf. On y accède dans le code avec l'accesseur .geom
appliqué à la colonne SHAPE
du sedf.Pour un exemple simple, nous pouvons par exemple utiliser la propriété
centroid
du GeoSeriesAccessor
pour obtenir le centroïde du polygone représentant la commune de Bordeaux :Plutôt sympa mais... ça ne sert à rien pour notre tutoriel ! Donc revenons à nos moutons, et utilisons le GeoSeriesAccessor
pour quelque chose de plus utile.disjoint()
permet de comparer deux géométries, et renvoie une série de booléens : True
si les sont géométries des entités comparées sont disjointes (ne s'intersectent pas) et False
sinon (les données s'intersectent). J'utilise donc cette méthode sur le
sedf contenant les compteurs, et passe en argument la géométrie du sedf
contenant les limites de bordeaux récupérée au-dessus.== False
me permet ensuite d'inverser le résultat, et de passer à True
les géométries non disjointes et à False
les géométries disjointes.J'utilise ensuite cette série booléenne pour filtrer le dataframe des compteurs de trafic. En passant la série en entrée de la propriété
loc
de mon dataframe, j'accède uniquement aux lignes pour lesquelles la valeur du booléen est True
. La fonction copy()
permet de créer une copie du dataframe filtré, afin d'éviter les problèmes liés à la modification d'une vue sur l'original.8c - Vérification des résultats sur une carte
9 - Publication du SeDF en tant que feature layer sur le portail
to_featurelayer
du GeoAccessor
. Je donne un titre et des tags à mon feature layer, et je réindique la variable de connexion à mon SIG. Le paramètre sanitize_columns
me permet de m'assurer que les noms de colonnes sont bien des chaînes
de caractères, que les caractères invalides seront retirés, etc., si
j'ai loupé quelque chose pendant le nettoyage de mes données.Dans le prochain tutoriel, nous verrons comment intégrer ces opérations de préparation et publication des données dans un workflow plus global de mise à jour de données et de cartes, toujours avec l'API Python d'ArcGIS.
Aucun commentaire:
Enregistrer un commentaire