Herunterskalierte bioklimatische Indikatoren

Dieses Datensatz bietet 76 bioklimatische Indikatoren mit einer Auflösung von 1 × 1 km für Europa, Nordbrasilien und Zentralafrika. Die Indikatoren wurden mithilfe von ERA5 (ERA5-Land)-Reanalysedaten und statistischer Herunterskalierung rekonstruiert. Sie konzentrieren sich auf Biodiversität und Ökosystemdienstleistungen und umfassen Variablen wie Oberflächenenergie, Dürre, Bodenfeuchte, Wind und essenzielle Klimavariablen. Der Datensatz wurde für die Biodiversitätsforschung entwickelt und unterstützt vielfältige Anwendungen durch zeitliche Auflösungen von monatlich bis hin zu mehrjährigen Mittelwerten.

Informationen zum Datensatz:

1. Festlegen der Pfade und Arbeitsverzeichnisse

import os

''' ---- Verzeichnisse hier angeben ---- '''
download_folder = r".\data\sis-biodiversity-era5-regional\download"
working_folder = r".\data\sis-biodiversity-era5-regional\working"
geotiff_folder = r".\data\sis-biodiversity-era5-regional\geotiff"
csv_folder = r".\data\sis-biodiversity-era5-regional\csv"
output_folder = r".\data\sis-biodiversity-era5-regional\output"
''' ----- Ende der Angaben ---- '''

os.makedirs(download_folder, exist_ok=True)
os.makedirs(working_folder, exist_ok=True)
os.makedirs(geotiff_folder, exist_ok=True)
os.makedirs(csv_folder, exist_ok=True)
os.makedirs(output_folder, exist_ok=True)

2. Herunterladen und Entpacken des Datensatzes

2.1 Authentifizierung

import cdsapi

def main():
    # API-Key für die Authentifizierung
    api_key = "fdae60fd-35d4-436f-825c-c63fedab94a4"
    api_url = "https://cds.climate.copernicus.eu/api"

    # Erstellung des CDS-API-Clients
    client = cdsapi.Client(url=api_url, key=api_key)
    return client

2.2 Definieren die „request“ und laden Sie den Datensatz herunter

# Definieren der Begrenzungsrahmen-Koordinaten (WGS84-Format)
# Das Koordinatenformat lautet: [Norden, Westen, Süden, Osten]
bbox_wgs84_deutschland = [56.0, 5.8, 47.2, 15.0]
bbox_wgs84_de_standard = [5.7, 47.1, 15.2, 55.2]
bbox_wgs84_konstanz = [47.9, 8.9, 47.6, 9.3]
bbox_wgs84_konstanz_standard = [9.0, 47.6, 9.3, 47.8]  # [West, South, East, North]

# Alternativ können Sie ein Shapefile für eine präzise geografische Filterung verwenden
import geopandas as gpd
import math

# Beispiel: Shapefile von Konstanz laden (WGS84-Projektion)
de_shapefile = r"./shapefiles/de_boundary.shp"
de_gdf = gpd.read_file(de_shapefile)

# Extrahieren Sie den Begrenzungsrahmen des Shapefiles
de_bounds = de_gdf.total_bounds

# Passen Sie den Begrenzungsrahmen an und puffern Sie ihn, um einen etwas größeren
de_bounds_adjusted = [(math.floor(de_bounds[0]* 10)/10)-0.1,
                      (math.floor(de_bounds[1]* 10)/10)-0.1,
                      (math.ceil(de_bounds[2]* 10)/10)+0.1,
                      (math.ceil(de_bounds[3]* 10)/10)+0.1]

# Ordnen Sie die Koordinaten in das Format: [Nord, West, Süd, Ost] um.
bbox_de_bounds_adjusted = [de_bounds_adjusted[3], de_bounds_adjusted[0],
                           de_bounds_adjusted[1], de_bounds_adjusted[2]]
