You've already forked donnees_meteo
Visualisations étendues (illuminance, calendriers, vent)
This commit is contained in:
213
scripts/plot_calendar_overview.py
Normal file
213
scripts/plot_calendar_overview.py
Normal file
@@ -0,0 +1,213 @@
|
||||
# scripts/plot_calendar_overview.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import calendar
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
from meteo.analysis import compute_daily_rainfall_totals
|
||||
from meteo.plots import plot_calendar_heatmap, plot_weekday_profiles
|
||||
from meteo.variables import VARIABLES_BY_KEY
|
||||
|
||||
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
OUTPUT_DIR = Path("figures/calendar")
|
||||
|
||||
WEEKDAY_VARIABLE_KEYS = ["temperature", "humidity", "wind_speed", "illuminance"]
|
||||
|
||||
|
||||
def _format_calendar_matrix(series: pd.Series, year: int, agg_label: str) -> pd.DataFrame:
|
||||
"""
|
||||
Transforme une série quotidienne en matrice mois x jours (1-31).
|
||||
"""
|
||||
start = pd.Timestamp(year=year, month=1, day=1, tz=series.index.tz)
|
||||
end = pd.Timestamp(year=year, month=12, day=31, tz=series.index.tz)
|
||||
filtered = series.loc[(series.index >= start) & (series.index <= end)]
|
||||
|
||||
matrix = pd.DataFrame(
|
||||
np.nan,
|
||||
index=[calendar.month_name[m][:3] for m in range(1, 13)],
|
||||
columns=list(range(1, 32)),
|
||||
)
|
||||
|
||||
for timestamp, value in filtered.items():
|
||||
month = timestamp.month
|
||||
day = timestamp.day
|
||||
matrix.at[calendar.month_name[month][:3], day] = value
|
||||
|
||||
matrix.index.name = f"{agg_label} ({year})"
|
||||
return matrix
|
||||
|
||||
|
||||
def compute_daily_mean(df: pd.DataFrame, column: str) -> pd.Series:
|
||||
return df[column].resample("1D").mean()
|
||||
|
||||
|
||||
def plot_combined_calendar(
|
||||
matrices: dict[str, pd.DataFrame],
|
||||
output_path: Path,
|
||||
*,
|
||||
title: str,
|
||||
) -> None:
|
||||
if not matrices:
|
||||
return
|
||||
|
||||
n = len(matrices)
|
||||
fig, axes = plt.subplots(n, 1, figsize=(14, 4 * n), sharex=True)
|
||||
if n == 1:
|
||||
axes = [axes]
|
||||
|
||||
for ax, (label, matrix) in zip(axes, matrices.items()):
|
||||
data = matrix.to_numpy(dtype=float)
|
||||
im = ax.imshow(data, aspect="auto", interpolation="nearest", cmap=matrix.attrs.get("cmap", "viridis"))
|
||||
ax.set_xticks(np.arange(matrix.shape[1]))
|
||||
ax.set_xticklabels(matrix.columns, rotation=90)
|
||||
ax.set_yticks(np.arange(matrix.shape[0]))
|
||||
ax.set_yticklabels(matrix.index)
|
||||
ax.set_ylabel(label)
|
||||
cbar = fig.colorbar(im, ax=ax)
|
||||
if matrix.attrs.get("colorbar_label"):
|
||||
cbar.set_label(matrix.attrs["colorbar_label"])
|
||||
|
||||
axes[-1].set_xlabel("Jour du mois")
|
||||
fig.suptitle(title)
|
||||
fig.tight_layout(rect=[0, 0, 1, 0.97])
|
||||
fig.savefig(output_path, dpi=150)
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {CSV_PATH}")
|
||||
return
|
||||
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
if df.empty:
|
||||
print("⚠ Dataset vide.")
|
||||
return
|
||||
|
||||
if not isinstance(df.index, pd.DatetimeIndex):
|
||||
print("⚠ Le dataset doit avoir un index temporel.")
|
||||
return
|
||||
|
||||
print(f"Dataset minuté chargé : {CSV_PATH}")
|
||||
print(f" Lignes : {len(df)}")
|
||||
print(f" Colonnes : {list(df.columns)}")
|
||||
print()
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
latest_year = df.index.year.max()
|
||||
print(f"Année retenue pour le calendrier : {latest_year}")
|
||||
|
||||
daily_totals = compute_daily_rainfall_totals(df=df)
|
||||
daily_rain = daily_totals["daily_total"]
|
||||
rain_matrix = _format_calendar_matrix(daily_rain, latest_year, "Pluie (mm)")
|
||||
rain_matrix.attrs["cmap"] = "Blues"
|
||||
rain_matrix.attrs["colorbar_label"] = "mm"
|
||||
rain_path = OUTPUT_DIR / f"calendar_rain_{latest_year}.png"
|
||||
plot_calendar_heatmap(
|
||||
matrix=rain_matrix,
|
||||
output_path=rain_path,
|
||||
title=f"Pluie quotidienne - {latest_year}",
|
||||
cmap="Blues",
|
||||
colorbar_label="mm",
|
||||
)
|
||||
print(f"✔ Heatmap pluie {latest_year} : {rain_path}")
|
||||
|
||||
daily_temp = compute_daily_mean(df, "temperature")
|
||||
temp_matrix = _format_calendar_matrix(daily_temp, latest_year, "Température (°C)")
|
||||
temp_matrix.attrs["cmap"] = "coolwarm"
|
||||
temp_matrix.attrs["colorbar_label"] = "°C"
|
||||
temp_path = OUTPUT_DIR / f"calendar_temperature_{latest_year}.png"
|
||||
plot_calendar_heatmap(
|
||||
matrix=temp_matrix,
|
||||
output_path=temp_path,
|
||||
title=f"Température moyenne quotidienne - {latest_year}",
|
||||
cmap="coolwarm",
|
||||
colorbar_label="°C",
|
||||
)
|
||||
print(f"✔ Heatmap température {latest_year} : {temp_path}")
|
||||
|
||||
matrices_for_combined = {
|
||||
"Pluie (mm)": rain_matrix,
|
||||
"Température (°C)": temp_matrix,
|
||||
}
|
||||
|
||||
if "pressure" in df.columns:
|
||||
daily_pressure = compute_daily_mean(df, "pressure")
|
||||
pressure_matrix = _format_calendar_matrix(daily_pressure, latest_year, "Pression (hPa)")
|
||||
pressure_matrix.attrs["cmap"] = "Greens"
|
||||
pressure_matrix.attrs["colorbar_label"] = "hPa"
|
||||
pressure_path = OUTPUT_DIR / f"calendar_pressure_{latest_year}.png"
|
||||
plot_calendar_heatmap(
|
||||
matrix=pressure_matrix,
|
||||
output_path=pressure_path,
|
||||
title=f"Pression moyenne quotidienne - {latest_year}",
|
||||
cmap="Greens",
|
||||
colorbar_label="hPa",
|
||||
)
|
||||
print(f"✔ Heatmap pression {latest_year} : {pressure_path}")
|
||||
matrices_for_combined["Pression (hPa)"] = pressure_matrix
|
||||
|
||||
if "illuminance" in df.columns:
|
||||
daily_lux = compute_daily_mean(df, "illuminance")
|
||||
lux_matrix = _format_calendar_matrix(daily_lux, latest_year, "Illuminance (lux)")
|
||||
lux_matrix.attrs["cmap"] = "YlOrBr"
|
||||
lux_matrix.attrs["colorbar_label"] = "lux"
|
||||
lux_path = OUTPUT_DIR / f"calendar_illuminance_{latest_year}.png"
|
||||
plot_calendar_heatmap(
|
||||
matrix=lux_matrix,
|
||||
output_path=lux_path,
|
||||
title=f"Illuminance moyenne quotidienne - {latest_year}",
|
||||
cmap="YlOrBr",
|
||||
colorbar_label="lux",
|
||||
)
|
||||
print(f"✔ Heatmap illuminance {latest_year} : {lux_path}")
|
||||
matrices_for_combined["Illuminance (lux)"] = lux_matrix
|
||||
|
||||
if "wind_speed" in df.columns:
|
||||
daily_wind = compute_daily_mean(df, "wind_speed")
|
||||
wind_matrix = _format_calendar_matrix(daily_wind, latest_year, "Vent (km/h)")
|
||||
wind_matrix.attrs["cmap"] = "Purples"
|
||||
wind_matrix.attrs["colorbar_label"] = "km/h"
|
||||
wind_path = OUTPUT_DIR / f"calendar_wind_{latest_year}.png"
|
||||
plot_calendar_heatmap(
|
||||
matrix=wind_matrix,
|
||||
output_path=wind_path,
|
||||
title=f"Vitesse moyenne du vent - {latest_year}",
|
||||
cmap="Purples",
|
||||
colorbar_label="km/h",
|
||||
)
|
||||
print(f"✔ Heatmap vent {latest_year} : {wind_path}")
|
||||
matrices_for_combined["Vent (km/h)"] = wind_matrix
|
||||
|
||||
combined_path = OUTPUT_DIR / f"calendar_combined_{latest_year}.png"
|
||||
plot_combined_calendar(
|
||||
matrices=matrices_for_combined,
|
||||
output_path=combined_path,
|
||||
title=f"Calendrier combiné {latest_year}",
|
||||
)
|
||||
print(f"✔ Calendrier combiné : {combined_path}")
|
||||
|
||||
hourly = df[WEEKDAY_VARIABLE_KEYS].resample("1h").mean()
|
||||
weekday_stats = hourly.groupby(hourly.index.dayofweek).mean()
|
||||
weekday_path = OUTPUT_DIR / "weekday_profiles.png"
|
||||
variables = [VARIABLES_BY_KEY[key] for key in WEEKDAY_VARIABLE_KEYS]
|
||||
plot_weekday_profiles(
|
||||
weekday_df=weekday_stats,
|
||||
variables=variables,
|
||||
output_path=weekday_path,
|
||||
title="Profils moyens par jour de semaine",
|
||||
)
|
||||
print(f"✔ Profils hebdomadaires : {weekday_path}")
|
||||
|
||||
print("✔ Graphiques calendrier générés.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -12,7 +12,7 @@ from meteo.plots import plot_diurnal_cycle
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
OUTPUT_PATH = Path("figures/diurnal_cycle/diurnal_cycle.png")
|
||||
|
||||
VARIABLE_KEYS = ["temperature", "humidity", "pressure", "wind_speed"]
|
||||
VARIABLE_KEYS = ["temperature", "humidity", "pressure", "wind_speed", "illuminance"]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
64
scripts/plot_illuminance_focus.py
Normal file
64
scripts/plot_illuminance_focus.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# scripts/plot_illuminance_focus.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
from meteo.analysis import compute_seasonal_hourly_profile, compute_monthly_daylight_hours
|
||||
from meteo.plots import plot_seasonal_hourly_profiles, plot_daylight_hours
|
||||
|
||||
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
OUTPUT_DIR = Path("figures/illuminance")
|
||||
DAYLIGHT_THRESHOLD_LUX = 1000.0
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {CSV_PATH}")
|
||||
return
|
||||
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
if "illuminance" not in df.columns:
|
||||
print("⚠ La colonne 'illuminance' est absente du dataset.")
|
||||
return
|
||||
|
||||
print(f"Dataset minuté chargé : {CSV_PATH}")
|
||||
print(f" Lignes : {len(df)}")
|
||||
print(f" Colonnes : {list(df.columns)}")
|
||||
print()
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
seasonal_profile = compute_seasonal_hourly_profile(
|
||||
df=df,
|
||||
value_column="illuminance",
|
||||
season_column="season",
|
||||
)
|
||||
seasonal_path = OUTPUT_DIR / "seasonal_diurnal_illuminance.png"
|
||||
plot_seasonal_hourly_profiles(
|
||||
profile_df=seasonal_profile,
|
||||
output_path=seasonal_path,
|
||||
title="Illuminance moyenne par heure et par saison",
|
||||
ylabel="Illuminance (lux)",
|
||||
)
|
||||
print(f"✔ Profil saisonnier de l'illuminance : {seasonal_path}")
|
||||
|
||||
daylight_hours = compute_monthly_daylight_hours(
|
||||
df=df,
|
||||
illuminance_column="illuminance",
|
||||
threshold_lux=DAYLIGHT_THRESHOLD_LUX,
|
||||
)
|
||||
daylight_path = OUTPUT_DIR / "monthly_daylight_hours.png"
|
||||
plot_daylight_hours(
|
||||
monthly_series=daylight_hours,
|
||||
output_path=daylight_path,
|
||||
title=f"Durée moyenne quotidienne > {DAYLIGHT_THRESHOLD_LUX:.0f} lx",
|
||||
)
|
||||
print(f"✔ Durée de luminosité mensuelle : {daylight_path}")
|
||||
|
||||
print("✔ Graphiques dédiés à l'illuminance générés.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
54
scripts/plot_monthly_patterns.py
Normal file
54
scripts/plot_monthly_patterns.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# scripts/plot_monthly_patterns.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
from meteo.variables import VARIABLES_BY_KEY
|
||||
from meteo.analysis import compute_monthly_climatology, compute_monthly_means
|
||||
from meteo.plots import plot_monthly_boxplots, plot_monthly_anomalies
|
||||
|
||||
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
OUTPUT_DIR = Path("figures/monthly")
|
||||
|
||||
BOXPLOT_KEYS = ["temperature", "humidity", "pressure", "wind_speed", "illuminance"]
|
||||
ANOMALY_KEYS = ["temperature", "humidity", "illuminance"]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {CSV_PATH}")
|
||||
return
|
||||
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
print(f"Dataset minuté chargé : {CSV_PATH}")
|
||||
print(f" Lignes : {len(df)}")
|
||||
print(f" Colonnes : {list(df.columns)}")
|
||||
print()
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
box_vars = [VARIABLES_BY_KEY[key] for key in BOXPLOT_KEYS]
|
||||
boxplot_path = OUTPUT_DIR / "monthly_boxplots.png"
|
||||
plot_monthly_boxplots(df=df, variables=box_vars, output_path=boxplot_path)
|
||||
print(f"✔ Boxplots mensuels : {boxplot_path}")
|
||||
|
||||
anomaly_vars = [VARIABLES_BY_KEY[key] for key in ANOMALY_KEYS]
|
||||
monthly_means = compute_monthly_means(df=df, columns=[v.column for v in anomaly_vars])
|
||||
climatology = compute_monthly_climatology(df=df, columns=[v.column for v in anomaly_vars])
|
||||
|
||||
anomaly_path = OUTPUT_DIR / "monthly_anomalies.png"
|
||||
plot_monthly_anomalies(
|
||||
monthly_means=monthly_means,
|
||||
climatology=climatology,
|
||||
variables=anomaly_vars,
|
||||
output_path=anomaly_path,
|
||||
)
|
||||
print(f"✔ Anomalies mensuelles : {anomaly_path}")
|
||||
|
||||
print("✔ Graphiques mensuels générés.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -13,7 +13,7 @@ from meteo.season import sort_season_labels, SEASON_LABELS
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
OUTPUT_DIR = Path("figures/seasonal")
|
||||
|
||||
BOXPLOT_VARIABLES = ["temperature", "humidity", "pressure", "wind_speed"]
|
||||
BOXPLOT_VARIABLES = ["temperature", "humidity", "pressure", "wind_speed", "illuminance"]
|
||||
|
||||
|
||||
def infer_season_order(df) -> list[str]:
|
||||
|
||||
86
scripts/plot_wind_conditionals.py
Normal file
86
scripts/plot_wind_conditionals.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# scripts/plot_wind_conditionals.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
from meteo.analysis import (
|
||||
compute_wind_rose_distribution,
|
||||
filter_by_condition,
|
||||
compute_mean_wind_components,
|
||||
)
|
||||
from meteo.plots import plot_wind_rose, plot_wind_vector_series
|
||||
|
||||
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
OUTPUT_DIR = Path("figures/wind_conditionals")
|
||||
RAIN_THRESHOLD = 0.2 # mm/h
|
||||
|
||||
|
||||
def _export_wind_rose(df, label: str, filename: str) -> None:
|
||||
if df.empty:
|
||||
print(f"⚠ Pas de données pour {label}.")
|
||||
return
|
||||
|
||||
frequencies, speed_labels, sector_size = compute_wind_rose_distribution(
|
||||
df=df,
|
||||
direction_sector_size=30,
|
||||
speed_bins=(0, 5, 15, 30, 50, float("inf")),
|
||||
)
|
||||
if frequencies.empty:
|
||||
print(f"⚠ Impossible de construire la rose pour {label}.")
|
||||
return
|
||||
|
||||
output_path = OUTPUT_DIR / filename
|
||||
plot_wind_rose(
|
||||
frequencies=frequencies,
|
||||
speed_bin_labels=speed_labels,
|
||||
output_path=output_path,
|
||||
sector_size_deg=sector_size,
|
||||
cmap="plasma",
|
||||
)
|
||||
print(f"✔ Rose des vents ({label}) : {output_path}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {CSV_PATH}")
|
||||
return
|
||||
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
if df.empty:
|
||||
print("⚠ Dataset vide.")
|
||||
return
|
||||
|
||||
print(f"Dataset minuté chargé : {CSV_PATH}")
|
||||
print(f" Lignes : {len(df)}")
|
||||
print(f" Colonnes : {list(df.columns)}")
|
||||
print()
|
||||
|
||||
if "rain_rate" not in df.columns:
|
||||
print("⚠ Colonne 'rain_rate' absente.")
|
||||
return
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
rain_condition = df["rain_rate"].fillna(0.0) >= RAIN_THRESHOLD
|
||||
dry_condition = df["rain_rate"].fillna(0.0) < RAIN_THRESHOLD
|
||||
|
||||
_export_wind_rose(df, "toutes conditions", "wind_rose_all.png")
|
||||
_export_wind_rose(filter_by_condition(df, condition=rain_condition), "pluie", "wind_rose_rain.png")
|
||||
_export_wind_rose(filter_by_condition(df, condition=dry_condition), "temps sec", "wind_rose_dry.png")
|
||||
|
||||
# Vecteurs moyens par mois
|
||||
vector_df = compute_mean_wind_components(df=df, freq="1M")
|
||||
vector_path = OUTPUT_DIR / "wind_vectors_monthly.png"
|
||||
plot_wind_vector_series(
|
||||
vector_df=vector_df,
|
||||
output_path=vector_path,
|
||||
title="Vecteurs moyens du vent (mensuel)",
|
||||
)
|
||||
print(f"✔ Vecteurs de vent mensuels : {vector_path}")
|
||||
print("✔ Graphiques vent/pluie conditionnels générés.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user