Les bases de Python 5 : Xarray

Ce tutoriel présente xarray (prononcé ex-array), une bibliothèque Python permettant de travailler avec des tableaux multidimensionnels étiquetés. Elle est largement utilisée pour traiter les données d’observation de la Terre, qui comportent souvent plusieurs dimensions - par exemple, la longitude, la latitude, le temps et les canaux/bandes. Elle peut également afficher des métadonnées telles que le système de référence de coordonnées (CRS) du jeu de données.

L’accès aux données contenues dans un xarray.DataArray ou un xarray.Dataset est très similaire à l’appel de valeurs à partir de dictionnaires.

Note: Ce tutoriel porte sur l’utilisation de xarray. Une introduction aux jeux de données de télédétection et plus d’informations sur les produits d’observation de la Terre utilisés sur la plateforme Digital Earth Africa peuvent être trouvées dans Session 2 : Produits Digital Earth Africa.

Suivez les instructions ci-dessous pour télécharger le tutoriel et l’ouvrir dans l’Environnement de test.

Télécharger le cahier d’exercices

Télécharger le carnet de notes du tutoriel Python basics 5

Télécharger le fichier NetCDF de l’exercice

Pour visualiser ce notebook sur l’Environnement de test, vous devrez d’abord télécharger le notebook et le fichier NetCDF sur votre ordinateur, puis les télécharger tous les deux sur l’Environnement de test. Assurez-vous d’avoir suivi les prérequis de configuration listés dans Python basics 1 : Jupyter, puis suivez ces instructions :

  1. Téléchargez le carnet de notes en cliquant sur le premier lien ci-dessus. Téléchargez l’image en cliquant sur le deuxième lien ci-dessus.

  2. Dans l’Environnement de test, ouvrez le dossier Training.

  3. Cliquez sur le bouton Transférer les fichiers comme indiqué ci-dessous.

Bouton de téléchargement.

  1. Sélectionnez le notebook téléchargé à l’aide du navigateur de fichiers. Cliquez sur OK.

  2. Répétez l’opération pour télécharger le fichier NetCDF (.nc) dans le dossier Training. Le téléchargement peut prendre un certain temps avant de s’achever.

  3. Les deux fichiers apparaîtront dans le dossier Training. Double-cliquez sur le cahier de formation pour l’ouvrir et commencer le tutoriel.

Vous pouvez maintenant utiliser le cahier d’exercices comme une version interactive de cette page Web.

Note

Le cahier d’exercices devrait ressembler au texte et au code ci-dessous. Cependant, les sorties du cahier d’exercices sont vides (c’est-à-dire qu’aucun résultat n’apparaît après les cellules de code). Suivez les instructions du cahier pour exécuter les cellules du cahier d’exercices. Reportez-vous à cette page pour vérifier que vos résultats sont similaires.

Introduction à xarray

Xarray rend les ensembles de données plus faciles à interpréter lors de l’analyse des données. Pour le démontrer, nous pouvons commencer par ouvrir un fichier NetCDF ( suffixe de fichier .nc) de la zone de Guinée-Bissau que nous avons utilisée dans la précédente matplotlib lesson.

Dans cette leçon, nous avons tracé la version .JPG de l’image en utilisant imread et imshow.

[1]:
# Review of Python basics lesson 3: matplotlib

%matplotlib inline

import numpy as np
from matplotlib import pyplot as plt

im = np.copy(plt.imread('Guinea_Bissau.JPG'))
plt.imshow(im)
[1]:
<matplotlib.image.AxesImage at 0x7f6fc79feba8>
../_images/python_basics_05_xarray_9_1.png

En utilisant xarray, nous allons maintenant lire un fichier .nc de la zone. Les fichiers .nc NetCDF sont un type de fichier utilisé pour stocker des données scientifiques orientées tableau. En se rappelant que les données d’image sont des tableaux, les deux formats sont presque équivalents.

Nous pourrions également charger le fichier .JPG comme un ensemble de données en utilisant xarray, mais le fichier NetCDF contient plus de métadonnées et sera donc plus facile à interpréter.

Comme d’habitude, nous allons d’abord importer le paquet xarray.

