Analyse de hauteurs d’eau pour les bâtiments du PICC

Import des modules

[ ]:
# import _add_path # for debugging purposes only - can be removed in production

try:
    from wolfhece import is_enough
    if not is_enough('2.2.32'):
        raise ImportError("Please update wolfhece to at least version 2.2.31")
except ImportError:
    raise ImportError("Please install the required version of wolfhece: pip install wolfhece>=2.2.30")

from wolfhece.analyze_poly import Building_Waterdepth_analysis
from wolfhece.wolf_array import WolfArray, header_wolf
from wolfhece.PyVertexvectors import vector, zone, Zones, wolfvertex as wv
from wolfhece.pydownloader import toys_dataset
from wolfhece.PyPalette import wolfpalette as wp

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pathlib import Path

Lecture de matrices

[2]:
T = [2, 5, 15, 25, 50, 100, 1000]
dir_arrays = 'Analysis_PICC_poly'

arrays = {f"T{t}": WolfArray(toys_dataset(dir_arrays, f"T{t}.tif")) for t in T}
[3]:
print(arrays['T2'])
Shape  : 1964 x 4218
Resolution  : 1.0 x 1.0
Spatial extent :
   - Origin : (251619.0 ; 135545.0)
   - End : (253583.0 ; 139763.0)
   - Width x Height : 1964.0 x 4218.0
   - Translation : (0.0 ; 0.0)
Null value : 0.0


Création de l’objet d’analyse

[4]:
# On passe les matrices sous la forme d'un dictionnaire dont les clés seront exploités pour les légendes
analyze = Building_Waterdepth_analysis(arrays= arrays,
                                        zones= toys_dataset('PICC', 'PICC_Vesdre.shp'),
                                        merge_zones=True, # merge all buildings into one zone - otherwise, each building will be a separate zone
                                        )
[5]:
analyze.all_categories
[5]:
['Administration',
 'Agricole',
 'Annexe',
 'Commerce ou service',
 'Culture, sport ou loisir',
 'Gare',
 'Habitation',
 'Industriel',
 'Lieu de culte',
 'Maison de repos',
 'Police',
 'Pompier',
 'Scolaire',
 'Scolaire fondamental',
 'Scolaire secondaire',
 'Station service']

Comptage du nombre de polygones avec valeurs

[6]:
df = analyze.count_strictly_positive_as_df()
print(df)
  Zone  Array  Count
0  all     T2     64
1  all     T5    168
2  all    T15    384
3  all    T25    693
4  all    T50    993
5  all   T100   1331
6  all  T1000   1999

Graphique du nombre de polygones contenant des valeurs strictement positives

[7]:
analyze.plot_count_strictly_positive()
../_images/tutorials_analyze_polygons_wd_picc_12_0.png
[7]:
(<Figure size 640x480 with 1 Axes>,
 <Axes: title={'center': 'Count of strictly positive values'}, xlabel='Array', ylabel='Count of strictly positive values'>)

Graphique de la distribution des valeurs

[8]:
analyze.plot_distributed_values(bins = [0., .3, 1.3, 2.5, 4, -1],
                                operator= 'Mean',
                                merge_zones= True,
                                engine= 'seaborn')
../_images/tutorials_analyze_polygons_wd_picc_14_0.png
[8]:
(<Figure size 640x480 with 1 Axes>,
 <Axes: xlabel='Water Depth [m]', ylabel='Count'>)

Sélection de certains types de bâtiments

On a vu un peu plus tôt comment afficher les catégories disponibles:

  • ‘Agricole’,

  • ‘Culture, sport ou loisir’,

  • ‘Station service’,

  • ‘Habitation’,

  • ‘Annexe’,

  • ‘Pompier’,

  • ‘Gare’,

  • ‘Police’,

  • ‘Scolaire fondamental’,

  • ‘Industriel’,

  • ‘Maison de repos’,

  • ‘Administration’,

  • ‘Scolaire secondaire’,

  • ‘Commerce ou service’,

  • ‘Scolaire’,

  • ‘Lieu de culte’

[9]:
analyze.active_categories = ['Habitation']
analyze.plot_count_strictly_positive()
analyze.plot_distributed_values(bins = [0., .3, 1.3, 2.5, 4, -1],
                                operator= 'Mean',
                                merge_zones= True,
                                engine= 'seaborn')
../_images/tutorials_analyze_polygons_wd_picc_16_0.png
../_images/tutorials_analyze_polygons_wd_picc_16_1.png
[9]:
(<Figure size 640x480 with 1 Axes>,
 <Axes: xlabel='Water Depth [m]', ylabel='Count'>)

Graphique des surfaces concernées

Il est également possible de n’activer que certaines matrices.

[10]:
analyze.active_arrays = analyze.all_arrays
analyze.deactivate_array('T1000')
analyze.deactivate_array('T100')
analyze.plot_distributed_areas(bins = [0., .3, 1.3, 2.5, 4, -1],
                                operator= 'Mean',
                                merge_zones= True)
