#!/usr/bin/env python3 """Figure ch44 — VAN des deux mesures selon le taux d'actualisation et la croissance du prix de l'électricité (DONNÉES SYNTHÉTIQUES, hypothèses de analysis/python/cases/ch44_renovation.py). Cartes de chaleur divergentes centrées sur VAN = 0 avec la courbe d'équilibre. Sortie : assets/figures/ch44/ch44-fig-heatmap-van.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 matplotlib.colors import TwoSlopeNorm from traite.style import setup, palette, savefig, LARGEUR import ch44_renovation as cas TAUX = np.array([0.02, 0.03, 0.04, 0.0458, 0.05, 0.06, 0.07, 0.08, 0.10]) CROIS = np.array([0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06]) def panneau(ax, m, titre, vmax): G = cas.grille_van(m, taux=tuple(TAUX), croissances=tuple(CROIS)).values norm = TwoSlopeNorm(vmin=-vmax, vcenter=0.0, vmax=vmax) # colormap divergente du traité : négatif = bleu, positif = rouge → ici on inverse pour que le positif (VAN > 0) soit bleu cmap = palette.cmap_div().reversed() ax.imshow(G, cmap=cmap, norm=norm, aspect="auto", origin="upper") ax.set_xticks(range(len(CROIS))); ax.set_xticklabels([f"{g*100:.0f} %" for g in CROIS]) ax.set_yticks(range(len(TAUX))); ax.set_yticklabels([f"{r*100:.2f} %".replace(".", ",") if r == 0.0458 else f"{r*100:.0f} %" for r in TAUX]) ax.grid(False) for i in range(len(TAUX)): for j in range(len(CROIS)): v = G[i, j] ax.text(j, i, f"{v/1000:+.1f}".replace(".", ",").replace("-", "−"), ha="center", va="center", fontsize=6.8, color="white" if abs(v) > 0.55 * vmax else palette.ink) # courbe d'équilibre sur une grille fine (interpolée sur les indices de cellules) rf = np.linspace(TAUX[0], TAUX[-1], 60); gf = np.linspace(CROIS[0], CROIS[-1], 60) Z = np.array([[cas.flux_mesure(m, r=r, g=g)["van"] for g in gf] for r in rf]) xi = np.interp(gf, CROIS, np.arange(len(CROIS))); yi = np.interp(rf, TAUX, np.arange(len(TAUX))) if (Z.min() < 0) and (Z.max() > 0): ax.contour(xi, yi, Z, levels=[0.0], colors=[palette.ink], linewidths=1.3) ax.set_xlabel("Croissance annuelle du prix de l'électricité"); ax.set_title(titre, loc="left", fontsize=9) def main(): setup() mm = cas.mesures() fig, (a, b) = plt.subplots(1, 2, figsize=(LARGEUR, 3.5), gridspec_kw={"wspace": 0.30}) panneau(a, mm["A"], "(a) Thermopompe climat froid — VAN (k$)", 10000.0) panneau(b, mm["B"], "(b) Isolation de l'entretoit — VAN (k$)", 4000.0) a.set_ylabel("Taux d'actualisation") out = savefig(fig, "ch44/ch44-fig-heatmap-van.pdf"); print("OK", out) if __name__ == "__main__": main()