1

Réorganise les visuels de l'étape 15 sous figures/step15

This commit is contained in:
Richard Dern 2025-12-01 23:15:59 +01:00
parent d494c1a695
commit 7a193136e5
4 changed files with 36 additions and 11 deletions

View File

@ -183,4 +183,5 @@ Le script lit `data/intermediate/colors_by_set.csv` et produit deux agrégats :
1. `source .venv/bin/activate` 1. `source .venv/bin/activate`
2. `python -m scripts.plot_colors_timeline` 2. `python -m scripts.plot_colors_timeline`
Le script lit les deux agrégats de l'étape précédente et produit `figures/step14/colors_translucent_share.png` (part des pièces translucides par année et nombre de couleurs distinctes), `figures/step14/colors_heatmap_linear.png` (heatmap année × couleur en quantités brutes) et `figures/step14/colors_heatmap_log.png` (heatmap avec échelle log1p). Le script lit les agrégats de l'étape 14 et produit `figures/step15/colors_translucent_share.png` (part des pièces translucides par année et nombre de couleurs distinctes), `figures/step15/colors_heatmap_linear.png` (heatmap année × couleur en quantités brutes) et `figures/step15/colors_heatmap_log.png` (heatmap avec échelle log1p).
Une troisième variante normalise les quantités par année : `figures/step15/colors_heatmap_share.png`. Dans cette vue, chaque colonne (année) est ramenée à une part relative (01) du total de pièces de l'année. Cela met en évidence la structure de palette indépendamment du volume : deux années restent comparables même si leur nombre total de pièces diffère fortement, mais l'information de volume absolu n'apparaît plus (à privilégier pour les comparaisons de proportions, pas pour mesurer la rareté volumique).

View File

@ -79,11 +79,21 @@ def build_heatmap_data(rows: Iterable[dict]) -> Tuple[List[int], List[str], np.n
return years, labels, matrix, swatches return years, labels, matrix, swatches
def plot_colors_heatmap(matrix_path: Path, destination_path: Path, use_log_scale: bool = False) -> None: def plot_colors_heatmap(
"""Génère une heatmap année × couleur basée sur les quantités totales avec pastilles.""" matrix_path: Path,
destination_path: Path,
use_log_scale: bool = False,
normalize_by_year: bool = False,
) -> None:
"""Génère une heatmap année × couleur avec pastilles (linéaire, log1p ou normalisée)."""
rows = load_rows(matrix_path) rows = load_rows(matrix_path)
years, labels, matrix, swatches = build_heatmap_data(rows) years, labels, matrix, swatches = build_heatmap_data(rows)
values = np.log1p(matrix) if use_log_scale else matrix values = matrix
if normalize_by_year:
column_totals = matrix.sum(axis=0, keepdims=True)
values = matrix / column_totals
if use_log_scale:
values = np.log1p(values)
fig, ax = plt.subplots(figsize=(14, max(6, len(labels) * 0.26))) fig, ax = plt.subplots(figsize=(14, max(6, len(labels) * 0.26)))
y_positions = np.arange(len(labels)) y_positions = np.arange(len(labels))
@ -108,10 +118,18 @@ def plot_colors_heatmap(matrix_path: Path, destination_path: Path, use_log_scale
) )
ax.set_xlim(-1.1, len(years) - 0.5) ax.set_xlim(-1.1, len(years) - 0.5)
ax.set_xlabel("Année") ax.set_xlabel("Année")
title_scale = "log1p des quantités" if use_log_scale else "quantités totales" if normalize_by_year:
title_scale = "parts de couleur (par année)"
else:
title_scale = "log1p des quantités" if use_log_scale else "quantités totales"
ax.set_title(f"Intensité des couleurs par année ({title_scale})") ax.set_title(f"Intensité des couleurs par année ({title_scale})")
cbar = fig.colorbar(heatmap, ax=ax, shrink=0.82, pad=0.018) cbar = fig.colorbar(heatmap, ax=ax, shrink=0.82, pad=0.018)
cbar_label = "log1p(quantité totale)" if use_log_scale else "quantité totale" if normalize_by_year:
cbar_label = "Part de la couleur (0-1)"
elif use_log_scale:
cbar_label = "log1p(quantité totale)"
else:
cbar_label = "quantité totale"
cbar.set_label(cbar_label) cbar.set_label(cbar_label)
ensure_parent_dir(destination_path) ensure_parent_dir(destination_path)
fig.subplots_adjust(left=0.26, right=0.97, bottom=0.08, top=0.94) fig.subplots_adjust(left=0.26, right=0.97, bottom=0.08, top=0.94)

