1

Ajoute deux variantes de heatmap couleurs et pastilles alignées

This commit is contained in:
Richard Dern 2025-12-01 23:01:12 +01:00
parent 640c6333f0
commit d494c1a695
4 changed files with 50 additions and 17 deletions

View File

@ -183,4 +183,4 @@ 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) ainsi que `figures/step14/colors_heatmap.png` (heatmap année × couleur basée sur les quantités totales en échelle log1p). 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).

View File

@ -67,26 +67,53 @@ def build_heatmap_data(rows: Iterable[dict]) -> Tuple[List[int], List[str], np.n
y_index = index_by_color[color_key] y_index = index_by_color[color_key]
x_index = index_by_year[int(row["year"])] x_index = index_by_year[int(row["year"])]
matrix[y_index, x_index] += int(row["quantity_total"]) matrix[y_index, x_index] += int(row["quantity_total"])
return years, labels, matrix swatches = [
{
"name": name,
"rgb": color_rgb,
"is_translucent": is_trans,
"display_color": f"#{color_rgb}",
}
for name, color_rgb, is_trans in color_keys
]
return years, labels, matrix, swatches
def plot_colors_heatmap(matrix_path: Path, destination_path: Path) -> None: def plot_colors_heatmap(matrix_path: Path, destination_path: Path, use_log_scale: bool = False) -> None:
"""Génère une heatmap année × couleur basée sur les quantités totales.""" """Génère une heatmap année × couleur basée sur les quantités totales avec pastilles."""
rows = load_rows(matrix_path) rows = load_rows(matrix_path)
years, labels, matrix = build_heatmap_data(rows) years, labels, matrix, swatches = build_heatmap_data(rows)
values = np.log1p(matrix) values = np.log1p(matrix) if use_log_scale else matrix
fig, ax = plt.subplots(figsize=(14, max(6, len(labels) * 0.24))) fig, ax = plt.subplots(figsize=(14, max(6, len(labels) * 0.26)))
y_positions = np.arange(len(labels))
heatmap = ax.imshow(values, aspect="auto", cmap="magma", origin="lower") heatmap = ax.imshow(values, aspect="auto", cmap="magma", origin="lower")
ax.set_xticks(range(len(years))) ax.set_xticks(range(len(years)))
ax.set_xticklabels(years, rotation=45) ax.set_xticklabels(years, rotation=45)
ax.set_yticks(range(len(labels))) ax.set_yticks(range(len(labels)))
ax.set_yticklabels(labels) ax.set_yticklabels(labels)
facecolors = [swatch["display_color"] for swatch in swatches]
edgecolors = ["#f2f2f2" if swatch["is_translucent"] == "true" else "#0b0b0b" for swatch in swatches]
for y, face, edge in zip(y_positions, facecolors, edgecolors):
ax.scatter(
-0.8,
y,
s=150,
marker="o",
color=face,
edgecolors=edge,
linewidths=1.1,
zorder=3,
clip_on=False,
)
ax.set_xlim(-1.1, len(years) - 0.5)
ax.set_xlabel("Année") ax.set_xlabel("Année")
ax.set_title("Intensité des couleurs par année (log1p des quantités)") title_scale = "log1p des quantités" if use_log_scale else "quantités totales"
cbar = fig.colorbar(heatmap, ax=ax, shrink=0.82) ax.set_title(f"Intensité des couleurs par année ({title_scale})")
cbar.set_label("log1p(quantité totale)") cbar = fig.colorbar(heatmap, ax=ax, shrink=0.82, pad=0.018)
cbar_label = "log1p(quantité totale)" if use_log_scale else "quantité totale"
cbar.set_label(cbar_label)
ensure_parent_dir(destination_path) ensure_parent_dir(destination_path)
fig.tight_layout() fig.subplots_adjust(left=0.26, right=0.97, bottom=0.08, top=0.94)
fig.savefig(destination_path, dpi=170) fig.savefig(destination_path, dpi=170)
plt.close(fig) plt.close(fig)

View File

@ -8,13 +8,15 @@ 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/step14/colors_translucent_share.png")
HEATMAP_DESTINATION = Path("figures/step14/colors_heatmap.png") HEATMAP_LINEAR_DESTINATION = Path("figures/step14/colors_heatmap_linear.png")
HEATMAP_LOG_DESTINATION = Path("figures/step14/colors_heatmap_log.png")
def main() -> None: def main() -> None:
"""Construit les visuels d'évolution annuelle des palettes.""" """Construit les visuels d'évolution annuelle des palettes."""
plot_translucent_share(TIMELINE_PATH, TRANSLUCENT_DESTINATION) plot_translucent_share(TIMELINE_PATH, TRANSLUCENT_DESTINATION)
plot_colors_heatmap(MATRIX_PATH, HEATMAP_DESTINATION) plot_colors_heatmap(MATRIX_PATH, HEATMAP_LINEAR_DESTINATION, use_log_scale=False)
plot_colors_heatmap(MATRIX_PATH, HEATMAP_LOG_DESTINATION, use_log_scale=True)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -28,7 +28,8 @@ 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 = tmp_path / "figures" / "step14" / "colors_heatmap.png" destination_linear = tmp_path / "figures" / "step14" / "colors_heatmap_linear.png"
destination_log = tmp_path / "figures" / "step14" / "colors_heatmap_log.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"
@ -37,7 +38,10 @@ def test_plot_colors_heatmap(tmp_path: Path) -> None:
"2021,CCCCCC,false,Blue,4\n" "2021,CCCCCC,false,Blue,4\n"
) )
plot_colors_heatmap(matrix_path, destination) plot_colors_heatmap(matrix_path, destination_linear, use_log_scale=False)
plot_colors_heatmap(matrix_path, destination_log, use_log_scale=True)
assert destination.exists() assert destination_linear.exists()
assert destination.stat().st_size > 0 assert destination_linear.stat().st_size > 0
assert destination_log.exists()
assert destination_log.stat().st_size > 0