[2]:
# Import the xarray package as xr

import xarray as xr
[3]:
# Use xarray to open the data file

guinea_bissau = xr.open_dataset('guinea_bissau.nc')
[4]:
# Inspect the xarray.DataSet by
# typing its name

guinea_bissau
[4]:
<xarray.Dataset>
Dimensions:      (x: 500, y: 501)
Coordinates:
    time         datetime64[ns] 2018-01-09T11:22:11.054208
  * y            (y) float64 1.338e+06 1.338e+06 ... 1.323e+06 1.323e+06
  * x            (x) float64 3.88e+05 3.880e+05 3.881e+05 ... 4.03e+05 4.03e+05
    spatial_ref  int32 32628
Data variables:
    red          (y, x) float64 ...
    green        (y, x) float64 ...
    blue         (y, x) float64 ...
Attributes:
    crs:           EPSG:32628
    grid_mapping:  spatial_ref

Inspectons les données. Cette image (notre jeu de données) a une hauteur y de 501 pixels et une largeur x de 500 pixels. Elle possède 3 variables, qui correspondent aux bandes rouge, verte et bleue nécessaires au tracé d’une image couleur. Chacune de ces bandes a une valeur pour chacun des pixels, ce qui nous donne un total de 751500 valeurs (le résultat de 501 x 500 x 3). Chacune des valeurs x et y est associée à une longitude et une latitude et leurs valeurs sont stockées dans la section Coordinates.

Le xarray.DataSet utilise des tableaux numpy dans le backend. Ce que nous voyons ci-dessus est fonctionnellement similaire à un tas de tableaux numpy contenant les mesures de la bande de l’image et les coordonnées de longitude/latitude, combiné avec un dictionnaire de paires clé-valeur qui définit les Attributs tels que le CRS et la résolution (res). Cela semble plus compliqué, n’est-ce pas ? L’accès aux données par xarray évite les complications liées à la gestion de tableaux numpy non corrélés par eux-mêmes.

Ventilation de l'ensemble de données Xarray

Visualisation d’un* xarray.Dataset . Les coordonnées sont chacune à une seule dimension : « latitude », « longitude » et « time ». Chaque variable (dans ce cas, température et precipitation) possède une valeur dans chacune des trois dimensions de coordonnées.

Un xarray.Dataset peut être vu comme une structure de dictionnaire pour emballer les données, les dimensions et les attributs tous liés ensemble.

Comme dans le NetCDF que nous avons chargé ci-dessus, Digital Earth Africa suit la convention de stocker les bandes spectrales comme des variables séparées, avec chacune d’elles comme des cubes à 3 dimensions contenant la dimension temporelle.

Pour accéder à une seule variable, nous pouvons utiliser le même format que s’il s’agissait d’un dictionnaire Python.

var = dataset_name['variable_name']

Alternativement, nous pouvons utiliser la notation . .

var = dataset_name.variable_name

Une variable unique extraite d’un xarray.Dataset est appelée xarray.DataArray. Dans l’image de visualisation ci-dessus, l’exemple xarray.Dataset est formé de deux xarray.DataArray - un pour la température et un pour la précipitation.

Note: Les noms des variables sont souvent des chaînes de caractères (entre guillemets). C’est le cas de la plupart des ensembles de données Digital Earth Africa, où les variables telles que les bandes de satellites ont des noms tels que 'red', 'green', 'nir'. N’oubliez pas les guillemets dans la méthode de premier appel ci-dessus, ou les données ne seront pas chargées.

L’ensemble de données que nous avons chargé ne comporte qu’un seul pas de temps. Nous allons maintenant extraire uniquement les données de la variable 'red' de notre ensemble de données guinea_bissau xarray.Dataset, puis les tracer.

[5]:
guinea_bissau['red']

# This is equivalent to
# guinea_bissau.red
# Try it!
[5]:
<xarray.DataArray 'red' (y: 501, x: 500)>
[250500 values with dtype=float64]
Coordinates:
    time         datetime64[ns] 2018-01-09T11:22:11.054208
  * y            (y) float64 1.338e+06 1.338e+06 ... 1.323e+06 1.323e+06
  * x            (x) float64 3.88e+05 3.880e+05 3.881e+05 ... 4.03e+05 4.03e+05
    spatial_ref  int32 32628
