#!/usr/bin/env python3 """Figure ch24 — décomposition de la valeur par le coût du sujet du cas 1 (DONNÉES SYNTHÉTIQUES, graine 20261031) : (a) lecture ventilée (ch. 11) : coût neuf − curable − courte durée − longue durée − désuétude fonctionnelle ; (b) lecture retenue : coût neuf − dépréciation extraite du marché − désuétude fonctionnelle + valeur du terrain = indication. Sortie : assets/figures/ch24/ch24-fig-decomposition.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 esc = lambda t: t.replace("$", r"\$") import ch24_depreciation as cas def cascade(ax, etapes, titre): """etapes : liste de (nom, montant, type) avec type ∈ {'total', 'moins', 'plus', 'resultat'}.""" cum = 0.0; xs = []; for i, (nom, m, t) in enumerate(etapes): if t == "total": ax.bar(i, m, color=palette.cat[0], width=0.62); cum = m; top = m elif t == "moins": ax.bar(i, -m, bottom=cum, color=palette.cat[1], width=0.62); cum -= m; top = cum + m elif t == "plus": ax.bar(i, m, bottom=cum, color=palette.cat[2], width=0.62); cum += m; top = cum else: ax.bar(i, m, color=palette.cat[4], width=0.62); top = m signe = "−" if t == "moins" else ("+" if t == "plus" else "") ax.text(i, top + 9000, esc(f"{signe}{fmt_dollars(m)}"), ha="center", va="bottom", fontsize=7, color=palette.ink) xs.append(nom) if i < len(etapes) - 1 and t != "resultat": ax.plot([i + 0.31, i + 1 - 0.31], [cum, cum], color=palette.ink2, lw=0.6) ax.set_xticks(range(len(etapes))); ax.set_xticklabels(xs, fontsize=7.5, rotation=0) ax.yaxis.set_major_formatter(plt.FuncFormatter(fmt_dollars)) ax.set_ylim(0, 760000); ax.grid(axis="x", visible=False) ax.set_title(esc(titre), loc="left", fontsize=9) def main(): setup() d = cas.charger() var = cas.variantes_physique(d["cn"], d["fiche"], d["travaux"]) se = cas.carence_salle_eau(d["devis"], d["cn"]) w, vl = cas.extraction(d["ventes"], d["modele"], d["cn"]["total"]) q = cas.ajuster_profil(w)["quadratique"]; vlr = cas.valeur_terrain_retenue(vl) vs = cas.valeur_sujet(d["cn"], vlr["retenue"], q, se["desuetude"], var) ve = var["ventilee"]; cn = d["cn"]["total"] fig, (a, b) = plt.subplots(2, 1, figsize=(LARGEUR, 5.6), gridspec_kw={"hspace": 0.42}) cascade(a, [("Coût neuf", cn, "total"), ("Curable", ve["curable"], "moins"), ("Courte durée", sum(ve["courte_duree"].values()), "moins"), ("Longue durée", ve["longue_duree"], "moins"), ("Fonctionnelle", se["desuetude"], "moins"), ("Contribution\ndu bâtiment", vs["A_ventilee"]["contribution_batiment"], "resultat")], f"(a) Lecture ventilée : dépréciation totale {vs['A_ventilee']['taux_depreciation']*100:.1f} %") cascade(b, [("Coût neuf", cn, "total"), ("Extraite (28 ans)", vs["d_extraite"], "moins"), ("Fonctionnelle", se["desuetude"], "moins"), ("Terrain", vlr["retenue"], "plus"), ("Indication\npar le coût", vs["B_extraction"]["valeur"], "resultat")], f"(b) Lecture retenue : dépréciation {vs['B_extraction']['taux_depreciation']*100:.1f} %, valeur {fmt_dollars(vs['valeur_arrondie'])}") out = savefig(fig, "ch24/ch24-fig-decomposition.pdf"); print("OK", out) if __name__ == "__main__": main()