1

78 lines
2.8 KiB
Python

"""Graphique des pièces rares par set."""
from pathlib import Path
from typing import List, Tuple
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
from lib.filesystem import ensure_parent_dir
from lib.rebrickable.stats import read_rows
def load_top_sets(path: Path, limit: int = 15) -> List[dict]:
"""Charge les sets triés par nombre de pièces rares et limite le top."""
rows = read_rows(path)
sorted_rows = sorted(
rows,
key=lambda row: (
-int(row["rare_parts_distinct"]),
-int(row["rare_parts_quantity"]),
row["set_num"],
),
)
return sorted_rows[:limit]
def split_counts(rows: List[dict]) -> Tuple[List[int], List[int]]:
"""Sépare les comptages minifig vs hors minifig."""
non_minifig: List[int] = []
minifig: List[int] = []
for row in rows:
total = int(row["rare_parts_distinct"])
minifig_count = int(row["rare_minifig_parts_distinct"])
non_minifig.append(total - minifig_count)
minifig.append(minifig_count)
return non_minifig, minifig
def plot_rare_parts_per_set(rare_by_set_path: Path, destination_path: Path) -> None:
"""Trace le top des sets contenant des pièces exclusives."""
rows = load_top_sets(rare_by_set_path)
if not rows:
return
non_minifig, minifig = split_counts(rows)
y_positions = list(range(len(rows)))
labels = [f"{row['set_num']} · {row['name']} ({row['year']})" for row in rows]
owned_mask = [row["in_collection"] == "true" for row in rows]
base_color = "#1f77b4"
accent_color = "#f28e2b"
fig, ax = plt.subplots(figsize=(11, 8))
for y, value, is_owned in zip(y_positions, non_minifig, owned_mask):
alpha = 0.92 if is_owned else 0.45
ax.barh(y, value, color=base_color, alpha=alpha, label=None)
for y, value, offset, is_owned in zip(y_positions, minifig, non_minifig, owned_mask):
alpha = 0.92 if is_owned else 0.45
ax.barh(y, value, left=offset, color=accent_color, alpha=alpha, label=None)
ax.set_yticks(y_positions)
ax.set_yticklabels(labels)
ax.invert_yaxis()
ax.set_xlabel("Variantes de pièces exclusives (hors rechanges)")
ax.set_title("Pièces rares par set (top)")
ax.grid(axis="x", linestyle="--", alpha=0.35)
handles = [
Patch(facecolor=base_color, edgecolor="none", label="Pièces hors minifigs"),
Patch(facecolor=accent_color, edgecolor="none", label="Pièces de minifigs"),
Patch(facecolor="#000000", edgecolor="none", alpha=0.92, label="Set possédé"),
Patch(facecolor="#000000", edgecolor="none", alpha=0.45, label="Set manquant"),
]
ax.legend(handles=handles, loc="lower right", frameon=False)
ensure_parent_dir(destination_path)
fig.tight_layout()
fig.savefig(destination_path, dpi=170)
plt.close(fig)