Attributes:
    units:         reflectance
    nodata:        -9999
    crs:           EPSG:32628
    grid_mapping:  spatial_ref
[6]:
# Plot using imshow

plt.imshow(guinea_bissau['red'], cmap='Reds')
[6]:
<matplotlib.image.AxesImage at 0x7f6fb0b77400>
../_images/python_basics_05_xarray_22_1.png

**Remarque : cmap signifie carte de couleurs. Que se passe-t-il si vous supprimez cet argument ? plt.imshow tracera alors toutes les valeurs de données red dans le schéma de couleurs par défaut, qui est une carte de couleurs séquentielle violet-jaune connue sous le nom de viridis. Ceci est dû au fait que matplotlib ne sait pas que le nom de variable red est associé à la couleur rouge - c’est juste un nom. Vous pouvez en savoir plus sur les cartes de couleurs de matplotlib grâce à ce tutoriel matplotlib.

Nous avons dit plus haut que xarray utilise des tableaux numpy en backend. Vous pouvez accéder à ces tableaux numpy en ajoutant .values après un nom de DataArray. Dans l’exemple ci-dessous, guinea_bissau.red est le nom du DataArray.

[7]:
guinea_bissau.red.values
[7]:
array([[1007., 1007., 1069., ...,  489.,  476.,  422.],
       [ 988.,  991., 1048., ...,  456.,  459.,  444.],
       [ 976., 1023., 1062., ...,  453.,  454.,  448.],
       ...,
       [ 518.,  518.,  546., ...,  551.,  577.,  553.],
       [ 517.,  527.,  523., ...,  530.,  572.,  570.],
       [ 502.,  490.,  473., ...,  545.,  576.,  580.]])

Il est possible d’indexer xarray.DataArrays par position en utilisant la syntaxe numpy [ :,:] que nous avons introduite dans les leçons précédentes, sans convertir en tableaux numpy. Cependant, nous pouvons également utiliser les syntaxes xarray, qui étiquettent explicitement les coordonnées au lieu de compter sur la connaissance de l’ordre des dimensions.

Chaque méthode est présentée ci-dessous.

  • [ :,:] : syntaxe numpy - nécessite de connaître l’ordre des dimensions et les index positionnels

  • isel(coordinate_name = coordinate_index) : sélection d’index - syntaxe xarray pour sélectionner des données basées sur leur index positionnel (similaire à numpy)

  • sel(coordinate_name = coordinate_value) : sélection de valeur - syntaxe xarray pour sélectionner des données en fonction de leur valeur dans cette dimension

Par exemple, nous pouvons appeler la valeur de vert dans le pixel supérieur gauche de l’ensemble des données de l’image.

[8]:
# Using numpy syntax

guinea_bissau.green[0,0]
[8]:
<xarray.DataArray 'green' ()>
array(730.)
Coordinates:
    time         datetime64[ns] 2018-01-09T11:22:11.054208
    y            float64 1.338e+06
    x            float64 3.88e+05
    spatial_ref  int32 32628
Attributes:
    units:         reflectance
    nodata:        -9999
    crs:           EPSG:32628
    grid_mapping:  spatial_ref

Dans ce cas, nos index positionnels pour x et y sont les mêmes, mais il est important de noter que y est la première dimension, et x la seconde. Cela n’est pas immédiatement évident et peut prêter à confusion. C’est pourquoi il est recommandé d’utiliser l’une des syntaxes xarray présentées ci-dessous. Elles font explicitement appel aux noms des dimensions.

[9]:
# Using index selection, isel()

guinea_bissau.green.isel(y=0, x=0)
[9]:
<xarray.DataArray 'green' ()>
array(730.)
Coordinates:
    time         datetime64[ns] 2018-01-09T11:22:11.054208
    y            float64 1.338e+06
    x            float64 3.88e+05
    spatial_ref  int32 32628
Attributes:
    units:         reflectance
    nodata:        -9999
    crs:           EPSG:32628
    grid_mapping:  spatial_ref