View File

@ -7,9 +7,10 @@ from lib.plots.colors_timeline import plot_colors_heatmap, plot_translucent_shar
TIMELINE_PATH = Path("data/intermediate/colors_timeline.csv") TIMELINE_PATH = Path("data/intermediate/colors_timeline.csv")
MATRIX_PATH = Path("data/intermediate/colors_year_color_matrix.csv") MATRIX_PATH = Path("data/intermediate/colors_year_color_matrix.csv")
TRANSLUCENT_DESTINATION = Path("figures/step14/colors_translucent_share.png") TRANSLUCENT_DESTINATION = Path("figures/step15/colors_translucent_share.png")
HEATMAP_LINEAR_DESTINATION = Path("figures/step14/colors_heatmap_linear.png") HEATMAP_LINEAR_DESTINATION = Path("figures/step15/colors_heatmap_linear.png")
HEATMAP_LOG_DESTINATION = Path("figures/step14/colors_heatmap_log.png") HEATMAP_LOG_DESTINATION = Path("figures/step15/colors_heatmap_log.png")
HEATMAP_SHARE_DESTINATION = Path("figures/step15/colors_heatmap_share.png")
def main() -> None: def main() -> None:
@ -17,6 +18,7 @@ def main() -> None:
plot_translucent_share(TIMELINE_PATH, TRANSLUCENT_DESTINATION) plot_translucent_share(TIMELINE_PATH, TRANSLUCENT_DESTINATION)
plot_colors_heatmap(MATRIX_PATH, HEATMAP_LINEAR_DESTINATION, use_log_scale=False) plot_colors_heatmap(MATRIX_PATH, HEATMAP_LINEAR_DESTINATION, use_log_scale=False)
plot_colors_heatmap(MATRIX_PATH, HEATMAP_LOG_DESTINATION, use_log_scale=True) plot_colors_heatmap(MATRIX_PATH, HEATMAP_LOG_DESTINATION, use_log_scale=True)
plot_colors_heatmap(MATRIX_PATH, HEATMAP_SHARE_DESTINATION, normalize_by_year=True)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -28,8 +28,9 @@ def test_plot_translucent_share(tmp_path: Path) -> None:
def test_plot_colors_heatmap(tmp_path: Path) -> None: def test_plot_colors_heatmap(tmp_path: Path) -> None:
"""Génère une heatmap année × couleur.""" """Génère une heatmap année × couleur."""
matrix_path = tmp_path / "colors_year_color_matrix.csv" matrix_path = tmp_path / "colors_year_color_matrix.csv"
destination_linear = tmp_path / "figures" / "step14" / "colors_heatmap_linear.png" destination_linear = tmp_path / "figures" / "step15" / "colors_heatmap_linear.png"
destination_log = tmp_path / "figures" / "step14" / "colors_heatmap_log.png" destination_log = tmp_path / "figures" / "step15" / "colors_heatmap_log.png"
destination_share = tmp_path / "figures" / "step15" / "colors_heatmap_share.png"
matrix_path.write_text( matrix_path.write_text(
"year,color_rgb,is_translucent,color_name,quantity_total\n" "year,color_rgb,is_translucent,color_name,quantity_total\n"
"2020,AAAAAA,false,Gray,5\n" "2020,AAAAAA,false,Gray,5\n"
@ -40,8 +41,11 @@ def test_plot_colors_heatmap(tmp_path: Path) -> None:
plot_colors_heatmap(matrix_path, destination_linear, use_log_scale=False) plot_colors_heatmap(matrix_path, destination_linear, use_log_scale=False)
plot_colors_heatmap(matrix_path, destination_log, use_log_scale=True) plot_colors_heatmap(matrix_path, destination_log, use_log_scale=True)
plot_colors_heatmap(matrix_path, destination_share, normalize_by_year=True)
assert destination_linear.exists() assert destination_linear.exists()
assert destination_linear.stat().st_size > 0 assert destination_linear.stat().st_size > 0
assert destination_log.exists() assert destination_log.exists()
assert destination_log.stat().st_size > 0 assert destination_log.stat().st_size > 0
assert destination_share.exists()
assert destination_share.stat().st_size > 0