#!/usr/bin/env python # coding: utf-8 # # Analyse der heissesten und kältesten Messstationen # Dieses Notebook kann lokal oder **direkt im Browser** auf [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/meteotest/urban-heat-API-docs/data-analysis?labpath=python_data_analysis_hottest_coldest_locations.ipynb) oder [![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/meteotest/urban-heat-API-docs/blob/data-analysis/python_data_analysis_hottest_coldest_locations.ipynb) ausgeführt werden. # In[120]: import requests import pandas as pd import geopandas as gpd import matplotlib.pyplot as plt # for plotting import folium import branca import math # ## Berechnungen heisseste und kälteste Messstation # In[ ]: # Auswahl an Zeitraum (z.B. eine Hitzewelle, ein Monat, oder der ganze Sommer) # Daten (UTC) als String in folgendem Format: "YYYY-MM-DDThh:mm:ssZ" time_from = "2024-10-01T00:00:00Z" time_to = "2024-10-11T23:59:59Z" # Auswahl an Stationen # Wenn alle Stationen berücksichtigt werden sollen, dann einfach die Liste leer lassen # Hier ist eine Liste aller Stationen mit Name und ID: https://smart-urban-heat-map.ch/api/v2/latest # station_ids = ["11001", "11002"] # Beispiel für nur eine Auswahl von zwei Stationen station_ids = [] # Beispiel für alle Stationen # In[ ]: def get_stations() -> gpd.GeoDataFrame: response = requests.get( url=f"https://smart-urban-heat-map.ch/api/v2/latest" ) stations = gpd.read_file(response.text) return stations def get_station_analysis_mean_temp(time_from: str, time_to: str, station_ids: [str]) -> pd.DataFrame: stations = get_stations() if station_ids: stations = stations[stations["stationId"].isin(station_ids)] time_from_dt = pd.to_datetime(time_from) time_to_dt = pd.to_datetime(time_to) time_difference = time_to_dt - time_from_dt min_expected_values = round(time_difference.days * 24 * 2) # minimum two values per hour stations["mean_temperature"] = None stations["max_temperature"] = None stations["date_of_max_temperature"] = None stations["min_temperature"] = None stations["date_of_min_temperature"] = None for idx, station in stations.iterrows(): station_id = station.stationId response = requests.get(url=f"https://smart-urban-heat-map.ch/api/v2/timeseries?stationId={station_id}&timeFrom={time_from}&timeTo={time_to}") payload = response.json() if payload["values"] is None or not len(payload["values"]): stations = stations.drop(idx) continue if len(payload["values"]) < min_expected_values: stations = stations.drop(idx) continue df = pd.DataFrame(payload["values"]) df["dateObserved"] = pd.to_datetime(df["dateObserved"]) df["dateObserved"] = df["dateObserved"].dt.tz_convert("Europe/Zurich") # hier wird der mittelwert berechnet mean_temperature = mean_temperatures(df) # hier werden die min und max temperaturen berechnet # und das jeweilige datum herausgeschrieben min_temperature = min_temperatures(df)[0] date_of_min_temperature = min_temperatures(df)[1] max_temperature = max_temperatures(df)[0] date_of_max_temperature = max_temperatures(df)[1] # hier wird der mittelwert dem 'stations' dataframe hinzugefügt stations.at[idx, "mean_temperature"] = mean_temperature # hier werden der min und max temperatur sowie deren messdatum dem 'stations' dataframe hinzugefügt stations.at[idx, "min_temperature"] = min_temperature stations.at[idx, "date_of_min_temperature"] = date_of_min_temperature stations.at[idx, "max_temperature"] = max_temperature stations.at[idx, "date_of_max_temperature"] = date_of_max_temperature return stations def mean_temperatures(df: pd.DataFrame) -> float: mean_temp = df.mean()["temperature"] return mean_temp def min_temperatures(df: pd.DataFrame) -> tuple[float,str]: min_temp = df.min()["temperature"] dateof_min_temp = df.loc[df['temperature'].idxmin()]['dateObserved'] return min_temp, dateof_min_temp def max_temperatures(df: pd.DataFrame) -> tuple[float,str]: max_temp = df.max()["temperature"] dateof_max_temp = df.loc[df['temperature'].idxmax()]['dateObserved'] return max_temp, dateof_max_temp # In[123]: # Analyse der Temperatur laufen lassen # Dies kann einige Sekunden / Minuten dauern, je nach ausgewähltem Zeitintervall station_analysis = get_station_analysis_mean_temp(time_from, time_to, station_ids) # In[132]: # anzeigen aller stationen station_analysis # **Note**: Die Zeitstempel sind bereits von UTC zu UTC+2 (Central European Summer Time) konvertiert. Dies ist durch den Suffix "+02:00" nach dem Zeitwert angegeben.
#
# Beispiel:
# Der Zeitstempel *2024-08-02 17:57:10+02:00* bedeutet 17:57:10 in CEST (Schweizer Sommerzeit) und 15:57:10 in UTC time. # ### Wärmste *n* Standorte herauslesen # Definition: Standort mit höchster **mittlerer Temperatur** über den oben definierten Zeitraum. # Hier muss für *n_warmest* eine Zahl eingegeben werden. # In[124]: # n wärmste Stationen auswählen n_warmest = 3 # z.B. Wert 3 eingeben, um die wärmsten 3 Stationen anzuzeigen # In[125]: # Sortieren um die heissesten Stationen anzuzeigen df_warm = station_analysis.sort_values(by='mean_temperature', ascending=False)[:n_warmest] df_warm # ### Kühlste *n* Standorte # Definition: Standort mit tiefster **mittlerer Temperatur** über den oben definierten Zeitraum. # Hier muss für *c_coldest* eine Zahl eingegeben werden. # In[126]: # n kälteste Stationen auswählen n_coldest = 3 # z.B. Wert 3 eingeben, um die kältesten 3 Stationen anzuzeigen # In[127]: # Sortieren um die kältesten Stationen anzuzeigen df_cold = station_analysis.sort_values(by='mean_temperature', ascending=True)[:n_coldest] df_cold # ## Karte der mittleren Temperaturen pro Messstation # In[133]: # mean_temperature Map m = folium.Map(location=[station_analysis.geometry.y.mean(), station_analysis.geometry.x.mean()], zoom_start=13, tiles="CartoDB positron") # Add a fixed title to the map title_html = f'''
Mittlere Temperatur
vom {pd.to_datetime(time_from).strftime('%d.%m.%Y')} bis {pd.to_datetime(time_to).strftime('%d.%m.%Y')}
''' m.get_root().html.add_child(folium.Element(title_html)) colormap = branca.colormap.linear.YlOrRd_09 mean_temperature = station_analysis.mean_temperature.values # Define colourmap range depending on values of 'mean_temperature vmin = math.floor(mean_temperature.min()) vmax = math.ceil(mean_temperature.max()) # Define the colormap with the specified range colormap = branca.colormap.linear.YlOrRd_09.scale(vmin, vmax) # Convert to step colormap with a specified number of steps n_steps = int((vmax - vmin) / 0.5) # Define the number of steps colormap = colormap.to_step(n_steps) # colormap = colormap.scale(0, mean_temperature).to_step(mean_temperature) colormap.caption = "Mittlere Temperatur" colormap.add_to(m) # plot each station temperature for idx, station in station_analysis.iterrows(): color = colormap(station.mean_temperature) # text with temperature value folium.Marker( location=(station.geometry.y, station.geometry.x), icon=folium.DivIcon( html=f'
{station.mean_temperature:.1f}°C
' ), tooltip=f"{station['name']}: Mittlere Temperatur {station.mean_temperature:.1f} °C", ).add_to(m) # show map m