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

115 lines
3.4 KiB
Python

"""Tracés orientés calendrier (heatmaps quotidiennes et profils hebdomadaires)."""
from __future__ import annotations
from pathlib import Path
from typing import Sequence
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from .base import export_plot_dataset
from meteo.variables import Variable
__all__ = ['plot_calendar_heatmap', 'plot_weekday_profiles']
def plot_calendar_heatmap(
matrix: pd.DataFrame,
output_path: str | Path,
*,
title: str,
cmap: str = "YlGnBu",
colorbar_label: str = "",
) -> Path:
"""
Affiche une heatmap calendrier (lignes = mois, colonnes = jours).
"""
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
export_plot_dataset(matrix, output_path)
if matrix.empty:
fig, ax = plt.subplots()
ax.text(0.5, 0.5, "Pas de données pour la heatmap.", ha="center", va="center")
ax.set_axis_off()
fig.savefig(output_path, dpi=150, bbox_inches="tight")
plt.close(fig)
return output_path.resolve()
fig, ax = plt.subplots(figsize=(14, 6))
data = matrix.to_numpy(dtype=float)
im = ax.imshow(data, aspect="auto", cmap=cmap, interpolation="nearest")
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_xlabel("Jour du mois")
ax.set_ylabel("Mois")
ax.set_title(title)
cbar = fig.colorbar(im, ax=ax)
if colorbar_label:
cbar.set_label(colorbar_label)
fig.tight_layout()
fig.savefig(output_path, dpi=150)
plt.close(fig)
return output_path.resolve()
def plot_weekday_profiles(
weekday_df: pd.DataFrame,
variables: Sequence[Variable],
output_path: str | Path,
*,
title: str,
) -> Path:
"""
Affiche les moyennes par jour de semaine pour plusieurs variables.
"""
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
if weekday_df.empty:
fig, ax = plt.subplots()
ax.text(0.5, 0.5, "Pas de données hebdomadaires.", 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(weekday_df, output_path)
weekday_labels = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"]
n_vars = len(variables)
fig, axes = plt.subplots(n_vars, 1, figsize=(10, 3 * n_vars), sharex=True)
if n_vars == 1:
axes = [axes]
x = np.arange(len(weekday_labels))
for ax, var in zip(axes, variables):
if var.column not in weekday_df.columns:
ax.text(0.5, 0.5, f"Aucune donnée pour {var.label}.", ha="center", va="center")
ax.set_axis_off()
continue
values = weekday_df[var.column].to_numpy(dtype=float)
ax.plot(x, values, marker="o", label=var.label)
ax.set_ylabel(f"{var.label} ({var.unit})" if var.unit else var.label)
ax.grid(True, linestyle=":", alpha=0.5)
ax.set_xticks(x)
ax.set_xticklabels(weekday_labels)
axes[-1].set_xlabel("Jour de semaine")
axes[0].legend(loc="upper right")
fig.suptitle(title)
fig.tight_layout(rect=[0, 0, 1, 0.97])
fig.savefig(output_path, dpi=150)
plt.close(fig)
return output_path.resolve()