You've already forked etude_lego_jurassic_world
Ajouter la frise des top couleurs annuelles
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user