## Derzeit ist für Region == Europa nur ERA5 verfügbar
# Für Region == Zentralafrika ist ERA5 verfügbar
# Für Region == Nördliches Brasilien ist ERA5-Land verfügbar

## Variablengruppe: Bioklimatische Indikatoren wie in WORLDCLIM
# cds.climate.copernicus.eu/datasets/sis-biodiversity-era5-regional?tab=download
variable_group = "bioclimatic_indicators_as_in_worldclim"
# Definition des Datensatzes und der Request-Parameter
dataset = "sis-biodiversity-era5-regional"
request = {
    "region": ["europe"],
    "origin": "era5",
    "variable": [
        "annual_mean_temperature",
        "mean_diurnal_range",
        "isothermality",
        "temperature_seasonality",
        "maximum_temperature_of_warmest_month",
        "minimum_temperature_of_coldest_month",
        "temperature_annual_range",
        "mean_temperature_of_wettest_quarter",
        "mean_temperature_of_driest_quarter",
        "mean_temperature_of_warmest_quarter",
        "mean_temperature_of_coldest_quarter",
        "annual_precipitation",
        "precipitation_of_wettest_month",
        "precipitation_of_driest_month",
        "precipitation_seasonality",
        "precipitation_of_wettest_quarter",
        "precipitation_of_driest_quarter",
        "precipitation_of_warmest_quarter",
        "precipitation_of_coldest_quarter"
    ],
    "statistic": [
        "mean",
        "median",
        "25th_quartile",
        "75th_quartile"
    ],
    "version": ["1_0"],
    # "area": bbox_de_bounds_adjusted,  # Die Definition des Bereichs mit einem Begrenzungsrahmen verursacht Probleme beim Herunterladen
    # Fehler: "Ihre Anfrage ist zu groß, bitte reduzieren Sie Ihre Auswahl"
}
# Führen Sie es aus, um den Datensatz herunterzuladen:
def main_retrieve():
    dataset_filename = f"{dataset}_{variable_group}.zip"
    dataset_filepath = os.path.join(download_folder, dataset_filename)

    # Den Datensatz nur herunterladen, wenn er noch nicht heruntergeladen wurde
    if not os.path.isfile(dataset_filepath):
        # Rufen Sie den CDS-Client nur auf, wenn der Datensatz noch nicht heruntergeladen wurde.
        client = main()
        # Den Datensatz mit den definierten Anforderungsparametern herunterladen
        client.retrieve(dataset, request, dataset_filepath)
    else:
        print("Datensatz bereits heruntergeladen.")

if __name__ == "__main__":
    main_retrieve()
Datensatz bereits heruntergeladen.

2.3 Extrahieren die ZIP-Datei in Ordner

import zipfile

# Erstelle den Ordnerpfad zum Extrahieren der Zip-Datei(en) basierend auf der Variablengruppe
extract_folder = os.path.join(working_folder, variable_group)
os.makedirs(extract_folder, exist_ok=True)

# Entpacken der ZIP-Datei
try:
    if not os.listdir(extract_folder):
        dataset_filename = f"{dataset}_{variable_group}.zip"
        dataset_filepath = os.path.join(download_folder, dataset_filename)
        
        with zipfile.ZipFile(dataset_filepath, 'r') as zip_ref:
            zip_ref.extractall(extract_folder)
            print(f"Dateien erfolgreich extrahiert nach: {extract_folder}")
    else:
        print("Ordner ist nicht leer. Entpacken überspringen.")
except FileNotFoundError:
    print(f"Fehler: Die Datei {dataset_filepath} wurde nicht gefunden.")
except zipfile.BadZipFile:
    print(f"Fehler: Die Datei {dataset_filepath} ist keine gültige ZIP-Datei.")
except Exception as e:
    print(f"Ein unerwarteter Fehler ist aufgetreten: {e}")
Ordner ist nicht leer. Entpacken überspringen.

