#!/usr/bin/env python3 """Figure ch24 — sensibilité (DONNÉES SYNTHÉTIQUES, cas 1, graine 20261031) : (a) taux de dépréciation âge-vie modifiée selon la vie économique et l'âge effectif ; (b) tornade de l'indication par le coût du sujet. Sortie : assets/figures/ch24/ch24-fig-sensibilite.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 numpy as np, matplotlib.pyplot as plt from traite.style import setup, palette, savefig, LARGEUR, fmt_dollars import ch24_depreciation as cas 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) sx = cas.sensibilite_extraction(d["ventes"], d["modele"], d["cn"]["total"]) to = cas.tornade(d["cn"], vlr["retenue"], vs["d_extraite"], se["desuetude"], var, sx) vies = (50, 60, 70, 80, 100); ages = (20, 25, 29, 33, 37) G = cas.grille_age_vie(d["cn"], var["curable"], vies, ages).values * 100 fig, (a, b) = plt.subplots(2, 1, figsize=(LARGEUR, 5.4), gridspec_kw={"hspace": 0.5, "height_ratios": [1.15, 1]}) im = a.imshow(G, cmap=palette.cmap_seq(), aspect="auto", origin="upper", vmin=15, vmax=80) a.set_xticks(range(len(ages))); a.set_xticklabels([str(x) for x in ages]); a.set_yticks(range(len(vies))); a.set_yticklabels([str(v) for v in vies]) a.set_xlabel("Âge effectif de la structure (ans)"); a.set_ylabel("Vie économique (ans)"); a.grid(False) for i in range(len(vies)): for j in range(len(ages)): a.text(j, i, f"{G[i, j]:.0f}", ha="center", va="center", fontsize=7.5, color="white" if G[i, j] > 45 else palette.ink) a.set_title("(a) Âge-vie modifiée, % du coût neuf", loc="left", fontsize=9) base = to[0]["base"] ordre = sorted(range(len(to)), key=lambda i: abs(to[i]["haut"] - to[i]["bas"])) for k, i in enumerate(ordre): o = to[i]; lo, hi = min(o["bas"], o["haut"]), max(o["bas"], o["haut"]) b.barh(k, hi - lo, left=lo, color=palette.cat[0] if k < len(ordre) - 1 else palette.cat[1], height=0.6) b.text(lo - 3000, k, fmt_dollars(lo).replace("$", r"\$"), ha="right", va="center", fontsize=7, color=palette.ink) b.text(hi + 3000, k, fmt_dollars(hi).replace("$", r"\$"), ha="left", va="center", fontsize=7, color=palette.ink) b.axvline(base, color=palette.ink2, lw=0.8, ls="--") b.set_yticks(range(len(ordre))); b.set_yticklabels([to[i]["param"].replace(" au lieu de l'extraction", "") for i in ordre], fontsize=7.5) b.set_xlim(400000, 680000); b.xaxis.set_major_formatter(plt.FuncFormatter(fmt_dollars)); b.grid(axis="y", visible=False) b.set_xlabel(f"Indication par le coût (base {fmt_dollars(base)})".replace("$", r"\$")); b.set_title("(b) Tornade de l'indication par le coût", loc="left", fontsize=9) out = savefig(fig, "ch24/ch24-fig-sensibilite.pdf"); print("OK", out) if __name__ == "__main__": main()