You've already forked donnees_meteo
Amélioration des vues basiques
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# scripts/plot_basic_variables.py
|
||||
"""Génère des séries temporelles simples (7 jours) pour chaque variable météo."""
|
||||
"""Génère des séries temporelles simples pour chaque variable météo."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -7,7 +7,6 @@ import argparse
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
|
||||
|
||||
@@ -16,7 +15,7 @@ if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
from meteo.plots import export_plot_dataset
|
||||
from meteo.plots import PlotChoice, PlotStyle, plot_basic_series, recommended_style, resample_series_for_plot
|
||||
from meteo.variables import Variable, VARIABLES
|
||||
|
||||
|
||||
@@ -25,47 +24,32 @@ DOC_DIR = Path(__file__).resolve().parent.parent
|
||||
DEFAULT_OUTPUT_DIR = DOC_DIR / "figures"
|
||||
|
||||
|
||||
def _prepare_slice(df: pd.DataFrame, *, last_days: int) -> pd.DataFrame:
|
||||
"""Extrait la fenêtre temporelle souhaitée et applique une moyenne horaire pour lisser la courbe."""
|
||||
def _select_window(df: pd.DataFrame, *, last_days: int | None) -> pd.DataFrame:
|
||||
"""Extrait la fenêtre temporelle souhaitée (ou la totalité si None)."""
|
||||
|
||||
if last_days is None:
|
||||
return df
|
||||
end = df.index.max()
|
||||
start = end - pd.Timedelta(days=last_days)
|
||||
df_slice = df.loc[start:end]
|
||||
numeric_slice = df_slice.select_dtypes(include="number")
|
||||
if numeric_slice.empty:
|
||||
raise RuntimeError("Aucune colonne numérique disponible pour les moyennes horaires.")
|
||||
return numeric_slice.resample("1h").mean()
|
||||
return df.loc[start:end]
|
||||
|
||||
|
||||
def _plot_variable(df_hourly: pd.DataFrame, var: Variable, output_dir: Path) -> Path | None:
|
||||
"""Trace la série pour une variable et retourne le chemin de l'image générée."""
|
||||
|
||||
if var.column not in df_hourly.columns:
|
||||
print(f"⚠ Colonne absente pour {var.key} ({var.column}).")
|
||||
return None
|
||||
|
||||
series = df_hourly[var.column].dropna()
|
||||
if series.empty:
|
||||
print(f"⚠ Aucun point valide pour {var.key} dans l'intervalle choisi.")
|
||||
return None
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
output_path = output_dir / f"{var.key}_last_7_days.png"
|
||||
|
||||
export_plot_dataset(series.to_frame(name=var.column), output_path)
|
||||
|
||||
plt.figure()
|
||||
plt.plot(series.index, series)
|
||||
plt.xlabel("Temps (UTC)")
|
||||
def _format_ylabel(var: Variable) -> str:
|
||||
unit_text = f" ({var.unit})" if var.unit else ""
|
||||
plt.ylabel(f"{var.label}{unit_text}")
|
||||
plt.title(f"{var.label} - Moyenne horaire sur les 7 derniers jours")
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.savefig(output_path, dpi=150)
|
||||
plt.close()
|
||||
print(f"✔ Graphique généré : {output_path}")
|
||||
return output_path
|
||||
return f"{var.label}{unit_text}"
|
||||
|
||||
|
||||
def _aggregation_label(choice: PlotChoice, freq: str) -> str:
|
||||
"""Texte court pour indiquer l'agrégation appliquée."""
|
||||
|
||||
base = "moyenne"
|
||||
if callable(choice.agg) and getattr(choice.agg, "__name__", "") == "_circular_mean_deg":
|
||||
base = "moyenne circulaire"
|
||||
elif choice.agg == "sum":
|
||||
base = "somme"
|
||||
elif choice.agg == "median":
|
||||
base = "médiane"
|
||||
return f"{base} {freq}"
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> None:
|
||||
@@ -78,8 +62,23 @@ def main(argv: list[str] | None = None) -> None:
|
||||
parser.add_argument(
|
||||
"--days",
|
||||
type=int,
|
||||
default=7,
|
||||
help="Nombre de jours à afficher (par défaut : 7).",
|
||||
default=None,
|
||||
help="Nombre de jours à afficher (par défaut : toute la période disponible).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--style",
|
||||
choices=[style.value for style in PlotStyle],
|
||||
help="Style de représentation à utiliser pour toutes les variables (par défaut : recommandations par variable).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--resample",
|
||||
help="Fréquence pandas à utiliser pour l'agrégation temporelle (par défaut : calcul automatique).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--max-points",
|
||||
type=int,
|
||||
default=420,
|
||||
help="Nombre de points cible après agrégation automatique (par défaut : 420).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-dir",
|
||||
@@ -93,7 +92,7 @@ def main(argv: list[str] | None = None) -> None:
|
||||
raise FileNotFoundError(f"Dataset introuvable : {CSV_PATH}")
|
||||
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
df_hourly = _prepare_slice(df, last_days=args.days)
|
||||
df_window = _select_window(df, last_days=args.days)
|
||||
|
||||
selected: list[Variable]
|
||||
if args.only:
|
||||
@@ -105,8 +104,44 @@ def main(argv: list[str] | None = None) -> None:
|
||||
else:
|
||||
selected = list(VARIABLES)
|
||||
|
||||
output_dir: Path = args.output_dir
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for variable in selected:
|
||||
_plot_variable(df_hourly, variable, args.output_dir)
|
||||
if variable.column not in df_window.columns:
|
||||
print(f"⚠ Colonne absente pour {variable.key} ({variable.column}).")
|
||||
continue
|
||||
|
||||
series = df_window[variable.column].dropna()
|
||||
if series.empty:
|
||||
print(f"⚠ Aucun point valide pour {variable.key} sur la période choisie.")
|
||||
continue
|
||||
|
||||
style_choice = recommended_style(variable, args.style)
|
||||
|
||||
aggregated, freq_used = resample_series_for_plot(
|
||||
series,
|
||||
variable=variable,
|
||||
freq=args.resample,
|
||||
target_points=args.max_points,
|
||||
)
|
||||
if aggregated.empty:
|
||||
print(f"⚠ Pas de points après agrégation pour {variable.key}.")
|
||||
continue
|
||||
|
||||
output_path = output_dir / f"{variable.key}_overview.png"
|
||||
annotate_freq = _aggregation_label(style_choice, freq_used)
|
||||
|
||||
plot_basic_series(
|
||||
aggregated,
|
||||
variable=variable,
|
||||
output_path=output_path,
|
||||
style=style_choice.style,
|
||||
title=f"{variable.label} — évolution temporelle",
|
||||
ylabel=_format_ylabel(variable),
|
||||
annotate_freq=annotate_freq,
|
||||
)
|
||||
print(f"✔ Graphique généré : {output_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user