print('Matrices actives : ', analyze.active_arrays)
print('Catégories actives : ', analyze.active_categories)
../_images/tutorials_analyze_polygons_wd_picc_18_0.png
Matrices actives :  ['T2', 'T5', 'T15', 'T25', 'T50']
Catégories actives :  ['Habitation']

Récupération d’une zone pour l’affichage

L’objet analyze permet de récupérer les zones des polygones analysés, sur base des catégories et des matrices activées.

Une ‘zone’ sera créée pour chaque matrice activée.

[11]:
zone2plot = analyze.as_zones()
print(zone2plot.mynames)
['T2', 'T5', 'T15', 'T25', 'T50']

Paramétrage de la zone :

  • set_filled(True) pour remplir les polygones,

  • set_colors_from_value('Mean', cmap=cmap, vmin=0, vmax=4) pour colorer les polygones en fonction de la valeur moyenne des hauteurs d’eau, avec une palette de couleurs définie par cmap.

[12]:
zone2plot.set_filled(True)
cmap = wp()
cmap.default16()
cmap.distribute_values(0., 5.)
zone2plot.set_colors_from_value('Mean', cmap=cmap, vmin=0, vmax=4)

Dessin des polygones

Etapes :

  • création d’autant de sous-graphes que de matrices activées.

  • pour chaque matrice activée, on affiche la matrice et un fond de plan IGN.

  • on affiche les polygones de la zone créée précédemment.

[13]:
# %matplotlib widget
fig, ax = plt.subplots(1,5, figsize=(20, 20), sharey='row', sharex='row')
for i, key in enumerate(zone2plot.mynames):
    arrays[key].mypal.defaultgray()
    arrays[key].plot_matplotlib((fig, ax[i]), IGN = True, cat = 'orthoimage_coverage_2021')
    zone2plot[key].plot_matplotlib(ax[i])
    ax[i].set_aspect('equal')
../_images/tutorials_analyze_polygons_wd_picc_24_0.png

Récupération des valeurs sous forme de DataFrame

[14]:
df50 = analyze['T50'].get_values()
print('Nombre de polygones : ', len(df50))
Nombre de polygones :  1576

On peut ensuite trouver toutes les autres grandeurs statistiques sur les valeurs des polygones, comme la somme, la moyenne, le minimum, le maximum, etc.

[15]:
maxima = df50.max()

minima = df50.min()

p90 = df50.quantile(0.9)
print(p90)
Habitation___3       0.450813
Habitation___4       1.570447
Habitation___5       0.248419
Habitation___14      1.144392
Habitation___15      0.236443
                       ...
Habitation___2768    0.607735
Habitation___2774    0.327185
Habitation___2791    0.615591
Habitation___2793    0.136333
Habitation___2806    0.399887
Name: 0.9, Length: 421, dtype: float64

Récupération des géométries sous forme de DataFrame

Le dataframe contient :

  • les coordonnées des centroids des polygones sous forme de Point (Shapely) et sous forme de coordonnées X et Y,

  • la géométrie des polygones sous forme de Polygons (Shapely).