3. Untersuchen der Metadaten der NetCDF4-Datei

3.1 Erstellen eines DataFrame mit verfügbaren NetCDF-Dateien

import re
import pandas as pd
import netCDF4 as nc
import numpy as np

def meta(filename):
    # Überprüfen, ob der Dateiname dem erwarteten Muster entspricht
    match = re.search(
        r"(?P<ds_variable>BIO\d{2})_(?P<ds_origin>[\w-]+)-(?P<statistic>mean|median|q25|q75)_v(?P<version>\d+\.\d+)",
        filename
        )

    # Fehler ausgeben, wenn der Dateiname nicht dem erwarteten Schema entspricht
    if not match:
        match = re.search("Der angegebene Dateiname entspricht nicht dem erwarteten Benennungsschema.")
        
    # Funktion zum Extrahieren des Variablennamens aus der NetCDF-Datei
    def get_nc_variable():
        with nc.Dataset(os.path.join(extract_folder, filename), 'r') as nc_dataset:
            variable_names = list(nc_dataset.variables.keys())

            primary_variable_index = 3  # Adjust this index as needed
            if primary_variable_index >= len(variable_names):
                raise IndexError("Der Index der primären Variablen liegt außerhalb des Bereichs für die NetCDF-Variablen.")
            
            primary_variable = variable_names[primary_variable_index]
            primary_variable_shape = np.shape(nc_dataset[primary_variable])

            return primary_variable, primary_variable_shape
    
    # Metadaten als Dictionary zurückgeben
    return dict(
        filename=filename,
        path=os.path.join(extract_folder, filename),
        ds_variable=match.group('ds_variable'),
        ds_origin=match.group('ds_origin'),
        variable_name=get_nc_variable()[0],
        variable_shape=get_nc_variable()[1],
        statistic=match.group('statistic')
    )

# Metadaten für alle NetCDF-Dateien im Ordner extrahieren
# Das Dictionary 'nc_files' enthält alle relevanten Metadaten der verfügbaren NetCDF4-Dateien
# Dieses Dictionary wird später verwendet, um die Dateien in GeoTiff zu konvertieren
nc_files = [meta(f) for f in os.listdir(extract_folder) if f.endswith('.nc')]
df_nc_files = pd.DataFrame.from_dict(nc_files)

# Pandas-Anzeigeoptionen anpassen
pd.options.display.max_colwidth = 30

# DataFrame anzeigen, ohne die Spalte 'path' darzustellen
df_nc_files.head(10).loc[:, df_nc_files.columns != 'path']
filename ds_variable ds_origin variable_name variable_shape statistic
0 BIO01_era5-to-1km_1979-201... BIO01 era5-to-1km_1979-2018 BIO01 (1, 4800, 9600) mean
1 BIO01_era5-to-1km_1979-201... BIO01 era5-to-1km_1979-2018 BIO01 (1, 4800, 9600) median
2 BIO01_era5-to-1km_1979-201... BIO01 era5-to-1km_1979-2018 BIO01 (1, 4800, 9600) q25
3 BIO01_era5-to-1km_1979-201... BIO01 era5-to-1km_1979-2018 BIO01 (1, 4800, 9600) q75
4 BIO02_era5-to-1km_1979-201... BIO02 era5-to-1km_1979-2018 BIO02 (1, 4800, 9600) mean
5 BIO02_era5-to-1km_1979-201... BIO02 era5-to-1km_1979-2018 BIO02 (1, 4800, 9600) median
6 BIO02_era5-to-1km_1979-201... BIO02 era5-to-1km_1979-2018 BIO02 (1, 4800, 9600) q25
7 BIO02_era5-to-1km_1979-201... BIO02 era5-to-1km_1979-2018 BIO02 (1, 4800, 9600) q75
8 BIO03_era5-to-1km_1979-201... BIO03 era5-to-1km_1979-2018 BIO03 (1, 4800, 9600) mean
9 BIO03_era5-to-1km_1979-201... BIO03 era5-to-1km_1979-2018 BIO03 (1, 4800, 9600) median

