diff --git a/README.md b/README.md index 7005cf4..cd1e18d 100644 --- a/README.md +++ b/README.md @@ -346,9 +346,11 @@ Les requêtes API sont dédoublonnées, espacées (fair-use) et mises en cache d 1. `source .venv/bin/activate` 2. `python -m scripts.plot_minifig_character_collages` +3. `python -m scripts.plot_minifig_head_collages` Le script lit `data/intermediate/minifigs_by_set.csv`, `data/intermediate/sets_enriched.csv` et les ressources téléchargées dans `figures/rebrickable`. Il regroupe chaque personnage connu (hors figurants) avec les sets associés et leur année de commercialisation, pour produire : -- `data/intermediate/minifig_character_sets.csv` : apparitions des personnages avec set, identifiant de set, année et fig_num. -- `figures/step32/minifig_characters/{personnage}.png` : frise horizontale par personnage, composée des visuels de minifigs dans l’ordre chronologique, annotés avec l’année et le numéro de set. Les minifigs dont l’image n’est pas disponible sont remplacées par un rectangle neutre pour matérialiser le manque. +- `data/intermediate/minifig_character_sets.csv` : apparitions des personnages avec set, identifiant de set, année, possession et fig_num. +- `figures/step32/minifig_characters/{personnage}.png` : frise horizontale par personnage, composée des visuels de minifigs dans l’ordre chronologique, annotés avec l’année, le numéro de set (avec `*` si possédé) et l’identifiant de minifig. Les minifigs dont l’image n’est pas disponible sont remplacées par un rectangle neutre pour matérialiser le manque. +- `figures/step32/minifig_heads/{personnage}.png` : même principe mais en utilisant les visuels de têtes (`head.jpg`) pour chaque apparition. - Les étiquettes affichent aussi l’identifiant de la minifig (`fig-*`) et un astérisque à côté du set (`set_num*`) lorsqu’il est présent dans la collection. diff --git a/figures/step32/minifig_heads/Alan_Grant.png b/figures/step32/minifig_heads/Alan_Grant.png new file mode 100644 index 0000000..9857091 Binary files /dev/null and b/figures/step32/minifig_heads/Alan_Grant.png differ diff --git a/figures/step32/minifig_heads/Allison_Miles.png b/figures/step32/minifig_heads/Allison_Miles.png new file mode 100644 index 0000000..2d33f5d Binary files /dev/null and b/figures/step32/minifig_heads/Allison_Miles.png differ diff --git a/figures/step32/minifig_heads/Atwater.png b/figures/step32/minifig_heads/Atwater.png new file mode 100644 index 0000000..136c940 Binary files /dev/null and b/figures/step32/minifig_heads/Atwater.png differ diff --git a/figures/step32/minifig_heads/Barry.png b/figures/step32/minifig_heads/Barry.png new file mode 100644 index 0000000..8e8aa24 Binary files /dev/null and b/figures/step32/minifig_heads/Barry.png differ diff --git a/figures/step32/minifig_heads/Ben.png b/figures/step32/minifig_heads/Ben.png new file mode 100644 index 0000000..9597003 Binary files /dev/null and b/figures/step32/minifig_heads/Ben.png differ diff --git a/figures/step32/minifig_heads/Brooklynn.png b/figures/step32/minifig_heads/Brooklynn.png new file mode 100644 index 0000000..f45f21f Binary files /dev/null and b/figures/step32/minifig_heads/Brooklynn.png differ diff --git a/figures/step32/minifig_heads/Claire_Dearing.png b/figures/step32/minifig_heads/Claire_Dearing.png new file mode 100644 index 0000000..1bc71a8 Binary files /dev/null and b/figures/step32/minifig_heads/Claire_Dearing.png differ diff --git a/figures/step32/minifig_heads/Danny_Nedermeyer.png b/figures/step32/minifig_heads/Danny_Nedermeyer.png new file mode 100644 index 0000000..f48b1c8 Binary files /dev/null and b/figures/step32/minifig_heads/Danny_Nedermeyer.png differ diff --git a/figures/step32/minifig_heads/Darius.png b/figures/step32/minifig_heads/Darius.png new file mode 100644 index 0000000..4b13071 Binary files /dev/null and b/figures/step32/minifig_heads/Darius.png differ diff --git a/figures/step32/minifig_heads/Dennis_Nedry.png b/figures/step32/minifig_heads/Dennis_Nedry.png new file mode 100644 index 0000000..f8ce532 Binary files /dev/null and b/figures/step32/minifig_heads/Dennis_Nedry.png differ diff --git a/figures/step32/minifig_heads/Duncan_Kincaid.png b/figures/step32/minifig_heads/Duncan_Kincaid.png new file mode 100644 index 0000000..d98c854 Binary files /dev/null and b/figures/step32/minifig_heads/Duncan_Kincaid.png differ diff --git a/figures/step32/minifig_heads/Eli_Mills.png b/figures/step32/minifig_heads/Eli_Mills.png new file mode 100644 index 0000000..5e4f745 Binary files /dev/null and b/figures/step32/minifig_heads/Eli_Mills.png differ diff --git a/figures/step32/minifig_heads/Ellie_Sattler.png b/figures/step32/minifig_heads/Ellie_Sattler.png new file mode 100644 index 0000000..4bbf02c Binary files /dev/null and b/figures/step32/minifig_heads/Ellie_Sattler.png differ diff --git a/figures/step32/minifig_heads/Franklin_Webb.png b/figures/step32/minifig_heads/Franklin_Webb.png new file mode 100644 index 0000000..463849a Binary files /dev/null and b/figures/step32/minifig_heads/Franklin_Webb.png differ diff --git a/figures/step32/minifig_heads/Gray_Mitchell.png b/figures/step32/minifig_heads/Gray_Mitchell.png new file mode 100644 index 0000000..fd78974 Binary files /dev/null and b/figures/step32/minifig_heads/Gray_Mitchell.png differ diff --git a/figures/step32/minifig_heads/Gunnar_Eversol.png b/figures/step32/minifig_heads/Gunnar_Eversol.png new file mode 100644 index 0000000..45a95f8 Binary files /dev/null and b/figures/step32/minifig_heads/Gunnar_Eversol.png differ diff --git a/figures/step32/minifig_heads/Henry_Loomis.png b/figures/step32/minifig_heads/Henry_Loomis.png new file mode 100644 index 0000000..5af6a1b Binary files /dev/null and b/figures/step32/minifig_heads/Henry_Loomis.png differ diff --git a/figures/step32/minifig_heads/Henry_Wu.png b/figures/step32/minifig_heads/Henry_Wu.png new file mode 100644 index 0000000..feadc4d Binary files /dev/null and b/figures/step32/minifig_heads/Henry_Wu.png differ diff --git a/figures/step32/minifig_heads/Hudson_Harper.png b/figures/step32/minifig_heads/Hudson_Harper.png new file mode 100644 index 0000000..b5e7aed Binary files /dev/null and b/figures/step32/minifig_heads/Hudson_Harper.png differ diff --git a/figures/step32/minifig_heads/Ian_Malcolm.png b/figures/step32/minifig_heads/Ian_Malcolm.png new file mode 100644 index 0000000..764a51e Binary files /dev/null and b/figures/step32/minifig_heads/Ian_Malcolm.png differ diff --git a/figures/step32/minifig_heads/Isabella_Delgado.png b/figures/step32/minifig_heads/Isabella_Delgado.png new file mode 100644 index 0000000..dfbdea6 Binary files /dev/null and b/figures/step32/minifig_heads/Isabella_Delgado.png differ diff --git a/figures/step32/minifig_heads/John_Hammond.png b/figures/step32/minifig_heads/John_Hammond.png new file mode 100644 index 0000000..f779c13 Binary files /dev/null and b/figures/step32/minifig_heads/John_Hammond.png differ diff --git a/figures/step32/minifig_heads/Kayla_Watts.png b/figures/step32/minifig_heads/Kayla_Watts.png new file mode 100644 index 0000000..11a74bc Binary files /dev/null and b/figures/step32/minifig_heads/Kayla_Watts.png differ diff --git a/figures/step32/minifig_heads/Ken_Wheatley.png b/figures/step32/minifig_heads/Ken_Wheatley.png new file mode 100644 index 0000000..644603b Binary files /dev/null and b/figures/step32/minifig_heads/Ken_Wheatley.png differ diff --git a/figures/step32/minifig_heads/Kenji.png b/figures/step32/minifig_heads/Kenji.png new file mode 100644 index 0000000..64ce6ec Binary files /dev/null and b/figures/step32/minifig_heads/Kenji.png differ diff --git a/figures/step32/minifig_heads/LeClerc.png b/figures/step32/minifig_heads/LeClerc.png new file mode 100644 index 0000000..929c135 Binary files /dev/null and b/figures/step32/minifig_heads/LeClerc.png differ diff --git a/figures/step32/minifig_heads/Lex_Murphy.png b/figures/step32/minifig_heads/Lex_Murphy.png new file mode 100644 index 0000000..332b1f6 Binary files /dev/null and b/figures/step32/minifig_heads/Lex_Murphy.png differ diff --git a/figures/step32/minifig_heads/Maisie_Lockwood.png b/figures/step32/minifig_heads/Maisie_Lockwood.png new file mode 100644 index 0000000..17125c9 Binary files /dev/null and b/figures/step32/minifig_heads/Maisie_Lockwood.png differ diff --git a/figures/step32/minifig_heads/Martin_Krebs.png b/figures/step32/minifig_heads/Martin_Krebs.png new file mode 100644 index 0000000..a732bdc Binary files /dev/null and b/figures/step32/minifig_heads/Martin_Krebs.png differ diff --git a/figures/step32/minifig_heads/Owen_Grady.png b/figures/step32/minifig_heads/Owen_Grady.png new file mode 100644 index 0000000..56e040a Binary files /dev/null and b/figures/step32/minifig_heads/Owen_Grady.png differ diff --git a/figures/step32/minifig_heads/Rainn_DeLaCourt.png b/figures/step32/minifig_heads/Rainn_DeLaCourt.png new file mode 100644 index 0000000..269e384 Binary files /dev/null and b/figures/step32/minifig_heads/Rainn_DeLaCourt.png differ diff --git a/figures/step32/minifig_heads/Ray_Arnold.png b/figures/step32/minifig_heads/Ray_Arnold.png new file mode 100644 index 0000000..0bfa406 Binary files /dev/null and b/figures/step32/minifig_heads/Ray_Arnold.png differ diff --git a/figures/step32/minifig_heads/Reuben_Delgado.png b/figures/step32/minifig_heads/Reuben_Delgado.png new file mode 100644 index 0000000..d1a1dfa Binary files /dev/null and b/figures/step32/minifig_heads/Reuben_Delgado.png differ diff --git a/figures/step32/minifig_heads/Robert_Muldoon.png b/figures/step32/minifig_heads/Robert_Muldoon.png new file mode 100644 index 0000000..136b47d Binary files /dev/null and b/figures/step32/minifig_heads/Robert_Muldoon.png differ diff --git a/figures/step32/minifig_heads/Sammy.png b/figures/step32/minifig_heads/Sammy.png new file mode 100644 index 0000000..c429266 Binary files /dev/null and b/figures/step32/minifig_heads/Sammy.png differ diff --git a/figures/step32/minifig_heads/Simon_Masrani.png b/figures/step32/minifig_heads/Simon_Masrani.png new file mode 100644 index 0000000..36e2089 Binary files /dev/null and b/figures/step32/minifig_heads/Simon_Masrani.png differ diff --git a/figures/step32/minifig_heads/Sinjin_Prescott.png b/figures/step32/minifig_heads/Sinjin_Prescott.png new file mode 100644 index 0000000..a09d28d Binary files /dev/null and b/figures/step32/minifig_heads/Sinjin_Prescott.png differ diff --git a/figures/step32/minifig_heads/Soyona_Santos.png b/figures/step32/minifig_heads/Soyona_Santos.png new file mode 100644 index 0000000..360b500 Binary files /dev/null and b/figures/step32/minifig_heads/Soyona_Santos.png differ diff --git a/figures/step32/minifig_heads/Teresa_Delgado.png b/figures/step32/minifig_heads/Teresa_Delgado.png new file mode 100644 index 0000000..4ce1d40 Binary files /dev/null and b/figures/step32/minifig_heads/Teresa_Delgado.png differ diff --git a/figures/step32/minifig_heads/Tim_Murphy.png b/figures/step32/minifig_heads/Tim_Murphy.png new file mode 100644 index 0000000..8599c5c Binary files /dev/null and b/figures/step32/minifig_heads/Tim_Murphy.png differ diff --git a/figures/step32/minifig_heads/Vic_Hoskins.png b/figures/step32/minifig_heads/Vic_Hoskins.png new file mode 100644 index 0000000..a8190f7 Binary files /dev/null and b/figures/step32/minifig_heads/Vic_Hoskins.png differ diff --git a/figures/step32/minifig_heads/Xavier_Dobbs.png b/figures/step32/minifig_heads/Xavier_Dobbs.png new file mode 100644 index 0000000..a06082c Binary files /dev/null and b/figures/step32/minifig_heads/Xavier_Dobbs.png differ diff --git a/figures/step32/minifig_heads/Yaz.png b/figures/step32/minifig_heads/Yaz.png new file mode 100644 index 0000000..2ff8a27 Binary files /dev/null and b/figures/step32/minifig_heads/Yaz.png differ diff --git a/figures/step32/minifig_heads/Zach_Mitchell.png b/figures/step32/minifig_heads/Zach_Mitchell.png new file mode 100644 index 0000000..d0363d1 Binary files /dev/null and b/figures/step32/minifig_heads/Zach_Mitchell.png differ diff --git a/figures/step32/minifig_heads/Zia_Rodriguez.png b/figures/step32/minifig_heads/Zia_Rodriguez.png new file mode 100644 index 0000000..5461001 Binary files /dev/null and b/figures/step32/minifig_heads/Zia_Rodriguez.png differ diff --git a/figures/step32/minifig_heads/Zora_Bennett.png b/figures/step32/minifig_heads/Zora_Bennett.png new file mode 100644 index 0000000..bec9612 Binary files /dev/null and b/figures/step32/minifig_heads/Zora_Bennett.png differ diff --git a/lib/plots/minifig_character_collages.py b/lib/plots/minifig_character_collages.py index 46132da..46a1b4d 100644 --- a/lib/plots/minifig_character_collages.py +++ b/lib/plots/minifig_character_collages.py @@ -57,6 +57,7 @@ def build_character_collage( destination_dir: Path, font: ImageFont.ImageFont, missing_paths: Set[str] | None = None, + image_filename: str = "minifig.jpg", image_height: int = 260, label_height: int = 44, spacing: int = 28, @@ -66,7 +67,7 @@ def build_character_collage( missing = missing_paths or set() cells: List[Image.Image] = [] for row in entries: - image_path = resources_dir / row["set_id"] / sanitized / "minifig.jpg" + image_path = resources_dir / row["set_id"] / sanitized / image_filename owned = "*" if row.get("in_collection", "").lower() == "true" else "" label = f"{row['year']} - {row['set_num']}{owned} ({row['fig_num']})" if str(image_path) in missing: @@ -92,6 +93,7 @@ def build_character_collages( resources_dir: Path, destination_dir: Path, missing_paths: Set[str] | None = None, + image_filename: str = "minifig.jpg", image_height: int = 260, label_height: int = 44, spacing: int = 28, @@ -108,6 +110,7 @@ def build_character_collages( destination_dir, font, missing_paths=missing_paths, + image_filename=image_filename, image_height=image_height, label_height=label_height, spacing=spacing, diff --git a/lib/rebrickable/minifig_character_sets.py b/lib/rebrickable/minifig_character_sets.py index e203930..9f5d821 100644 --- a/lib/rebrickable/minifig_character_sets.py +++ b/lib/rebrickable/minifig_character_sets.py @@ -86,13 +86,18 @@ def group_by_character(rows: Iterable[dict]) -> Dict[str, List[dict]]: def load_missing_minifigs(path: Path) -> set[str]: """Charge les ressources minifigs introuvables consignées dans le log de téléchargement.""" + return load_missing_resources(path, "minifig.jpg") + + +def load_missing_resources(path: Path, filename: str) -> set[str]: + """Charge les ressources introuvables d'un type donné consignées dans le log de téléchargement.""" missing: set[str] = set() with path.open() as csv_file: reader = csv.DictReader(csv_file) for row in reader: if row["status"] != "missing": continue - if not row["path"].endswith("minifig.jpg"): + if not row["path"].endswith(filename): continue missing.add(row["path"]) return missing diff --git a/scripts/plot_minifig_head_collages.py b/scripts/plot_minifig_head_collages.py new file mode 100644 index 0000000..e175142 --- /dev/null +++ b/scripts/plot_minifig_head_collages.py @@ -0,0 +1,43 @@ +"""Construit les frises chronologiques des têtes de minifigs par personnage.""" + +from pathlib import Path + +from lib.plots.minifig_character_collages import build_character_collages +from lib.rebrickable.minifig_character_sets import ( + build_character_sets, + group_by_character, + load_minifigs_by_set, + load_missing_resources, + load_sets, + write_character_sets, +) + + +MINIFIGS_BY_SET_PATH = Path("data/intermediate/minifigs_by_set.csv") +SETS_ENRICHED_PATH = Path("data/intermediate/sets_enriched.csv") +RESOURCES_DIR = Path("figures/rebrickable") +DESTINATION_DIR = Path("figures/step32/minifig_heads") +CHARACTER_SETS_PATH = Path("data/intermediate/minifig_character_sets.csv") +DOWNLOAD_LOG_PATH = Path("data/intermediate/resources_download_log.csv") +EXCLUDED_CHARACTERS = ["Figurant"] + + +def main() -> None: + """Assemble les apparitions des personnages et génère les frises de têtes associées.""" + minifigs_by_set = load_minifigs_by_set(MINIFIGS_BY_SET_PATH) + sets_lookup = load_sets(SETS_ENRICHED_PATH) + character_sets = build_character_sets(minifigs_by_set, sets_lookup, excluded_characters=EXCLUDED_CHARACTERS) + write_character_sets(CHARACTER_SETS_PATH, character_sets) + missing_heads = load_missing_resources(DOWNLOAD_LOG_PATH, "head.jpg") + grouped = group_by_character(character_sets) + build_character_collages( + grouped, + RESOURCES_DIR, + DESTINATION_DIR, + missing_paths=missing_heads, + image_filename="head.jpg", + ) + + +if __name__ == "__main__": + main() diff --git a/tests/test_minifig_character_collages.py b/tests/test_minifig_character_collages.py index e3472be..6be4d4d 100644 --- a/tests/test_minifig_character_collages.py +++ b/tests/test_minifig_character_collages.py @@ -85,6 +85,7 @@ def test_build_character_sets_and_collages(tmp_path: Path) -> None: resources_dir, destination_dir, missing_paths=missing_minifigs, + image_filename="minifig.jpg", image_height=20, label_height=10, spacing=2, @@ -98,3 +99,28 @@ def test_build_character_sets_and_collages(tmp_path: Path) -> None: assert bob.size == (42, 30) assert claire.size == (20, 30) assert claire.getpixel((5, 10)) == (220, 220, 220) + + # Variante sur les têtes : utilise un autre fichier et un autre manque. + heads_destination = tmp_path / "output_heads" + head_missing = { + str(resources_dir / "1001" / sanitize_name("Bob") / "head.jpg"), + str(resources_dir / "1002" / sanitize_name("Bob") / "head.jpg"), + str(resources_dir / "1004" / sanitize_name("Claire Dearing") / "head.jpg"), + } + head_image = resources_dir / "1000" / sanitize_name("Alice") / "head.jpg" + create_image(head_image, (10, 120, 60), (8, 12)) + head_collages = build_character_collages( + group_by_character(character_sets), + resources_dir, + heads_destination, + missing_paths=head_missing, + image_filename="head.jpg", + image_height=16, + label_height=8, + spacing=2, + ) + assert len(head_collages) == 3 + alice_head = Image.open(heads_destination / f"{sanitize_name('Alice')}.png") + bob_head = Image.open(heads_destination / f"{sanitize_name('Bob')}.png") + assert alice_head.size[1] == 24 + assert bob_head.getpixel((3, 8)) == (220, 220, 220)