1
donnees_meteo/meteo/plots/seasonal_profiles.py
2025-11-18 09:01:34 +01:00

152 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Profils horaires/saisonniers liés à l'irradiance et aux cycles diurnes."""
from __future__ import annotations
from pathlib import Path
from typing import Sequence
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from .base import export_plot_dataset
from meteo.analysis import DiurnalCycleStats
from meteo.variables import Variable
__all__ = ['plot_diurnal_cycle', 'plot_seasonal_hourly_profiles', 'plot_daylight_hours']
def plot_diurnal_cycle(
stats: DiurnalCycleStats,
variables: Sequence[Variable],
output_path: str | Path,
) -> Path:
"""
Trace les cycles diurnes moyens (moyenne/médiane + quantiles).
"""
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
export_plot_dataset(
{
"mean": stats.mean,
"median": stats.median,
"quantile_low": stats.quantile_low,
"quantile_high": stats.quantile_high,
},
output_path,
)
hours = stats.mean.index.to_numpy(dtype=float)
n_vars = len(variables)
fig, axes = plt.subplots(n_vars, 1, figsize=(10, 3 * n_vars), sharex=True)
if n_vars == 1:
axes = [axes]
for ax, var in zip(axes, variables):
col = var.column
ax.plot(hours, stats.mean[col], label="Moyenne", color="tab:blue")
ax.plot(hours, stats.median[col], label="Médiane", color="tab:orange", linestyle="--")
if stats.quantile_low is not None and stats.quantile_high is not None:
ax.fill_between(
hours,
stats.quantile_low[col],
stats.quantile_high[col],
color="tab:blue",
alpha=0.15,
label=(
f"Quantiles {int(stats.quantile_low_level * 100)}{int(stats.quantile_high_level * 100)}%"
if stats.quantile_low_level is not None and stats.quantile_high_level is not None
else "Quantiles"
),
)
ylabel = f"{var.label} ({var.unit})" if var.unit else var.label
ax.set_ylabel(ylabel)
ax.grid(True, linestyle=":", alpha=0.5)
axes[-1].set_xlabel("Heure locale")
axes[0].legend(loc="upper right")
axes[-1].set_xticks(range(0, 24, 2))
axes[-1].set_xlim(0, 23)
fig.suptitle("Cycle diurne moyen")
fig.tight_layout(rect=[0, 0, 1, 0.97])
fig.savefig(output_path, dpi=150)
plt.close(fig)
return output_path.resolve()
def plot_seasonal_hourly_profiles(
profile_df: pd.DataFrame,
output_path: str | Path,
*,
title: str,
ylabel: str,
) -> Path:
"""
Courbes moyennes par heure pour chaque saison.
"""
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
if profile_df.empty or profile_df.isna().all().all():
fig, ax = plt.subplots()
ax.text(0.5, 0.5, "Pas de profil saisonnier disponible.", ha="center", va="center")
ax.set_axis_off()
fig.savefig(output_path, dpi=150, bbox_inches="tight")
plt.close(fig)
return output_path.resolve()
export_plot_dataset(profile_df, output_path)
hours = profile_df.index.to_numpy(dtype=float)
fig, ax = plt.subplots(figsize=(10, 4))
colors = plt.get_cmap("turbo")(np.linspace(0.1, 0.9, profile_df.shape[1]))
for color, season in zip(colors, profile_df.columns):
ax.plot(hours, profile_df[season], label=season.capitalize(), color=color)
ax.set_xlabel("Heure locale")
ax.set_ylabel(ylabel)
ax.set_title(title)
ax.grid(True, linestyle=":", alpha=0.5)
ax.legend()
fig.tight_layout()
fig.savefig(output_path, dpi=150)
plt.close(fig)
return output_path.resolve()
def plot_daylight_hours(
monthly_series: pd.Series,
output_path: str | Path,
*,
title: str = "Durée moyenne de luminosité (> seuil)",
) -> Path:
"""
Représente la durée moyenne quotidienne de luminosité par mois.
"""
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
if monthly_series.empty:
fig, ax = plt.subplots()
ax.text(0.5, 0.5, "Pas de données sur la luminosité.", ha="center", va="center")
ax.set_axis_off()
fig.savefig(output_path, dpi=150, bbox_inches="tight")
plt.close(fig)
return output_path.resolve()
export_plot_dataset(monthly_series, output_path)
months = monthly_series.index
fig, ax = plt.subplots(figsize=(10, 4))
ax.bar(months, monthly_series.values, color="goldenrod", alpha=0.8)
ax.set_ylabel("Heures de luminosité par jour")
ax.set_xlabel("Mois")
ax.xaxis.set_major_locator(mdates.AutoDateLocator())
ax.xaxis.set_major_formatter(mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()))
ax.set_title(title)
ax.grid(True, axis="y", linestyle=":", alpha=0.5)
fig.tight_layout()
fig.savefig(output_path, dpi=150)
plt.close(fig)
return output_path.resolve()