Comme précédemment, la mesure du vert dans le pixel supérieur gauche est de 730. Dans cet exemple, les valeurs de x et y sont des valeurs de latitude et de longitude, mais leurs indices de position sont 0.

Nous pouvons appeler la valeur en utilisant l’indice, comme indiqué ci-dessous.

Note: Le CRS que nous utilisons a des unités de mètres. Cela signifie que les valeurs x et y sont mesurées en mètres.

[10]:
# The value of x at the pixel located at index (0,0)

guinea_bissau.green.x[0].values
[10]:
array(388020.)
[11]:
# The value of y at the pixel located at index (0,0)

guinea_bissau.green.y[0].values
[11]:
array(1338000.)

L’interprétation de la cellule ci-dessus est la suivante :

Output the value of y in the 1st position of the green variable from the dataset called guineau_bissau.

Nous voyons que le premier élément (indice de 0) de x a une valeur de 388020 mètres, et que la première valeur de y est 1338000 mètres.

Que pensez-vous de la deuxième méthode, sel() ? Cette méthode n’était pas disponible dans les tableaux numpy que nous avons utilisés dans les leçons précédentes, et c’est l’une des forces de xarray car vous pouvez utiliser la valeur de la dimension sans connaître son index positionnel.

Si on nous donne (y, x) = (1338000, 388020), nous pouvons trouver la mesure verte à ce point en utilisant sel().

[12]:
guinea_bissau.green.sel(y=1338000, x=388020)
[12]:
<xarray.DataArray 'green' ()>
array(730.)
Coordinates:
    time         datetime64[ns] 2018-01-09T11:22:11.054208
    y            float64 1.338e+06
    x            float64 3.88e+05
    spatial_ref  int32 32628
Attributes:
    units:         reflectance
    nodata:        -9999
    crs:           EPSG:32628
    grid_mapping:  spatial_ref

