Aller au contenu

Import Heat Vulnerability

Heat vulnerability

The script assumes that the vulnerability data is stored in a geopackage file located in the file_data/vulnerability directory. This geopackage has been produced by Maurine Di Tommaso (Service Climat & Résilience – Direction Environnement, Écologie, Énergie).

A description of the approach can be found here : https://geoweb.grandlyon.com/portal/apps/storymaps/collections/7e7862ec92694601a7085074dcaf7481?item=3.

Command

Bases: BaseCommand

Source code in back/iarbre_data/management/commands/import_vulnerability.py
152
153
154
155
156
157
158
159
160
161
162
class Command(BaseCommand):
    help = "Load heat vulnerability data in the DB."

    def handle(self, *args, **options):
        """Load heat vulnerability data in the DB."""
        log_progress("Remove existing data")
        print(Vulnerability.objects.all().delete())
        log_progress("Loading data")
        vulnerability_data = load_data()
        log_progress("Saving data")
        save_geometries(vulnerability_data)

handle(*args, **options)

Load heat vulnerability data in the DB.

Source code in back/iarbre_data/management/commands/import_vulnerability.py
155
156
157
158
159
160
161
162
def handle(self, *args, **options):
    """Load heat vulnerability data in the DB."""
    log_progress("Remove existing data")
    print(Vulnerability.objects.all().delete())
    log_progress("Loading data")
    vulnerability_data = load_data()
    log_progress("Saving data")
    save_geometries(vulnerability_data)

load_data()

Open the geopackage for vulnerabilty.

Returns:

Type Description
GeoDataFrame

geopandas.GeoDataFrame: The loaded geopackage as a GeoDataFrame.

Raises:

Type Description
FileNotFoundError

If no folder with "vulnerability" in the name is found or no .gpkg file is found in the folder.

Source code in back/iarbre_data/management/commands/import_vulnerability.py
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
def load_data() -> geopandas.GeoDataFrame:
    """Open the geopackage for vulnerabilty.

    Returns:
        geopandas.GeoDataFrame: The loaded geopackage as a GeoDataFrame.

    Raises:
        FileNotFoundError: If no folder with "vulnerability" in the name is found or no .gpkg file is found in the folder.
    """
    vulnerability_path = "file_data/vulnerability"
    if not os.path.isdir(vulnerability_path):
        raise FileNotFoundError(
            "No folder for 'vulnerability' found in 'file_data/' directory."
        )
    gpkg_file = None
    for file in os.listdir(vulnerability_path):
        if file.lower().endswith(".gpkg"):
            gpkg_file = file
            break
    if not gpkg_file:
        raise FileNotFoundError(
            f"No geopackage file found in the folder '{vulnerability_path}'."
        )

    gpkg_path = os.path.join(vulnerability_path, gpkg_file)
    gdf = geopandas.read_file(gpkg_path, layer="vulnérabilité_fortes_chaleurs")
    gdf.to_crs(TARGET_PROJ, inplace=True)
    gdf_details = geopandas.read_file(
        gpkg_path, layer="Vulnerabilite_fortes_chaleurs_détail"
    )
    gdf_details.to_crs(TARGET_PROJ, inplace=True)

    merged = gdf.merge(
        gdf_details, on="ID_RSU", suffixes=("", "_details"), validate="one_to_one"
    )
    merged.drop(
        columns=[
            "id",
            "commune",
            "ID_RSU",
            "Surface_RSU",
            "NOTE_EXPO_JOUR",
            "NOTE_EXPO_NUIT",
            "NOTE_SENSI_JOUR",
            "NOTE_SENSI_NUIT",
            "NOTE_CAPAF_JOUR",
            "NOTE_CAPAF_NUIT",
        ],
        inplace=True,
    )
    duplicate_columns = [
        col
        for col in merged.columns
        if col.endswith("_details") and col[:-8] in merged.columns
    ]

    for col in duplicate_columns:
        original_col = col[:-8]
        if not merged[original_col].equals(merged[col]):
            raise ValueError(f"Mismatch found in column '{original_col}' and '{col}'.")

    merged.drop(columns=duplicate_columns, inplace=True)

    def make_valid(geometry):
        """Fix minor topology errors, like Polygon not closed."""
        if geometry and not geometry.is_valid:
            return geometry.buffer(0)
        return geometry

    merged["geometry"] = merged["geometry"].apply(make_valid)
    merged["map_geometry"] = merged.geometry.to_crs(TARGET_MAP_PROJ)
    merged["map_geometry"] = merged["map_geometry"].apply(make_valid)

    merged.fillna(
        0, inplace=True
    )  # Columns ['majic_Log_av1949', 'majic_Log_1949_1989',
    # 'majic_Log_ap1990', 'majic_nlogh', 'majic_stoth', 'majic_slocal',
    #        'majic_nloghmais', 'majic_nloghappt', 'siret_densite_emploi'] contains NaN because
    # these data (economical indices) are missing in water, forest, etc.
    # For all this values 0 means absence.

    return merged

save_geometries(vulnerability_datas)

Save vulnerability data to the database.

Parameters:

Name Type Description Default
vulnerability_datas GeoDataFrame

GeoDataFrame to save to the database.

required

Returns:

Type Description
None

None

Source code in back/iarbre_data/management/commands/import_vulnerability.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
def save_geometries(vulnerability_datas: geopandas.GeoDataFrame) -> None:
    """Save vulnerability data to the database.

    Args:
        vulnerability_datas (GeoDataFrame): GeoDataFrame to save to the database.

    Returns:
        None
    """
    batch_size = 10000
    indices = [
        "geometry",
        "map_geometry",
        "VULNERABILITE_JOUR",
        "VULNERABILITE_NUIT",
        "EXPO_JOUR",
        "EXPO_NUIT",
        "CAPAF_JOUR",
        "CAPAF_NUIT",
        "SENSI_JOUR",
        "SENSI_NUIT",
    ]
    for start in tqdm(range(0, len(vulnerability_datas), batch_size)):
        end = start + batch_size
        batch = vulnerability_datas.loc[start:end]
        Vulnerability.objects.bulk_create(
            [
                Vulnerability(
                    geometry=GEOSGeometry(data["geometry"].wkt),
                    map_geometry=GEOSGeometry(data["map_geometry"].wkt),
                    vulnerability_index_day=data["VULNERABILITE_JOUR"],
                    vulnerability_index_night=data["VULNERABILITE_NUIT"],
                    expo_index_day=data["EXPO_JOUR"],
                    expo_index_night=data["EXPO_NUIT"],
                    capaf_index_day=data["CAPAF_JOUR"],
                    capaf_index_night=data["CAPAF_NUIT"],
                    sensibilty_index_day=data["SENSI_JOUR"],
                    sensibilty_index_night=data["SENSI_NUIT"],
                    details={
                        col: data[col] for col in data.index if col not in indices
                    },
                )
                for _, data in batch.iterrows()
            ]
        )