... | ... | @@ -2,35 +2,33 @@ |
|
|
|
|
|
**Objectifs** : tracer une carte à partir de données (x,y,z), définir l'échelle des couleurs et la légende (=customiser la **colormap** et la **colorbar**)
|
|
|
|
|
|
**Mots clés** : **matshow** (et **imshow**), **contour et contourf**, **geopandas**, **colormap** (discrétisation ; ListedColormap...), **colorbar**
|
|
|
**Mots clés** : **matshow** (et **imshow**), **contour et contourf**, **geopandas**, **colormap** (discrétisation ; ListedColormap...), **colorbar**
|
|
|
|
|
|
**autre modules utilisés :** **pathlib** (notamment méthode **Path.is_file**), **Shapely** pour le traitement des objets géométriques
|
|
|
**autre modules utilisés :** **pathlib** (notamment méthode **Path.is_file**), **Shapely** pour le traitement des objets géométriques
|
|
|
|
|
|
**Modules pour les cartes géoréférencées ** : **pyproj**, **geopandas**, (_**cartopy ?**_)
|
|
|
\*\*Modules pour les cartes géoréférencées \*\* : **pyproj**, **geopandas**, (**_cartopy ?_**)
|
|
|
|
|
|
SOMMAIRE
|
|
|
========
|
|
|
**Etape 1** : tracer une carte à partir d'une **matrice de valeurs** ("heatmap")
|
|
|
([Sur le REPL.it, une série de cartes simples est proposée](https://replit.com/@CPoulard/LaCartoAvecMplMatshowEtShapely#main.py))
|
|
|
- **1.a** affichage sous forme de matrice (abscisses et ordonnées = indices de colonne et de lignes)
|
|
|
- **1.b** ajout d'une légende colorimétrique (**colorbar**)
|
|
|
- **1.c** affichage de la carte en coordonnées précisées via les xmin, xmax, ymin, ymax (argument **extent=**(gauche, droite, haut, bas))
|
|
|
- **1.d** personnalisation de la **colormap** (code couleur) et de la **colorbar** (légende)
|
|
|
# SOMMAIRE
|
|
|
|
|
|
**Etape 2** : lire un fichier **shape** et tracer les lignes ou polygones correspondants avec le module **Shapely**. Variante : avec **geopandas**, un module puissant mais difficile à installer
|
|
|
**Etape 1** : tracer une carte à partir d'une **matrice de valeurs** ("heatmap") ([Sur le REPL.it, une série de cartes simples est proposée](https://replit.com/@CPoulard/LaCartoAvecMplMatshowEtShapely#main.py))
|
|
|
|
|
|
**Etape 3** : lire des données (x,y,z) et les représenter par des isolignes
|
|
|
* **1.a** affichage sous forme de matrice (abscisses et ordonnées = indices de colonne et de lignes)
|
|
|
* **1.b** ajout d'une légende colorimétrique (**colorbar**)
|
|
|
* **1.c** affichage de la carte en coordonnées précisées via les xmin, xmax, ymin, ymax (argument **extent=**(gauche, droite, haut, bas))
|
|
|
* **1.d** personnalisation de la **colormap** (code couleur) et de la **colorbar** (légende)
|
|
|
|
|
|
**Etape 4** : _à venir_ : gestion des projections, modules pyproj et geopandas
|
|
|
**Etape 2** : lire un fichier **shape** et tracer les lignes ou polygones correspondants avec le module **Shapely**. Variante : avec **geopandas**, un module puissant mais difficile à installer
|
|
|
|
|
|
**Etape 3** : lire des données (x,y,z) et les représenter par des contours (isolignes ou aplats de couleur par classe)
|
|
|
|
|
|
**Etape 4** : _à venir_ : gestion des projections, modules pyproj et geopandas
|
|
|
|
|
|
<img src="uploads/3495d20090b9fa6f99526442c859cf9b/carte.png" width="240">
|
|
|
![](uploads/3495d20090b9fa6f99526442c859cf9b/carte.png)
|
|
|
|
|
|
_Exemple de carte d'intensité de pluie à partir d'une matrice, avec tracé des rivières et d'un BV ; colormap discrète définie par une liste de couleurs ; on verra dans l'atelier comment faire mieux en discrétisant une colormap continue prédéfinie_
|
|
|
|
|
|
**Etape 1** : tracer une carte à partir d'une **matrice de valeurs** ("heatmap")
|
|
|
=====================
|
|
|
# **Etape 1** : tracer une carte à partir d'une **matrice de valeurs** ("heatmap")
|
|
|
|
|
|
[Sur le REPL.it, une série de cartes simples est proposée](https://replit.com/@CPoulard/LaCartoAvecMplMatshowEtShapely#main.py), on ne travaille qu'avec une petite matrice 5x5 sortie du chapeau . Cela permet néanmoins de voir les bases : \* l'instruction **imshow** pour tracer le champ de valeurs sur une grille (en numéros de ligne et numéros de colonne) \* l'argument **extent** pour tracer avec, par exemple, des coordonnées Lambert \* faire apparaître **une échelle de couleurs et la customiser**.
|
|
|
|
|
|
Sur ce git, le code est plus complet, et permet de tracer :
|
... | ... | @@ -41,21 +39,14 @@ Sur ce git, le code est plus complet, et permet de tracer : |
|
|
|
|
|
## Etape 1.a : Premier contact, afficher une matrice avec _plt.matshow_
|
|
|
|
|
|
Un premier contact avec la méthode **plt.imshow** ou **plt.matshow**, où on passe juste une matrice .
|
|
|
Un bon réflexe : lire la doc !
|
|
|
**Axes.matshow(Z:array-like, kwargs)**¶
|
|
|
_Plot the values of a 2D matrix or array as color-coded image.
|
|
|
The matrix will be shown the way it would be printed, with the first row at the top. Row and column numbering is zero-based._
|
|
|
|
|
|
**Axes.imshow(Z:= array-like or PIL image, kwargs)** ¶
|
|
|
_Display data as an image, i.e., on a 2D regular raster. The input may either be actual RGB(A) data, or 2D scalar data_
|
|
|
Un premier contact avec la méthode **plt.imshow** ou **plt.matshow**, où on passe juste une matrice . Un bon réflexe : lire la doc ! **Axes.matshow(Z:array-like, kwargs)**¶ _Plot the values of a 2D matrix or array as color-coded image. The matrix will be shown the way it would be printed, with the first row at the top. Row and column numbering is zero-based._
|
|
|
|
|
|
**Axes.spy(Z:= array-like , kwargs)** ¶
|
|
|
_Plot the sparsity pattern of a 2D array.
|
|
|
This visualizes the non-zero values of the array._
|
|
|
**Axes.imshow(Z:= array-like or PIL image, kwargs)** ¶ _Display data as an image, i.e., on a 2D regular raster. The input may either be actual RGB(A) data, or 2D scalar data_
|
|
|
|
|
|
**Axes.spy(Z:= array-like , kwargs)** ¶ _Plot the sparsity pattern of a 2D array. This visualizes the non-zero values of the array._
|
|
|
|
|
|
_L'exemple mis en ligne dans le REPL utilise en entrée une matrice 5x5 codée en dur. D'abord on appelle seulement plt.matshow(matrice), puis on va ajouter progressivement des arguments ou objets supplémentaires._
|
|
|
|
|
|
```python
|
|
|
from matplotlib import pyplot as plt
|
|
|
# méthode matshow en spécifiant uniquement la matrice
|
... | ... | @@ -63,21 +54,20 @@ plt.matshow([[1, 2, 30, 50, 120], [21, 2, 50, 50, 90], [-1, 2, -30, 50, -120], [ |
|
|
|
|
|
plt.show()
|
|
|
```
|
|
|
|
|
|
Quelques remarques suite à la première figure générée :
|
|
|
|
|
|
* Une matrice, par défaut, est tracée par matshow() selon une grille avec la première valeur dans la case _en haut à gauche_. Les cases représentant un élément de la matrice sont _centrées sur les points de grille_. => on préfèrerait 1 carré = 1 pixel : étape 2
|
|
|
* Une matrice, par défaut, est tracée par matshow() selon une grille avec la première valeur dans la case _en haut à gauche_. Les cases représentant un élément de la matrice sont _centrées sur les points de grille_. => on préfèrerait 1 carré = 1 pixel : étape 2
|
|
|
* voir l'échelle colorimétrique : étape 3
|
|
|
* comment customiser l’échelle ? : étape 4
|
|
|
* comment travailler avec des données géoréférencées ? : étape 5
|
|
|
|
|
|
| deuxième étape : méthode `matshow `en spécifiant uniquement la matrice ; on a ajouté une `colorbar ` | troisième étape : on envoie à matshow l'argument extent, ce qui revient à définir les coordonnées des 4 coins
|
|
|
|----------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
|
|
|
* comment customiser l’échelle ? : étape 4
|
|
|
* comment travailler avec des données géoréférencées ? : étape 5
|
|
|
| deuxième étape : méthode `matshow `en spécifiant uniquement la matrice ; on a ajouté une `colorbar` | troisième étape : on envoie à matshow l'argument extent, ce qui revient à définir les coordonnées des 4 coins |
|
|
|
|-----------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
|
|
|
| ![Cartes_Replit_2](uploads/cf23f79e6554fe32fbc2de57eceb3e89/Cartes_Replit_2.PNG) | ![](uploads/7b3cc259ebe50939fce5a65662361842/Cartes_Replit_3.PNG) |
|
|
|
|
|
|
\*\*Etape 1.b \*\*: légende colorimétrique
|
|
|
|
|
|
**Etape 1.b **: légende colorimétrique
|
|
|
|
|
|
Dans un premier temps, on va demander à afficher la légende ; comme on n'a pas précisé le code couleur, donc c'est donc un paramétrage "par défaut". On en profite pour ajouter un carré orange de côté 1 dont un des sommets est en (0,0), pour matérialiser le décalage entre le pixels et la grille. Note : l'argument 'interpolate' nous permet de choisir entre cette représentation "par pixels" et une représentation lissée.
|
|
|
Dans un premier temps, on va demander à afficher la légende ; comme on n'a pas précisé le code couleur, donc c'est donc un paramétrage "par défaut". On en profite pour ajouter un carré orange de côté 1 dont un des sommets est en (0,0), pour matérialiser le décalage entre le pixels et la grille. Note : l'argument 'interpolate' nous permet de choisir entre cette représentation "par pixels" et une représentation lissée.
|
|
|
|
|
|
```python
|
|
|
from matplotlib import pyplot as plt
|
... | ... | @@ -98,11 +88,10 @@ cbar.set_label('colorbar par défaut ' ) |
|
|
plt.tick_params(labeltop=False, labelbottom=True)
|
|
|
fig.show()
|
|
|
```
|
|
|
|
|
|
**Etape 1.b **: On spécifie les coordonnées des coins grâce à l'argument _extent_.
|
|
|
=========================
|
|
|
La carte reste visuellement identique mais le repère a changé : les cases coïncident alors avec les mailles de la grille, et l'axe des y prend alors la valeur 0 en bas . Pour bien montrer le changement de repère, on a placé un rectangle défini de la même manière qui n'a pas le même emplacement dans les 2 repères.
|
|
|
Voir aussi l'argument **origin** qui peut être utile.
|
|
|
|
|
|
# \*\*Etape 1.b \*\*: On spécifie les coordonnées des coins grâce à l'argument _extent_.
|
|
|
|
|
|
La carte reste visuellement identique mais le repère a changé : les cases coïncident alors avec les mailles de la grille, et l'axe des y prend alors la valeur 0 en bas . Pour bien montrer le changement de repère, on a placé un rectangle défini de la même manière qui n'a pas le même emplacement dans les 2 repères. Voir aussi l'argument **origin** qui peut être utile.
|
|
|
|
|
|
```python
|
|
|
fig = plt.figure("D'une matrice à une carte de champ")
|
... | ... | @@ -120,14 +109,11 @@ plt.tick_params(labeltop=False, labelbottom=True) |
|
|
fig.show()
|
|
|
```
|
|
|
|
|
|
**Etape 1.d **: personnaliser l'échelle colorimétrique et la légende correspondante
|
|
|
On peut personnaliser le code couleur, en imposant les couleurs et les limites de classe, et la légende, en formatant les valeurs ou en ajoutant un titre par exemple.
|
|
|
|
|
|
\*\*Etape 1.d \*\*: personnaliser l'échelle colorimétrique et la légende correspondante On peut personnaliser le code couleur, en imposant les couleurs et les limites de classe, et la légende, en formatant les valeurs ou en ajoutant un titre par exemple.
|
|
|
| 4) on peut définir une colormap par une liste de couleurs, et spécifier des limites de classe ; notez les classes pour "-200 et moins" ou "500 et plus" | 5) quand c'est préférable, on peut partir d'une échelle colorimétrique continue que l'on va découper en N classes. Il reste possible de la modifier couleur par couleur. |
|
|
|
|----------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
|
|
|
|---------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
|
| ![Cartes_Replit_4](uploads/d34b473b6d3dc4b6e991bc66b9e6a79e/Cartes_Replit_4.PNG) | ![Cartes_Replit_5](uploads/a869b3360c738f4bd1927d213b767689/Cartes_Replit_5.PNG) |
|
|
|
|
|
|
|
|
|
Dans un premier temps, on va passer une liste de couleurs 'nommées' définies par l'utilisateur (exemple de noms simples : 'red', 'blue', 'orange'), instance de la classe ListedColorMaps. Les limites de classe sont définies avec bounds.
|
|
|
|
|
|
```python
|
... | ... | @@ -178,21 +164,16 @@ fig.show() |
|
|
```
|
|
|
|
|
|
## **Etape 2** : Lire et tracer des shapes
|
|
|
=================
|
|
|
Lire des fichiers *shape**, issus de SIG comme QGis (plusieurs fichiers dont un avec l'extension *.shp) est utile indépendamment ou avec une représentation de champs de valeur, pour laquelle ils serviront au minimum de points de repère.
|
|
|
Dans cette partie, on va travailler avec des vrais fichiers de champs et des shapes.
|
|
|
|
|
|
Au passage, rappelons que la [base de données vectorielle TOPO de l'IGN est téléchargeable en ligne](https://geoservices.ign.fr/documentation/donnees/vecteur/bdtopo). Un[document décrit les données](https://geoservices.ign.fr/sites/default/files/2021-07/DC_BDTOPO_3-0_0.pdf), avec notamment couches hydrographiques disponibles (réseau hydrographique, bassins versants à chaque confluence...)
|
|
|
================= Lire des fichiers _shape_\*, issus de SIG comme QGis (plusieurs fichiers dont un avec l'extension \*.shp) est utile indépendamment ou avec une représentation de champs de valeur, pour laquelle ils serviront au minimum de points de repère. Dans cette partie, on va travailler avec des vrais fichiers de champs et des shapes.
|
|
|
|
|
|
Au passage, rappelons que la [base de données vectorielle TOPO de l'IGN est téléchargeable en ligne](https://geoservices.ign.fr/documentation/donnees/vecteur/bdtopo). Un[document décrit les données](https://geoservices.ign.fr/sites/default/files/2021-07/DC_BDTOPO_3-0_0.pdf), avec notamment couches hydrographiques disponibles (réseau hydrographique, bassins versants à chaque confluence...)
|
|
|
|
|
|
Dans le code fourni, on trouve des fonctions pour lire et écrire des fichiers shapes, puis des champs, pour pouvoir les superposer dans une même carte.
|
|
|
|
|
|
|
|
|
## **Etape 2.a** : Lire des fichiers shape "seuls"
|
|
|
|
|
|
A cette étape, on va lire les fichiers en plusieurs étapes, selon une démarche trouvée dans un tuto.
|
|
|
C'est un peu lourd, mais cela permet de comprendre la structure d'un fichier shp, et de décrire les différents objets (LineString, Polygon...).
|
|
|
Ensuite, on va utiliser le module Shapely qui permet de créer des objets géométriques et de disposer d'un grand nombre de méthodes. :
|
|
|
A cette étape, on va lire les fichiers en plusieurs étapes, selon une démarche trouvée dans un tuto. C'est un peu lourd, mais cela permet de comprendre la structure d'un fichier shp, et de décrire les différents objets (LineString, Polygon...). Ensuite, on va utiliser le module Shapely qui permet de créer des objets géométriques et de disposer d'un grand nombre de méthodes. :
|
|
|
|
|
|
* lecture_shape(chemin_fichier_shape, trace=False), qui suppose que le fichier shape contient un seul objet géométrique, un polygone
|
|
|
* lecture_shape_plusieurs_elements(chemin_fichier_shape, trace=False) : qui généralise le cas précédent. Ces deux fonctions vont convertir les informations contenues dans les fichiers en un objet d'un type défini dans Shapely, et contient une méthode pour le(s) tracer. On remarque que l'import de la classe Polygon de Shapely se fait avec un alias, tout simplement parce qu'il m'est arrivé d'importer deux classes de même nom, Polygon, de deux bibliothèques différentes ! Un alias comme PolygonShapely lève les ambiguités (c'est une des raisons pour lesquelles import \* est mal ! Vous importez tout ce qui a dans une bibliothèque, avec des objets qui portent peut-être le même nom qu'un autre...).
|
... | ... | @@ -249,6 +230,18 @@ mon_champ.ajouter_shape("réseau", nom="réseau hydrographique") |
|
|
mon_champ.ajouter_shape("contour", nom="France")
|
|
|
cmap, cbounds = cmap_continue(50)
|
|
|
mon_champ.trace_champ(cmap, cbounds)
|
|
|
|
|
|
**Etape 3** : lire des données (x,y,z) et les représenter par des isolignes
|
|
|
|
|
|
```python
|
|
|
from matplotlib import pyplot as plt
|
|
|
matrice = [[1, 2, 30, 50, 120], [21, 2, 50, 50, 90], [-1, 2, -30, 50, -120], [41, 42, 80, 50, 50], [9, 29, 39, 590, 10]]
|
|
|
x= (1,2,5,10,20)
|
|
|
y=x
|
|
|
cax = plt.contour(x,y,matrice) # renvoie un objet matplotlib.contour.QuadContourSet
|
|
|
>>>
|
|
|
cbar= plt.colorbar(cax)
|
|
|
plt.show()
|
|
|
```
|
|
|
|
|
|
### Compléments techniques, si besoin
|
... | ... | @@ -259,4 +252,7 @@ voir code. |
|
|
|
|
|
#### NB : Inclure sur une même figure des champs et des polygones issus de fichiers shape
|
|
|
|
|
|
Cela s'obtient en passant un "ax" comme argument ou en retournant un "ax". Sera détaillé si besoin. |
|
|
\ No newline at end of file |
|
|
Cela s'obtient en passant un "ax" comme argument ou en retournant un "ax". Sera détaillé si besoin.
|
|
|
| ![contour](uploads/f0f3c34ef3476098e086ba2d06a9c04d/contour.png) | |
|
|
|
|------------------------------------------------------------------|--|
|
|
|
| _matrice de l'étape 1 représentée avec contour_ | | |
|
|
\ No newline at end of file |