[16]:
analyze['T2'].get_geometries()
[16]:
Centroid X Y Geometry
Habitation___365 POINT (252578.20644290387 136661.75737353018) 252578.206443 136661.757374 POLYGON ((252582.94600000232 136659.3898000009...
Habitation___410 POINT (251865.23978716985 138603.36743561501) 251865.239787 138603.367436 POLYGON ((251862.51299999654 138603.2758000008...
Habitation___758 POINT (252772.58743948632 136357.6868196059) 252772.587439 136357.686820 POLYGON ((252773.40299999714 136357.2417999990...
Habitation___767 POINT (252784.93215005085 136341.31213371415) 252784.932150 136341.312134 POLYGON ((252790.3650000021 136340.31679999828...
Habitation___883 POINT (252323.63143596248 137277.06658775956) 252323.631436 137277.066588 POLYGON ((252331.30099999905 137284.5667999982...
Habitation___885 POINT (252773.2139256541 136328.34762762696) 252773.213926 136328.347628 POLYGON ((252780.64299999923 136329.3528000004...
Habitation___1199 POINT (252410.0295237607 137201.88507863414) 252410.029524 137201.885079 POLYGON ((252416.6799999997 137202.84980000183...
Habitation___1259 POINT (252780.1457208407 136349.35527273448) 252780.145721 136349.355273 POLYGON ((252787.9680000022 136346.9987999983,...
Habitation___1695 POINT (253080.48830737371 136050.9957918227) 253080.488307 136050.995792 POLYGON ((253078.31769999862 136048.2879000008...
Habitation___1783 POINT (252362.85480023528 137243.4041296981) 252362.854800 137243.404130 POLYGON ((252369.33299999684 137254.7947999984...
Habitation___1873 POINT (252752.37265091634 136269.89060153702) 252752.372651 136269.890602 POLYGON ((252761.24899999797 136275.6917999982...
Habitation___2292 POINT (252764.6561770505 136373.69342816217) 252764.656177 136373.693428 POLYGON ((252773.41200000048 136373.2578000016...
Habitation___2397 POINT (252530.13401562328 137045.56626955583) 252530.134016 137045.566270 POLYGON ((252520.64310000092 137063.7829999998...
Habitation___2523 POINT (252452.3326791363 137168.09434894653) 252452.332679 137168.094349 POLYGON ((252465.28700000048 137171.0007999986...
Habitation___2544 POINT (252778.3285363715 136322.41603772016) 252778.328536 136322.416038 POLYGON ((252785.46400000155 136323.3817999996...
Habitation___2691 POINT (252475.51498097405 137134.79409508978) 252475.514981 137134.794095 POLYGON ((252478.82500000298 137139.1717999987...

Conversion en GeoDataFrame

Cela peut être utile pour traiter les données géographiques avec des bibliothèques comme GeoPandas.

[17]:
import geopandas as gpd

# convert the DataFrame to a GeoDataFrame
gdf50 = gpd.GeoDataFrame(analyze['T50'].get_geometries(), geometry='Geometry')
gdf50.set_crs(epsg=31370, inplace=True)  # set the coordinate reference system
gdf50.plot(column='X', figsize=(10, 10), markersize=5, alpha=0.5)
[17]:
<Axes: >
../_images/tutorials_analyze_polygons_wd_picc_32_1.png

Fusion des géométries avec les valeurs

On peut également fusionner les géométries avec les valeurs pour obtenir un GeoDataFrame contenant à la fois les géométries et les valeurs des polygones.

[18]:
maxima = pd.Series(df50.max(), name='Maximum') # Pour la fusion, il est préférable de créer une série avec un nom
gdf50 = gdf50.merge(maxima, left_index=True, right_index=True)
gdf50.plot(column='Maximum', figsize=(10, 10), markersize=5, alpha=0.5, cmap='viridis')
[18]:
<Axes: >
../_images/tutorials_analyze_polygons_wd_picc_34_1.png

Récupération des géométries et des valeurs

Il est possible de récupérer les géométries et les valeurs des polygones sous forme de GeoDataFrame.

Dans ce cas, les valeurs sont sous la forme d’un vecteyur Numpy dans la colonne ‘Values’, et les géométries sont sous la forme de Polygons (Shapely) dans la colonne ‘Geometry’.

[19]:
gdf50 = analyze['T50'].get_geodataframe_with_values()
[20]:
gdf50.iloc[0]
[20]:
Centroid         POINT (251843.7876969067 139239.45057711063)
X                                               251843.787697
Y                                               139239.450577
Geometry    POLYGON ((251846.17119999975 139244.2434000000...
Values      [0.3013153, 0.27349854, 0.42713928, 0.29135132...
Name: Habitation___3, dtype: object

Exemple pour trouver la valeur maximale du premier polygone :

[21]:
gdf50.iloc[0].Values.max()
[21]:
np.float32(0.55755615)

Réaliser un clustering des bâtiments touchés

On peut réaliser un clustering des polygones en utilisant la méthode clustering() de l’objet analyze. Cette méthode retourne un GeoDataFrame contenant les polygones regroupés par cluster, ainsi que les centroids et les footprints des clusters.

[22]:
gdf_cluster, (centroids, footprints) = analyze['T50'].clustering(n_clusters= 8)

Comme pour la routine ‘get_geodataframe_with_values’, les valeurs sont fournies sous la forme d’un vecteur Numpy dans la colonne ‘Values’, et les géométries sont sous la forme de Polygons (Shapely) dans la colonne ‘Geometry’.

[23]:
gdf_cluster.columns
[23]:
Index(['Centroid', 'X', 'Y', 'Geometry', 'Values', 'Cluster'], dtype='object')

Calcul, pour l’exemple, de la valeur maximale pour chaque polygone :

[24]:
# Iterate over lines and store the maximum value in a new column
for i, row in gdf_cluster.iterrows():
    gdf_cluster.at[i, 'maximum'] = row['Values'].max()

Affichage des polygones et des clusters

[25]:
fig, ax = plt.subplots(figsize=(10, 10))
ax.set_aspect('equal')

arrays['T50'].plot_matplotlib((fig, ax), IGN=True, cat='orthoimage_coverage_2021')
# Plot a white rectangle over the background to make the footprints more visible
bounds = ax.get_xlim(), ax.get_ylim()
ax.add_patch(plt.Rectangle((bounds[0][0], bounds[1][0]), bounds[0][1] - bounds[0][0], bounds[1][1] - bounds[1][0], color='white', alpha=0.5))
# Plot the clusters
for footprint in footprints:
    xy = np.array(footprint.exterior.coords) # Get the coordinates of the polygon exterior
    plt.plot(xy[:,0], xy[:,1], linewidth=3)
# Plot the polygons
gdf_cluster.plot(ax=ax, column='maximum', cmap='viridis', markersize=5, alpha=0.5)

[25]:
<Axes: >
../_images/tutorials_analyze_polygons_wd_picc_47_1.png