You've already forked donnees_meteo
Graphiques de corrélations binaires simples
This commit is contained in:
@@ -26,6 +26,7 @@ from .basic_series import (
|
||||
PlotChoice,
|
||||
PlotStyle,
|
||||
plot_basic_series,
|
||||
plot_dual_time_series,
|
||||
recommended_style,
|
||||
resample_series_for_plot,
|
||||
)
|
||||
@@ -64,6 +65,7 @@ __all__ = [
|
||||
"PlotChoice",
|
||||
"PlotStyle",
|
||||
"plot_basic_series",
|
||||
"plot_dual_time_series",
|
||||
"recommended_style",
|
||||
"resample_series_for_plot",
|
||||
"plot_daylight_hours",
|
||||
|
||||
@@ -23,6 +23,7 @@ __all__ = [
|
||||
"recommended_style",
|
||||
"resample_series_for_plot",
|
||||
"plot_basic_series",
|
||||
"plot_dual_time_series",
|
||||
]
|
||||
|
||||
|
||||
@@ -145,6 +146,11 @@ def _series_color(variable: Variable) -> str:
|
||||
return PALETTE.get(variable.column, DEFAULT_COLOR)
|
||||
|
||||
|
||||
def _format_label(var: Variable) -> str:
|
||||
unit_text = f" ({var.unit})" if var.unit else ""
|
||||
return f"{var.label}{unit_text}"
|
||||
|
||||
|
||||
def resample_series_for_plot(
|
||||
series: pd.Series,
|
||||
*,
|
||||
@@ -230,3 +236,115 @@ def plot_basic_series(
|
||||
|
||||
export_plot_dataset(series.to_frame(name=variable.column), output_path)
|
||||
return output_path.resolve()
|
||||
|
||||
|
||||
def _draw_series(ax: plt.Axes, series: pd.Series, *, choice: PlotChoice, color: str, label: str):
|
||||
x = mdates.date2num(series.index)
|
||||
values = series.to_numpy(dtype=float)
|
||||
|
||||
if choice.style is PlotStyle.LINE:
|
||||
return ax.plot_date(x, values, "-", linewidth=1.8, color=color, label=label)
|
||||
if choice.style is PlotStyle.AREA:
|
||||
ax.fill_between(x, values, step="mid", color=color, alpha=0.15)
|
||||
return ax.plot_date(x, values, "-", linewidth=1.6, color=color, label=label)
|
||||
if choice.style is PlotStyle.BAR:
|
||||
width = _infer_bar_width(series.index) * 0.9
|
||||
return ax.bar(x, values, width=width, color=color, edgecolor=color, linewidth=0.5, alpha=0.75, label=label)
|
||||
if choice.style is PlotStyle.SCATTER:
|
||||
return ax.scatter(x, values, s=16, color=color, alpha=0.9, label=label)
|
||||
raise ValueError(f"Style inconnu : {choice.style}")
|
||||
|
||||
|
||||
def plot_dual_time_series(
|
||||
series_left: pd.Series,
|
||||
variable_left: Variable,
|
||||
choice_left: PlotChoice,
|
||||
series_right: pd.Series,
|
||||
variable_right: Variable,
|
||||
choice_right: PlotChoice,
|
||||
*,
|
||||
output_path: str | Path,
|
||||
title: str,
|
||||
annotate_freq: str | None = None,
|
||||
) -> Path:
|
||||
"""Superpose deux séries temporelles (axes Y séparés) avec styles adaptés."""
|
||||
|
||||
_ensure_datetime_index(series_left)
|
||||
_ensure_datetime_index(series_right)
|
||||
|
||||
if series_left.empty or series_right.empty:
|
||||
raise ValueError("Les séries à tracer ne peuvent pas être vides.")
|
||||
|
||||
output_path = Path(output_path)
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
color_left = _series_color(variable_left)
|
||||
color_right = _series_color(variable_right)
|
||||
|
||||
fig, ax_left = plt.subplots(figsize=(11, 4.6))
|
||||
ax_right = ax_left.twinx()
|
||||
|
||||
artists_left = _draw_series(
|
||||
ax_left,
|
||||
series_left,
|
||||
choice=choice_left,
|
||||
color=color_left,
|
||||
label=_format_label(variable_left),
|
||||
)
|
||||
artists_right = _draw_series(
|
||||
ax_right,
|
||||
series_right,
|
||||
choice=choice_right,
|
||||
color=color_right,
|
||||
label=_format_label(variable_right),
|
||||
)
|
||||
|
||||
ax_left.set_ylabel(_format_label(variable_left), color=color_left)
|
||||
ax_right.set_ylabel(_format_label(variable_right), color=color_right)
|
||||
ax_left.tick_params(axis="y", labelcolor=color_left)
|
||||
ax_right.tick_params(axis="y", labelcolor=color_right)
|
||||
|
||||
_format_time_axis(ax_left)
|
||||
ax_left.grid(True, color="#e0e0e0", linewidth=0.8, alpha=0.7)
|
||||
ax_left.margins(x=0.02, y=0.05)
|
||||
ax_right.margins(x=0.02, y=0.05)
|
||||
ax_left.set_title(title)
|
||||
|
||||
handles = []
|
||||
labels = []
|
||||
for artist in artists_left if isinstance(artists_left, list) else [artists_left]:
|
||||
handles.append(artist)
|
||||
labels.append(artist.get_label())
|
||||
if isinstance(artists_right, list):
|
||||
handles.extend(artists_right)
|
||||
labels.extend([a.get_label() for a in artists_right])
|
||||
else:
|
||||
handles.append(artists_right)
|
||||
labels.append(artists_right.get_label())
|
||||
|
||||
ax_left.legend(handles, labels, loc="upper left")
|
||||
|
||||
if annotate_freq:
|
||||
ax_left.text(
|
||||
0.99,
|
||||
0.02,
|
||||
f"Agrégation : {annotate_freq}",
|
||||
transform=ax_left.transAxes,
|
||||
ha="right",
|
||||
va="bottom",
|
||||
fontsize=9,
|
||||
color="#555555",
|
||||
)
|
||||
|
||||
fig.tight_layout()
|
||||
fig.savefig(output_path, dpi=150)
|
||||
plt.close(fig)
|
||||
|
||||
export_plot_dataset(
|
||||
pd.concat(
|
||||
{variable_left.column: series_left, variable_right.column: series_right},
|
||||
axis=1,
|
||||
),
|
||||
output_path,
|
||||
)
|
||||
return output_path.resolve()
|
||||
|
||||
Reference in New Issue
Block a user