|
|
## **(:warning: en construction ! :construction: :construction_worker: ) **
|
|
|
## \*\*(⚠ en construction ! 🚧 👷 ) \*\*
|
|
|
|
|
|
**Objectifs** :
|
|
|
|
|
|
Sur le REPL.it, on ne travaille qu'avec une petite matrice 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 appraraître une échelle de couleurs et la customiser.
|
|
|
* tracer une carte à partir d'une matrice de valeurs ("heatmap"), définir l'échelle des couleurs et la légende (=customiser la **colormap** et la **colorbar**)
|
|
|
* lire un fichier **shape** et tracer les lignes ou polygones correspondants avec le module **Shapely**. Variante : avec **geopandas**, un module puissant mais difficile à installer
|
|
|
|
|
|
\*\*Mots clés\*\* : colormap (discrétisation ; ListedColormap...), colorbar
|
|
|
|
|
|
![](uploads/3495d20090b9fa6f99526442c859cf9b/carte.png)
|
|
|
|
|
|
_Exemple de carte d'intensité de pluie avec tracé des rivières et d'un BV ; colormap discrète définie par une liste de couleurs_
|
|
|
|
|
|
Sur le REPL.it, on ne travaille qu'avec une petite matrice 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 appraraître une échelle de couleurs et la customiser.
|
|
|
|
|
|
Sur ce git, le code est plus complet, et permet de tracer :
|
|
|
- des champs lus dans un fichier grid ascii
|
|
|
- des champs lus dans un fichier binaire (pour info)
|
|
|
- des fichiers shape.
|
|
|
|
|
|
## Premier contact avec *plt.matshow*, sur une matrice simple
|
|
|
* des champs lus dans un fichier grid ascii
|
|
|
* des champs lus dans un fichier binaire (pour info)
|
|
|
* des fichiers shape.
|
|
|
|
|
|
## Premier contact avec _plt.matshow_, sur une matrice simple
|
|
|
|
|
|
Un premier contact avec la méthode plt.imshow ou plt.matshow, où on passe juste une matrice (ici, une liste de listes).
|
|
|
C'est l'exemple repris dans le REPL.
|
|
|
Un premier contact avec la méthode plt.imshow ou plt.matshow, où on passe juste une matrice (ici, une liste de listes). C'est l'exemple repris dans le REPL.
|
|
|
|
|
|
```python
|
|
|
from matplotlib import pyplot as plt
|
... | ... | @@ -22,14 +29,15 @@ plt.matshow([[1, 2, 30, 50, 120], [21, 2, 50, 50, 90], [-1, 2, -30, 50, -120], [ |
|
|
|
|
|
plt.show()
|
|
|
```
|
|
|
|
|
|
Quelques remarques :
|
|
|
|
|
|
* valeurs centrées sur les points de la grille => on préfèrerait 1 carré = 1 pixel
|
|
|
* voir l'échelle colorimétrique ?
|
|
|
* comment customiser l’échelle ?
|
|
|
* changer l’échelle pour des coordonnées géoréférencées ? (par ex. Lambert)
|
|
|
|
|
|
On va d'abord s'occuper de l'échelle colorimétrique.
|
|
|
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.
|
|
|
On va d'abord s'occuper de l'échelle colorimétrique. 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
|
... | ... | @@ -49,7 +57,8 @@ plt.tick_params(labeltop=False, labelbottom=True) |
|
|
fig.show()
|
|
|
```
|
|
|
|
|
|
Ensuite, on utilise tout simplement l'argument *extent* pour définir des coordonnées
|
|
|
Ensuite, on utilise tout simplement l'argument _extent_ pour définir des coordonnées
|
|
|
|
|
|
```python
|
|
|
fig = plt.figure("D'une matrice à une carte de champ")
|
|
|
ax = fig.add_subplot(111)
|
... | ... | @@ -68,8 +77,7 @@ fig.show() |
|
|
|
|
|
### Personnaliser l'échelle colorimétrique
|
|
|
|
|
|
Avec une liste de couleurs définies par l'utilisateur, objet ListedColorMaps.
|
|
|
Je choisis aussi les limites de classe avec bounds.
|
|
|
Avec une liste de couleurs définies par l'utilisateur, objet ListedColorMaps. Je choisis aussi les limites de classe avec bounds.
|
|
|
|
|
|
```python
|
|
|
from matplotlib.colors import ListedColormap as mpl_colors_ListedColormap
|
... | ... | @@ -90,11 +98,9 @@ plt.tick_params(labeltop=False, labelbottom=True) |
|
|
fig.show()
|
|
|
```
|
|
|
|
|
|
En m'appuyant sur une colormap continue, dont je peux aussi comme précédemment forcer le découpage avec bounds (mais je ne maîtrise pas les nuances de couleurs dans chaque classe)
|
|
|
définies par l'utilisateur, objet ListedColorMaps.
|
|
|
Je choisis aussi les limites de classe avec bounds.
|
|
|
En m'appuyant sur une colormap continue, dont je peux aussi comme précédemment forcer le découpage avec bounds (mais je ne maîtrise pas les nuances de couleurs dans chaque classe) définies par l'utilisateur, objet ListedColorMaps. Je choisis aussi les limites de classe avec bounds.
|
|
|
|
|
|
https://matplotlib.org/3.1.1/gallery/color/colormap_reference.html
|
|
|
[https://matplotlib.org/3.1.1/gallery/color/colormap_reference.html](https://matplotlib.org/3.1.1/gallery/color/colormap_reference.html)
|
|
|
|
|
|
```python
|
|
|
from matplotlib.colors import ListedColormap as mpl_colors_ListedColormap
|
... | ... | @@ -125,70 +131,54 @@ fig.show() |
|
|
## Travailler avec des vrais fichiers de champs et des shapes
|
|
|
|
|
|
Dans le code, on trouve :
|
|
|
### Deux fonctions pour lire et tracer des *fichiers champs*
|
|
|
L'une accepte un format grid ascii et l'autre du binaire. Quand on exécute le code AtelierD_Champs, le message suivant d'affiche sur la console : " choix du type de fichier champ à lire (grid ou bin) ? " ; on vous demandera ensuite un nom de fichier, que le programme essaiera de lire avec l'une ou l'autre fonction selon votre choix (grid ou bin).
|
|
|
Un exemple de fichier grid vous sera fourni. Le fichier champ de pluie radar utilisé dans les diapos est trop gros pour être mis à demeure sur le gitlab, il sera fourni au besoin en séance via filesender.
|
|
|
|
|
|
Le fichier [grid ascii](https://en.wikipedia.org/wiki/Esri_grid), contrairement au grid binaire, est au format texte, et il est facile d'écrire ou de lire ce format.
|
|
|
Les six première lignes correspondent aux informations suivantes : nombre de colonnes puis de lignes de la matrice, coordonnées du point situé en bas à gauche (lowerleft), taille d'une cellule et code lacune.
|
|
|
### Deux fonctions pour lire et tracer des _fichiers champs_
|
|
|
|
|
|
L'une accepte un format grid ascii et l'autre du binaire. Quand on exécute le code AtelierD_Champs, le message suivant d'affiche sur la console : " choix du type de fichier champ à lire (grid ou bin) ? " ; on vous demandera ensuite un nom de fichier, que le programme essaiera de lire avec l'une ou l'autre fonction selon votre choix (grid ou bin). Un exemple de fichier grid vous sera fourni. Le fichier champ de pluie radar utilisé dans les diapos est trop gros pour être mis à demeure sur le gitlab, il sera fourni au besoin en séance via filesender.
|
|
|
|
|
|
Le fichier [grid ascii](https://en.wikipedia.org/wiki/Esri_grid), contrairement au grid binaire, est au format texte, et il est facile d'écrire ou de lire ce format. Les six première lignes correspondent aux informations suivantes : nombre de colonnes puis de lignes de la matrice, coordonnées du point situé en bas à gauche (lowerleft), taille d'une cellule et code lacune.
|
|
|
|
|
|
ncols 21
|
|
|
nrows 27
|
|
|
xllcorner 823737.2847998787
|
|
|
yllcorner 6619018.593063972
|
|
|
cellsize 1013.374429690636
|
|
|
NODATA_value -1
|
|
|
(ensuite, nrows ligne de ncols valeurs chacune )
|
|
|
ncols 21 nrows 27 xllcorner 823737.2847998787 yllcorner 6619018.593063972 cellsize 1013.374429690636 NODATA_value -1 (ensuite, nrows ligne de ncols valeurs chacune )
|
|
|
|
|
|
une fois le fichier lu, on applique imshow comme précédemment
|
|
|
|
|
|
### Deux fonctions pour lire et tracer des *fichiers shape*, en utilisant en particulier le module Shapely :
|
|
|
- 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...).
|
|
|
### Deux fonctions pour lire et tracer des _fichiers shape_, en utilisant en particulier le module Shapely :
|
|
|
|
|
|
* 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...).
|
|
|
|
|
|
```python
|
|
|
from shapely.geometry import Polygon as PolygonShapely
|
|
|
|
|
|
```
|
|
|
|
|
|
#### Deux fonctions pour lire des fichiers shape et les tracer
|
|
|
On va d'abord s'intéresser aux fichiers "shape" (on rappelle qu'il y a en fait plusieurs fichiers, dont un seul porte l'extension *.shp).
|
|
|
#### Deux fonctions pour lire des fichiers shape et les tracer
|
|
|
|
|
|
On passe le chemin en argument ; on teste que ce chemin existe avec Path.is_file.
|
|
|
Les instructions ont été trouvées dans des discussions sur un forum dédié : on utilise le module shapefile pour lire le fichier shape, et ensuite on utilise les méthodes de l'objet lu pour en extraire l'information utile (variable feature) et le convertir en objet shapely avec shape.
|
|
|
On va d'abord s'intéresser aux fichiers "shape" (on rappelle qu'il y a en fait plusieurs fichiers, dont un seul porte l'extension \*.shp).
|
|
|
|
|
|
On passe le chemin en argument ; on teste que ce chemin existe avec Path.is_file. Les instructions ont été trouvées dans des discussions sur un forum dédié : on utilise le module shapefile pour lire le fichier shape, et ensuite on utilise les méthodes de l'objet lu pour en extraire l'information utile (variable feature) et le convertir en objet shapely avec shape.
|
|
|
|
|
|
*lecture_shape* suppose qu'il y a dans le fichier shape un seul objet intéressant, un polygone.
|
|
|
On ne va donc travailler qu'avec le premier objet : feature = shape_lu.shapeRecords()[0]
|
|
|
On propose de tracer l'objet pour vérifier que l'import s'est bien passé : on remarque que l'instruction x, y = objet_shapely.exterior.xy permet d'extraire la liste des abscisses et la liste des ordonnées des points, information dont on a besoin pour tracer avec matplotlib.
|
|
|
La fonction retourne un objet shapely, un PolygonShapely.
|
|
|
_lecture_shape_ suppose qu'il y a dans le fichier shape un seul objet intéressant, un polygone. On ne va donc travailler qu'avec le premier objet : feature = shape_lu.shapeRecords()\[0\] On propose de tracer l'objet pour vérifier que l'import s'est bien passé : on remarque que l'instruction x, y = objet_shapely.exterior.xy permet d'extraire la liste des abscisses et la liste des ordonnées des points, information dont on a besoin pour tracer avec matplotlib. La fonction retourne un objet shapely, un PolygonShapely.
|
|
|
|
|
|
*lecture_shape_plusieurs_elements* est plus général, il va boucler sur les objets extraits du fichier et va vérifier le type des objets extraits un à un par shape(item), et applique un traitement un peu différent : par exemple si c'est un PolygonShapely on retrouve les instructions précédentes
|
|
|
_lecture_shape_plusieurs_elements_ est plus général, il va boucler sur les objets extraits du fichier et va vérifier le type des objets extraits un à un par shape(item), et applique un traitement un peu différent : par exemple si c'est un PolygonShapely on retrouve les instructions précédentes
|
|
|
|
|
|
```python
|
|
|
if isinstance(shape_item, PolygonShapely):
|
|
|
x, y = shape_item.exterior.xy
|
|
|
liste_xy.append([x, y])
|
|
|
print("Polygone")
|
|
|
|
|
|
```
|
|
|
|
|
|
La fonction retourne la liste des tuples (x,y) pour les objets 2D ainsi que la liste des points indépendants, non exploités dans la suite.
|
|
|
|
|
|
#### classe ObjetsShapely
|
|
|
Elle permet d'affiner la manipulation des shapes avec une méthode de lecture tirée de la fonction "indépendante", une méthode __repr__ qui définit ce qui se passe quand on tape print(mon_instance_de_cette_classe), et une méthode pour tracer qui prend en argument un objet de type "Axes", ce qui permet de construire une carte en plusieurs étapes
|
|
|
|
|
|
Elle permet d'affiner la manipulation des shapes avec une méthode de lecture tirée de la fonction "indépendante", une méthode **repr** qui définit ce qui se passe quand on tape print(mon_instance_de_cette_classe), et une méthode pour tracer qui prend en argument un objet de type "Axes", ce qui permet de construire une carte en plusieurs étapes
|
|
|
|
|
|
#### classe Champ
|
|
|
Elle permet de manipuler des champs de valeurs avec des méthodes associées.
|
|
|
creer_heatmap va demander à l'utilisateur (fonction *input*) le format et le fichier, pour aiguiller vers l'une ou l'autre méthode de lecture, pour du binaire ou du grid ascii. Cette méthode s'exécute dès la création de l'instance, on pourrait faire autrement.
|
|
|
La méthode test_trace_matrice_valeurs trace le champ seul pour vérification, si besoin.
|
|
|
La méthode trace_champ construit une carte avec les valeurs de champ, en ajoutant tous les objets Shapely qui auront été définis en plus avec la méthode ajouter_shape.
|
|
|
Ici, on a défini un "type" que l'on passe en argument, qui va simplement déterminer la couleur du tracé (bleu pour un réseau hydrographique...).
|
|
|
|
|
|
Elle permet de manipuler des champs de valeurs avec des méthodes associées. creer_heatmap va demander à l'utilisateur (fonction _input_) le format et le fichier, pour aiguiller vers l'une ou l'autre méthode de lecture, pour du binaire ou du grid ascii. Cette méthode s'exécute dès la création de l'instance, on pourrait faire autrement. La méthode test_trace_matrice_valeurs trace le champ seul pour vérification, si besoin. La méthode trace_champ construit une carte avec les valeurs de champ, en ajoutant tous les objets Shapely qui auront été définis en plus avec la méthode ajouter_shape. Ici, on a défini un "type" que l'on passe en argument, qui va simplement déterminer la couleur du tracé (bleu pour un réseau hydrographique...).
|
|
|
|
|
|
### Déroulé dans le corps de programme
|
|
|
### Déroulé dans le corps de programme
|
|
|
|
|
|
Les instructions du corps de programme demandent la création d'une carte composée d'un champ de valeurs (fichier grid ascii ou binaire) et de trois fichiers shapes : un pour le bassin versant, un pour le réseau hydrographique et un pour le contour. Ici, on a choisi une colormap continue, mais une autre fonction permet de choisir une échelle discrète à partir d'une colormap continue.
|
|
|
|
... | ... | @@ -199,14 +189,13 @@ 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)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
### Compléments techniques, si besoin
|
|
|
|
|
|
#### Lire un fichier de champ binaire et le tracer
|
|
|
voir code.
|
|
|
|
|
|
voir code.
|
|
|
|
|
|
#### NB : Inclure sur une même figure des champs et des polygones issus de fichiers shape
|
|
|
|
... | ... | |