SPB Git
3.1 KB · 41 lines python
1#!/usr/bin/env python32"""Figure ch23 — sensibilité (DONNÉES SYNTHÉTIQUES, cas 1 ; taux documenté Banque du Canada V80691335) :3(a) intérêts intérimaires selon la durée du chantier et le taux (tirage uniforme, L·i·T/2) ;4(b) tornade du coût neuf : durée, taux intérimaire, indirects hors financement, hausse salariale (λ = 40 %), incitatif.5Sortie : assets/figures/ch23/ch23-fig-sensibilite.pdf"""6import sys, pathlib7ROOT = pathlib.Path(__file__).resolve().parents[3]8sys.path.insert(0, str(ROOT / "analysis/python")); sys.path.insert(0, str(ROOT / "analysis/python/cases"))9import numpy as np, matplotlib.pyplot as plt10from matplotlib.ticker import FuncFormatter11from traite.style import setup, palette, savefig, LARGEUR, fmt_milliers12import ch21_cout_neuf as c21, ch23_structure_couts as cas1314def main():15    setup()16    devis, sujet = c21.charger(); cn = c21.cout_neuf_sujet(devis); i_aff = cas.taux_affiche_5ans()17    fc = cas.financement_cas1(devis, cn, i_aff); base = fc["base_hors_financement"]18    mois = np.arange(3, 25); taux = [0.04, 0.05, i_aff, 0.07, 0.09]19    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(LARGEUR, 3.4), gridspec_kw={"width_ratios": [1, 1.25]})20    for k, t in enumerate(taux):21        ax1.plot(mois, [cas.fin.interets_intermediaires(base, t, m / 12)["interets"] / 1000 for m in mois], color=palette.cat[k], lw=2.0 if abs(t - i_aff) < 1e-6 else 1.2, label=f"{t*100:.2f} %".replace(".", ","))22    ax1.axhline(fc["forfait"] / 1000, color=palette.ink2, lw=0.8, ls="--"); ax1.text(3.2, fc["forfait"] / 1000 + 0.3, f"forfait du devis {fc['forfait']/1000:.1f} k$".replace(".", ","), fontsize=6.8, color=palette.ink2, ha="left", va="bottom")23    ax1.set_xlabel("Durée du chantier (mois)"); ax1.set_ylabel("Intérêts intérimaires (k$)"); ax1.set_title("(a) Intérêts selon durée et taux", loc="left")24    ax1.legend(title="Taux annuel", fontsize=7, title_fontsize=7, loc="upper left")25    torn = cas.tornade(devis, cn, i_aff); base_cn = torn[0]["base"]26    torn = sorted(torn, key=lambda o: abs(o["haut"] - o["bas"]))27    y = np.arange(len(torn))28    for yi, o in zip(y, torn):29        lo, hi = min(o["bas"], o["haut"]), max(o["bas"], o["haut"])30        ax2.barh(yi, (hi - lo) / 1000, left=lo / 1000, color=palette.cat[0], height=0.55)31        ax2.text(lo / 1000 - 1, yi, f"{lo/1000:.0f}", ha="right", va="center", fontsize=7); ax2.text(hi / 1000 + 1, yi, f"{hi/1000:.0f}", ha="left", va="center", fontsize=7)32    ax2.axvline(base_cn / 1000, color=palette.ink2, lw=0.8); ax2.text(base_cn / 1000, -0.95, f"base {base_cn/1000:.1f} k$".replace(".", ","), ha="center", va="bottom", fontsize=7, color=palette.ink2); ax2.set_ylim(-1.1, len(torn) - 0.5)33    ax2.set_yticks(y); ax2.set_yticklabels([f"{o['param']}\n{o['etiquette']}" for o in torn], fontsize=7)34    ax2.set_xlabel("Coût neuf (k$)"); ax2.set_title("(b) Tornade du coût neuf", loc="left"); ax2.set_xlim(365, 430)35    ax2.xaxis.set_major_formatter(FuncFormatter(fmt_milliers)); ax2.grid(axis="y", visible=False)36    fig.tight_layout(w_pad=2.0)37    out = savefig(fig, "ch23/ch23-fig-sensibilite.pdf"); print("OK", out)3839if __name__ == "__main__":40    main()41
Files · fd7f44c8789c8b7d81811c1898b290bc997b5c13
Menu

Theme