1

Ajouter la frise des top couleurs annuelles

This commit is contained in:
2025-12-03 15:28:53 +01:00
parent ed3e4354ec
commit ff2fa1819a
4 changed files with 84 additions and 2 deletions

View File

@@ -1,7 +1,7 @@
"""Visualisations temporelles des palettes de couleurs."""
from pathlib import Path
from typing import Dict, Iterable, List, Tuple
from typing import Dict, Iterable, List, Sequence, Tuple
import matplotlib.pyplot as plt
import numpy as np
@@ -115,6 +115,80 @@ def build_heatmap_data(rows: Iterable[dict]) -> Tuple[List[int], List[str], np.n
return years, labels, matrix, swatches
def build_top_colors_by_year(rows: Iterable[dict], limit: int = 5) -> List[dict]:
"""Extrait les principales couleurs par année avec leur part relative."""
totals_by_year: Dict[int, int] = {}
grouped: Dict[int, List[dict]] = {}
for row in rows:
year = int(row["year"])
quantity = int(row["quantity_total"])
totals_by_year[year] = totals_by_year.get(year, 0) + quantity
grouped.setdefault(year, []).append(row)
top_rows: List[dict] = []
for year in sorted(grouped.keys()):
entries = grouped[year]
entries.sort(key=lambda r: (-int(r["quantity_total"]), r["color_name"], r["color_rgb"]))
total = totals_by_year[year]
for rank, entry in enumerate(entries[:limit]):
quantity = int(entry["quantity_total"])
share = quantity / total if total > 0 else 0.0
top_rows.append(
{
"year": year,
"rank": rank,
"color_name": entry["color_name"],
"color_rgb": entry["color_rgb"],
"is_translucent": entry["is_translucent"],
"quantity_total": quantity,
"share": share,
}
)
return top_rows
def plot_top_colors_swatches(
matrix_path: Path,
destination_path: Path,
limit: int = 5,
) -> None:
"""Affiche une frise des top couleurs par année (5 pastilles empilées par année)."""
rows = load_rows(matrix_path)
if not rows:
return
top_rows = build_top_colors_by_year(rows, limit=limit)
years = sorted({row["year"] for row in top_rows})
year_positions = {year: idx for idx, year in enumerate(years)}
x_values = [year_positions[row["year"]] for row in top_rows]
y_values = [limit - row["rank"] - 1 for row in top_rows]
ordered_hex = sort_hex_colors_lab({row["color_rgb"] for row in top_rows})
hex_rank = {hex_value: idx for idx, hex_value in enumerate(ordered_hex)}
sorted_rows = sorted(
top_rows,
key=lambda r: (r["year"], hex_rank[r["color_rgb"]], r["is_translucent"], r["color_name"]),
)
x_values = [year_positions[row["year"]] for row in sorted_rows]
y_values = [sorted_rows[i]["rank"] * 0.6 for i in range(len(sorted_rows))]
colors = [f"#{row['color_rgb']}" for row in sorted_rows]
sizes = [620 for _ in sorted_rows]
edges = ["#f2f2f2" if row["is_translucent"] == "true" else "#111111" for row in sorted_rows]
fig, ax = plt.subplots(figsize=(0.75 * len(years) + 3.5, 0.75 * limit + 0.9))
ax.scatter(x_values, y_values, s=sizes, c=colors, edgecolors=edges, linewidths=1.05)
ax.set_xticks(list(year_positions.values()))
ax.set_xticklabels(years, rotation=45)
ax.set_yticks([])
ax.set_ylabel("")
ax.set_xlim(-0.6, len(years) - 0.4)
ax.set_ylim(-0.6, limit - 0.5)
ax.set_title(f"Top {limit} couleurs par année")
ax.grid(axis="x", linestyle="--", alpha=0.25)
ensure_parent_dir(destination_path)
fig.tight_layout()
fig.savefig(destination_path, dpi=160)
plt.close(fig)
def plot_colors_heatmap(
matrix_path: Path,
destination_path: Path,