Enfin, nous pouvons sélectionner des plages de DataArrays avec les syntaxes xarray en utilisant slice. Les trois cellules ci-dessous extraient toutes la même étendue du DataArray guinea_bissau.green`.

Les syntaxes xarray pour les plages utilisant slice sont :

dataarray_name.isel(dimension_name = slice(index_start, index_end))

dataarray_name.sel(dimension_name = slice(value_start, value_end))

Comme précédemment, il est plus facile d’appeler les dimensions par leur nom plutôt que d’utiliser la syntaxe implicite des crochets de numpy, bien que cela fonctionne toujours.

[13]:
# Numpy syntax - dimensions are not named
# Valid but not recommended

guinea_bissau.green[:250, :250]
[13]:
<xarray.DataArray 'green' (y: 250, x: 250)>
array([[730., 737., 811., ..., 493., 514., 539.],
       [729., 717., 773., ..., 512., 532., 534.],
       [714., 738., 764., ..., 528., 541., 521.],
       ...,
       [662., 665., 676., ..., 506., 510., 480.],
       [667., 669., 664., ..., 553., 502., 501.],
       [662., 661., 676., ..., 600., 575., 560.]])
Coordinates:
    time         datetime64[ns] 2018-01-09T11:22:11.054208
  * y            (y) float64 1.338e+06 1.338e+06 ... 1.331e+06 1.331e+06
  * x            (x) float64 3.88e+05 3.880e+05 ... 3.955e+05 3.955e+05
    spatial_ref  int32 32628
Attributes:
    units:         reflectance
    nodata:        -9999
    crs:           EPSG:32628
    grid_mapping:  spatial_ref
[14]:
# Index selection slice

guinea_bissau.green.isel(x=slice(0,250), y=slice(0,250))
[14]:
<xarray.DataArray 'green' (y: 250, x: 250)>
array([[730., 737., 811., ..., 493., 514., 539.],
       [729., 717., 773., ..., 512., 532., 534.],
       [714., 738., 764., ..., 528., 541., 521.],
       ...,
       [662., 665., 676., ..., 506., 510., 480.],
       [667., 669., 664., ..., 553., 502., 501.],
       [662., 661., 676., ..., 600., 575., 560.]])
Coordinates:
    time         datetime64[ns] 2018-01-09T11:22:11.054208
  * y            (y) float64 1.338e+06 1.338e+06 ... 1.331e+06 1.331e+06
  * x            (x) float64 3.88e+05 3.880e+05 ... 3.955e+05 3.955e+05
    spatial_ref  int32 32628
Attributes:
    units:         reflectance
    nodata:        -9999
    crs:           EPSG:32628
    grid_mapping:  spatial_ref
[15]:
# Value selection slice

guinea_bissau.green.sel(x=slice(388020,395500), y=slice(1338000,1330530))
[15]:
<xarray.DataArray 'green' (y: 250, x: 250)>
array([[730., 737., 811., ..., 493., 514., 539.],
       [729., 717., 773., ..., 512., 532., 534.],
       [714., 738., 764., ..., 528., 541., 521.],
       ...,
       [662., 665., 676., ..., 506., 510., 480.],
       [667., 669., 664., ..., 553., 502., 501.],
       [662., 661., 676., ..., 600., 575., 560.]])
Coordinates:
    time         datetime64[ns] 2018-01-09T11:22:11.054208
  * y            (y) float64 1.338e+06 1.338e+06 ... 1.331e+06 1.331e+06
  * x            (x) float64 3.88e+05 3.880e+05 ... 3.955e+05 3.955e+05
    spatial_ref  int32 32628
Attributes:
    units:         reflectance
    nodata:        -9999
    crs:           EPSG:32628
    grid_mapping:  spatial_ref

Nous pouvons tracer la zone sélectionnée en utilisant la fonction matplotlib plt.imshow. Nous pouvons également utiliser la fonction xarray .plot(). Le tracé est un bon moyen de vérifier que la sélection affiche la partie supérieure gauche de l’image comme prévu.

La syntaxe de plt.imshow() est :

plt.imshow(data)

Nous copions donc le code dans les parenthèses de plt.imshow().

[16]:
plt.imshow(guinea_bissau.green.sel(x=slice(388020,395500), y=slice(1338000,1330530)))
[16]:
<matplotlib.image.AxesImage at 0x7f6fb0af2470>
../_images/python_basics_05_xarray_43_1.png

Note: Nous n’avons pas spécifié de carte de couleurs cmap donc vous pouvez voir qu’il prend le schéma de couleurs par défaut. Le tracé d’images en couleurs (RVB) est présenté pour la première fois dans la Session 2 : Chargement des données dans le bac à sable.

La syntaxe de la fonction xarray plot est :

data.plot()

Nous copions donc le code avant de taper .plot().

[17]:
guinea_bissau.green.sel(x=slice(388020,395500), y=slice(1338000,1330530)).plot()
[17]:
<matplotlib.collections.QuadMesh at 0x7f6fb0a0cba8>
../_images/python_basics_05_xarray_47_1.png

L’avantage d’utiliser la fonction .plot() de xarray est qu’elle affiche automatiquement les axes x et y en utilisant les valeurs des coordonnées, et non leur indice de position.

Exercices

5.1 Pouvez-vous accéder à la valeur crs dans les attributs du guinea_bissau xarray.Dataset ?

Introduction: Vous pouvez faire appel aux « attributs » de la même manière que vous sélectionneriez une « variable » ou une « coordonnée ».

[ ]:
# Replace the ? with the attribute name

guinea_bissau.?

5.2 Sélectionnez la région de la variable « bleue » délimitée par ces coordonnées :

  • latitude de l’intervalle [1335000, 1329030]

  • longitude de la plage [389520, 395490]

Instruction: Voulons-nous utiliser sel() ou isel() ? Quelle est la coordonnée x et quelle est la coordonnée y ?

5.3 Tracez la région sélectionnée en utilisant imshow, puis tracez la région en utilisant .plot().

[ ]:
# Plot using plt.imshow

[ ]:
# Plot using .plot()

Pouvez-vous changer la carte des couleurs en 'Blues' ?

Conclusion

Xarray est un outil important pour traiter les données d’observation de la Terre en Python. Son interface flexible et intuitive permet d’utiliser plusieurs méthodes pour sélectionner les données et effectuer des analyses.