#!/usr/bin/env python3 """Figure ch21 — décomposition du coût neuf du sujet du cas 1 par corps de métier (DONNÉES SYNTHÉTIQUES, graine 20261031). Sortie : assets/figures/ch21/ch21-fig-decomposition-corps.pdf""" import sys, pathlib ROOT = pathlib.Path(__file__).resolve().parents[3] sys.path.insert(0, str(ROOT / "analysis/python")); sys.path.insert(0, str(ROOT / "analysis/python/cases")) import matplotlib.pyplot as plt from traite.style import setup, palette, savefig, LARGEUR, fmt_dollars import ch21_cout_neuf as cas def main(): setup() devis, sujet = cas.charger(); g = cas.regrouper(devis); cn = cas.cout_neuf_sujet(devis) noms = list(g.index) + ["Incitatif de l'entrepreneur (10 %)"] vals = list(g["montant"]) + [cn["incitatif"]] couleurs = [palette.cat[0]] * 6 + [palette.cat[1], palette.cat[3]] ordre = sorted(range(len(vals)), key=lambda i: vals[i]) fig, ax = plt.subplots(figsize=(LARGEUR, 3.4)) y = range(len(ordre)) ax.barh(list(y), [vals[i] for i in ordre], color=[couleurs[i] for i in ordre], height=0.68) ax.set_yticks(list(y)); ax.set_yticklabels([noms[i] for i in ordre]) tot = cn["total"] for k, i in enumerate(ordre): ax.text(vals[i] + 1200, k, f"{fmt_dollars(vals[i])} ({vals[i]/tot*100:.1f} %)", va="center", ha="left", fontsize=8, color=palette.ink) ax.set_xlim(0, max(vals) * 1.42) ax.xaxis.set_major_formatter(plt.FuncFormatter(fmt_dollars)) ax.set_xlabel("Montant (dollars de 2026)") ax.grid(axis="y", visible=False) ax.set_title(f"Coût neuf total : {fmt_dollars(tot)} — directs {cn['direct']/tot*100:.1f} %, indirects {cn['indirects']/tot*100:.1f} %, incitatif {cn['incitatif']/tot*100:.1f} %", loc="left", fontsize=8.5, color=palette.ink) from matplotlib.patches import Patch ax.legend(handles=[Patch(color=palette.cat[0], label="Coûts directs (six corps de métier)"), Patch(color=palette.cat[1], label="Coûts indirects (cinq postes)"), Patch(color=palette.cat[3], label="Incitatif de l'entrepreneur")], loc="upper center", bbox_to_anchor=(0.42, -0.16), ncol=3, fontsize=7.5) out = savefig(fig, "ch21/ch21-fig-decomposition-corps.pdf"); print("OK", out) if __name__ == "__main__": main()