"""Visualisation de la réutilisation des têtes de minifigs.""" import csv from pathlib import Path from typing import List import matplotlib.pyplot as plt from lib.filesystem import ensure_parent_dir def load_head_reuse(path: Path) -> List[dict]: """Charge le CSV head_reuse.""" rows: List[dict] = [] with path.open() as csv_file: reader = csv.DictReader(csv_file) for row in reader: rows.append(row) return rows def format_label(row: dict) -> str: """Formate le label affiché sur l'axe vertical.""" character = row["known_character"] if character != "": return f"{row['part_num']} — {character}" return row["part_num"] def plot_head_reuse(path: Path, destination_path: Path, top: int = 30) -> None: """Trace un bar chart horizontal mettant en avant les têtes exclusives ou rares.""" rows = load_head_reuse(path) rows.sort(key=lambda r: (int(r["other_sets"]), -int(r["filtered_sets"]), r["part_num"])) selected = rows[:top] labels = [format_label(r) for r in selected] filtered_counts = [int(r["filtered_sets"]) for r in selected] other_counts = [int(r["other_sets"]) for r in selected] positions = list(reversed(range(len(selected)))) fig, ax = plt.subplots(figsize=(12, 0.5 * len(selected) + 1.5)) ax.barh(positions, filtered_counts, color="#1f78b4", label="Sets filtrés") ax.barh(positions, other_counts, left=filtered_counts, color="#b2df8a", label="Autres sets") ax.set_yticks(positions) ax.set_yticklabels(reversed(labels)) ax.set_xlabel("Nombre de sets contenant la tête") ax.invert_yaxis() ax.grid(axis="x", linestyle="--", alpha=0.4) ax.legend() fig.tight_layout() ensure_parent_dir(destination_path) fig.savefig(destination_path, dpi=150) plt.close(fig)