3.2 Einzigartige Variablennamen und verfügbare Variablen ausgeben

# Variable definieren, um bereits verarbeitete Variablennamen zu speichern und Duplikate zu vermeiden  
seen_variables = set()

# Alle Variablen in jeder NetCDF-Datei auflisten  
for i, nc_file in enumerate(nc_files):
    variable_name = nc_file['variable_name']
    
    # Überspringen, wenn die Variable bereits verarbeitet wurde  
    if variable_name in seen_variables:
        continue

    # NetCDF-Datei im Lesemodus öffnen  
    with nc.Dataset(nc_file['path'], mode='r') as nc_dataset:  
        # Alle Variablen im aktuellen Datensatz auflisten  
        variables_list = list(nc_dataset.variables.keys())  
        
        # Details der Datei und ihrer Variablen ausgeben  
        print(f"{i + 1:<2} {variable_name:<18}: Verfügbare Variablen: {variables_list}") 
    
    # Diese Variable als verarbeitet markieren  
    seen_variables.add(variable_name)
1  BIO01             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO01']
5  BIO02             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO02']
9  BIO03             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO03']
13 BIO04             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO04']
17 BIO05             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO05']
21 BIO06             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO06']
25 BIO07             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO07']
29 BIO08             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO08']
33 BIO09             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO09']
37 BIO10             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO10']
41 BIO11             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO11']
45 BIO12             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO12']
49 BIO13             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO13']
53 BIO14             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO14']
57 BIO15             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO15']
61 BIO16             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO16']
65 BIO17             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO17']
69 BIO18             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO18']
73 BIO19             : Verfügbare Variablen: ['latitude', 'longitude', 'time', 'BIO19']
# Alle Variableninformationen in jeder NetCDF-Datei auflisten  
seen_variables = set()

# Alle variablen Informationen in jeder NetCDF-Datei auflisten
for i, nc_file in enumerate(nc_files):
    variable_name = nc_file['variable_name']
    
    # Überspringen, wenn die Variable bereits verarbeitet wurde
    if variable_name in seen_variables:
        continue
    
    # NetCDF-Datei im Lesemodus öffnen
    with nc.Dataset(nc_file['path'], mode='r') as nc_dataset:  
        # Primärvariable-Daten abrufen  
        variable_data = nc_dataset[variable_name]  

        # Zusammenfassung der Primärvariable erstellen  
        summary = {  
            "Variablenname": variable_name,  
            "Datentyp": variable_data.dtype,  
            "Form": variable_data.shape,  
            "Variableninfo": f"{variable_data.dimensions}",  
            "Einheiten": getattr(variable_data, "units", "N/A"),  
            "Langer Name": getattr(variable_data, "long_name", "N/A"),  
        }  

        # Datensatz-Zusammenfassung als DataFrame zur besseren Visualisierung anzeigen  
        nc_summary = pd.DataFrame(list(summary.items()), columns=['Beschreibung', 'Bemerkungen'])  
        print(f"{i + 1}. Zusammenfassung der Variable '{variable_name}':")  
        display(nc_summary)  

    # Variablenname zur Liste der bereits verarbeiteten Variablen hinzufügen  
    seen_variables.add(variable_name)  

    # Ausgabe begrenzen  
    output_limit = 2  
    if len(seen_variables) >= output_limit:  
        print(f".... (Ausgabe auf die ersten {output_limit} Variablen gekürzt)")  
        break  
