115 lines
3.4 KiB
Python
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()
|