1. Zusammenfassung der Variable 'BIO01':
Beschreibung Bemerkungen
0 Variablenname BIO01
1 Datentyp float32
2 Form (1, 4800, 9600)
3 Variableninfo ('time', 'latitude', 'long...
4 Einheiten K
5 Langer Name Temperature annual mean
5. Zusammenfassung der Variable 'BIO02':
Beschreibung Bemerkungen
0 Variablenname BIO02
1 Datentyp float32
2 Form (1, 4800, 9600)
3 Variableninfo ('time', 'latitude', 'long...
4 Einheiten K
5 Langer Name Mean diurnal range (mean o...
.... (Ausgabe auf die ersten 2 Variablen gekürzt)

4. Exportieren der NetCDF4-Dateien im CSV-Format

⚠️ Wichtig: Nach dem Herunterladen der Datensätze definiere die interessierende Variable im folgenden Code. Wenn du beispielsweise an der jährlichen Durchschnittstemperatur interessiert bist, wähle die Variable BIO01, die der Jährlichen Durchschnittstemperatur (BIO01) entspricht.

# Ändere hier die ausgewählte Variable
selected_variable = "BIO01"

# Filtere die NetCDF-Dateien basierend auf der ausgewählten Variable
nc_files_subset = [nc_file for nc_file in nc_files if nc_file['ds_variable'] == selected_variable]

4.1 Define a function to convert NetCDF data to a pandas DataFrame

import xarray as xr

# Funktion zur Konvertierung von NetCDF-Daten in ein Pandas DataFrame
def netcdf_to_dataframe(
    nc_file,
    bounding_box=None
    ):

    # Öffne das NetCDF-Dataset im Lesemodus
    with xr.open_dataset(nc_file['path']) as nc_dataset:
        # Zugriff auf die Variablendaten aus dem Datensatz
        variable_data = nc_dataset[nc_file['variable_name']]
        
        # Sicherstellen, dass die Namen für Breiten- und Längengrad korrekt sind
        latitude_name = 'latitude' if 'latitude' in nc_dataset.coords else 'lat'
        longitude_name = 'longitude' if 'longitude' in nc_dataset.coords else 'lon'
        
        # Falls eine Begrenzungsbox angegeben ist, die Daten filtern
        if bounding_box:
            filtered_data = variable_data.where(
                (nc_dataset[latitude_name] >= bounding_box[1]) & (nc_dataset[latitude_name] <= bounding_box[3]) &
                (nc_dataset[longitude_name] >= bounding_box[0]) & (nc_dataset[longitude_name] <= bounding_box[2]),
                drop=True
            )
        else:
            filtered_data = variable_data

        # Umwandlung des xarray-Datensatzes in ein Pandas DataFrame
        df = filtered_data.to_dataframe().reset_index().set_index(['time', latitude_name, longitude_name])
        
        # Benenne die Wertspalte um, sodass der Dateiname als Spaltenname verwendet wird (optional)
        df.rename(columns={nc_file['variable_name']: nc_file['filename']}, inplace=True)
        
        return df

4.2 Filtern nach Boundary Box, DataFrame erstellen und als CSV-Datei exportieren

Hinweis: bbox_wgs84_de_standard wird verwendet, um Daten für Deutschland zu filtern.

from tqdm.notebook import tqdm
import textwrap

# Erstelle einen Ordner für die Teilmengen-CSV-Dateien basierend auf der Variablengruppe
subset_csv_folder = os.path.join(csv_folder, variable_group)
os.makedirs(subset_csv_folder, exist_ok=True)

# Definiere den CSV-Dateinamen und Pfad für die Ausgabe
subset_csv_filename = f"{selected_variable}.csv.zip"
subset_csv_filepath = os.path.join(subset_csv_folder, subset_csv_filename)

# Erstelle ein DataFrame und eine CSV-Datei, falls sie noch nicht existiert
if not os.path.isfile(subset_csv_filepath):
    # Verarbeite NetCDF-Dateien in DataFrames und füge sie zusammen
    dataframes = [netcdf_to_dataframe(nc_file=nc_file, bounding_box=bbox_wgs84_de_standard) for nc_file in tqdm(selected_nc_files)]
    df_merged = pd.concat(dataframes, axis=1)

    # Exportiere das zusammengefügte DataFrame als komprimierte CSV-Datei
    df_merged.to_csv(subset_csv_filepath, sep=',', encoding='utf8', compression='zip')
else:
    print(f"Datei existiert bereits unter {subset_csv_filepath}. Überspringen den Export.")
    print("Lesen bestehende CSV-Datei ein...")
    df_merged = pd.read_csv(subset_csv_filepath).set_index(['time', 'latitude', 'longitude'])

# Funktion zum Umbruch der Spaltennamen für bessere Lesbarkeit
def wrap_column_names(df, width):
    wrapped_columns = {col: " ".join(textwrap.wrap(col, width)) for col in df.columns}
    return df.rename(columns=wrapped_columns)
    
# Ändere die Pandas-Anzeigeoptionen
pd.options.display.float_format = '{:,.2f}'.format
    
# Zeige das DataFrame an
df_wrapped = wrap_column_names(df_merged, width=12)
df_wrapped
Datei existiert bereits unter .\data\sis-biodiversity-era5-regional\csv\bioclimatic_indicators_as_in_worldclim\BIO01.csv.zip. Überspringen den Export.
Lesen bestehende CSV-Datei ein...
BIO01_era5- to-1km_1979- 2018- mean_v1.0.nc BIO01_era5- to-1km_1979- 2018- median_v1.0. nc BIO01_era5- to-1km_1979- 2018- q25_v1.0.nc BIO01_era5- to-1km_1979- 2018- q75_v1.0.nc
time latitude longitude
1999-01-01 47.10 5.70 284.57 284.59 284.02 285.10
5.71 284.57 284.59 284.02 285.10
5.72 284.55 284.57 284.00 285.08
5.73 284.54 284.57 283.99 285.07
5.74 284.51 284.54 283.97 285.05
... ... ... ... ... ...
55.20 15.16 281.95 282.07 281.51 282.72
15.17 281.94 282.07 281.51 282.71
15.18 281.93 282.06 281.50 282.70
15.19 281.93 282.05 281.49 282.70
15.20 281.92 282.05 281.49 282.69

1108080 rows × 4 columns

5. Exportieren der NetCDF4-Datei nach GeoTIFF

5.1 Definieren eine Funktion zum Exportieren der NetCDF4-Datei als GeoTIFF-Datei(en)

import numpy as np
from rasterio.transform import from_origin
import rasterio

from tqdm.notebook import tqdm

def main_export_geotiff(
    nc_file,
    bounding_box=None,
    output_directory=None):
    
    """
    Parameters:
        nc_file (dict): Ein Wörterbuch mit den Schlüsseln 'path' (Dateipfad), 'variable', 'rcp' und 'statistic'.
        bounding_box (list): [lon_min, lat_min, lon_max, lat_max] (optional).
        output_directory (str): Verzeichnis zum Speichern der Ausgabe-GeoTIFF-Dateien (optional).
    """
    
    # Öffnet die NetCDF-Datei
    with nc.Dataset(nc_file['path'], 'r') as nc_dataset:
        nc_dataset = nc.Dataset(nc_file['path'], 'r')
        
        lon = nc_dataset['longitude'][:]
        lat = nc_dataset['latitude'][:]
        
        # Falls eine Begrenzungsbox angegeben wurde, filtere die Daten entsprechend
        if bounding_box:
            lon_min, lat_min, lon_max, lat_max = bounding_box
            
            indices_lat = np.where((lat >= lat_min) & (lat <= lat_max))[0]
            indices_lon = np.where((lon >= lon_min) & (lon <= lon_max))[0]
            start_lat, end_lat = indices_lat[0], indices_lat[-1] + 1
            start_lon, end_lon = indices_lon[0], indices_lon[-1] + 1
        else:
            start_lat, end_lat = 0, len(lat)
            start_lon, end_lon = 0, len(lon)
        
        lat = lat[start_lat:end_lat]
        lon = lon[start_lon:end_lon]

        # Berechnet die räumliche Auflösung und die Rastertransformation
        dx = abs(lon[1] - lon[0])
        dy = abs(lat[1] - lat[0])
        transform = from_origin(lon.min() - dx / 2, lat.min() - dy / 2, dx, -dy)
            
        # Extrahiere Variablen-Daten
        variable_data = nc_dataset.variables[nc_file['variable_name']]
        variable_data_subset = variable_data[:]

        output_filename = f"{nc_file['variable_name']}-{nc_file['statistic']}.tif"
        
        # Export als GeoTIFF-Dateien
        if output_directory:
            subset_directory_path = output_directory
        else:
            subset_directory_path = os.path.join(geotiff_folder, f"{selected_variable}")
            os.makedirs(subset_directory_path, exist_ok=True)
        
        for year_index in tqdm(range(variable_data_subset.shape[0]),
                            desc="Exportieren GeoTIFF-Dateien"):
            
            # Definiere den Ausgabe-Dateipfad
            output_filepath = os.path.join(subset_directory_path, output_filename)

            # Exportiere den aktuellen Zeitschritt als GeoTIFF
            with rasterio.open(
                output_filepath,
                "w",
                driver="GTiff",
                dtype=str(variable_data_subset.dtype),
                width=variable_data_subset.shape[2],
                height=variable_data_subset.shape[1],
                count=1,
                crs="EPSG:4326",
                nodata=-9999,
                transform=transform,
            ) as dst:
                time_slice_data = variable_data_subset[year_index, :, :]
                dst.write(time_slice_data , 1)

5.2 Ausgewählte NetCDF4-Datei(en) in GeoTIFF-Datei(en) exportieren

if __name__ == "__main__":
    # Exportieren Sie alle NetCDF-Dateien als GeoTIFF-Dateien.
    for nc_file in nc_files_subset:
        main_export_geotiff(
            nc_file=nc_file,
            bounding_box=None,
        )

6. Analyse und Visualisierung Optionen

6.1 Definieren eine Funktion zur Erstellung einer Heatmap

import matplotlib.pyplot as plt
import cartopy.feature as cfeature
import cartopy.crs as ccrs
import numpy as np

def main_plt_plot(
        nc_file=nc_file,
        bounding_box=None):
    
    # Öffnet die NetCDF-Datei
    nc_dataset = nc.Dataset(nc_file['path'], mode='r')
    latitudes = nc_dataset.variables['latitude'][:]
    longitudes = nc_dataset.variables['longitude'][:]

    # Falls eine Begrenzungsbox angegeben wurde, filtere die Daten entsprechend
    if bounding_box:
        lat_indices = np.where((latitudes >= bounding_box[1]) & (latitudes <= bounding_box[3]))[0]
        lon_indices = np.where((longitudes >= bounding_box[0]) & (longitudes <= bounding_box[2]))[0]

        lat_subset = latitudes[lat_indices]
        lon_subset = longitudes[lon_indices]
    else:
        lat_indices = slice(None)
        lon_indices = slice(None)

        lat_subset = latitudes
        lon_subset = longitudes

    # Extrahiere Variablen-Daten
    variable_name = nc_file['variable_name']
    variable_data = nc_dataset.variables[variable_name][..., lat_indices, lon_indices]
    var_units = getattr(nc_dataset.variables[variable_name], "units", "N/A")
    var_longname = getattr(nc_dataset.variables[variable_name], "long_name", "N/A")

    # NaN-Werte für Perzentilberechnungen entfernen
    band_data_nonan = variable_data[~np.isnan(variable_data)]
    vmin = np.nanpercentile(band_data_nonan, 1)
    vmax = np.nanpercentile(band_data_nonan, 99)

    def dynamic_round(value):
        # Bestimmen Sie die Größe des Wertes.
        order_of_magnitude = np.floor(np.log10(abs(value)))
        
        # Verwenden Sie diese Größe, um die Genauigkeit dynamisch zu wählen.
        if order_of_magnitude < -2:  # Werte kleiner als 0,01
            return round(value, 3)
        elif order_of_magnitude < -1:  # Werte zwischen 0,01 und 1
            return round(value, 2)
        elif order_of_magnitude < 0:  # Werte zwischen 1 und 10
            return round(value, 1)
        else:  # Werte 10 oder größer
            return round(value)
    
    # Dynamische Rundung auf vmin und vmax anwenden
    vmin = dynamic_round(vmin)
    vmax = dynamic_round(vmax)

    bins = 10
    interval = (vmax - vmin) / bins

    # Erstellen Sie ein 2D-Netzgitter für die grafische Darstellung.
    lon_grid, lat_grid = np.meshgrid(lon_subset, lat_subset)

    # Create the plot
    fig, ax = plt.subplots(
        figsize=(12, 8),
        facecolor='#f1f1f1',
        edgecolor='k',
        subplot_kw={'projection': ccrs.PlateCarree()}
    )

    # Kartenmerkmale hinzufügen
    ax.coastlines(edgecolor='black', linewidth=0.5)
    ax.add_feature(cfeature.BORDERS, edgecolor='black', linewidth=0.5)

    # Erstellen Sie ein Farbnetzdiagramm mit der angegebenen Farbkarte und den Grenzen.
    cmap = plt.get_cmap("viridis", bins)
    pcm = ax.pcolormesh(
        lon_grid, lat_grid, variable_data[0, :, :],
        transform=ccrs.PlateCarree(),
        cmap=cmap,
        shading='auto',
        vmin=vmin,
        vmax=vmax
    )

    # Passe die Kartenausdehnung an die Daten an
    ax.set_extent([lon_subset.min(), lon_subset.max(), lat_subset.min(), lat_subset.max()], crs=ccrs.PlateCarree())

    # Einen Farbbalken hinzufügen
    ticks = np.linspace(vmin, vmax, num=bins + 1)
    cbar = plt.colorbar(pcm, ax=ax, orientation='vertical', pad=0.02, ticks=ticks)
    cbar.set_label(f"{var_longname}, ({variable_name}), {var_units}", fontsize=12)
    cbar.ax.tick_params(labelsize=12)
    
    # Gitterlinien hinzufügen
    gl = ax.gridlines(draw_labels=True,
                      crs=ccrs.PlateCarree(),
                      linewidth=0.8,
                      color='gray',
                      alpha=0.7,
                      linestyle='--')
    gl.top_labels = False 
    gl.right_labels = False
    gl.xlabel_style = {'size': 10, 'color': 'black'}
    gl.ylabel_style = {'size': 10, 'color': 'black'}
    
    # Add title and labels
    fig.text(0.5, 0.0, 'Longitude', ha='center', fontsize=14)
    fig.text(0.04, 0.5, 'Latitude', va='center', rotation='vertical', fontsize=14)
    ax.set_aspect("equal")

    # Titel und Beschriftungen hinzufügen
    ax.set_title(f"{var_longname} ({variable_name})", fontsize=14)

    # Layout anpassen und das Diagramm anzeigen
    plt.tight_layout()
    plt.show()
if __name__ == "__main__":
    # Beispiel für einen Anwendungsfall
    main_plt_plot(nc_file=nc_files_subset[0],
                  bounding_box=bbox_wgs84_de_standard
    )
F:\ProgramFiles\condaEnvs\cds_env\lib\site-packages\numpy\lib\_function_base_impl.py:4842: UserWarning: Warning: 'partition' will ignore the 'mask' of the MaskedArray.
  arr.partition(
../../_images/c02e9641677ef72895f67a698d1d3f92bb15941bd934f763125ec494b59c60df.png