spb/traite-evaluation-qc
Public
1#!/usr/bin/env python32"""Figure ch03 — Modèle des quatre quadrants (DiPasquale–Wheaton) tracé à partir des paramètres pédagogiques du marché type3(analysis/python/cases/ch03_cycles.py, SYNTHÉTIQUE). Équilibre de référence (trait plein) et nouvel équilibre après une baisse4du taux de capitalisation de 5 % à 4 % (tirets), avec la réaction de court terme (stock fixe) en pointillé.5Sortie : assets/figures/ch03/ch03-fig-quatre-quadrants.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 traite.style import setup, palette, savefig, LARGEUR11import ch03_cycles as cas121314def main():15 setup()16 p = cas.Parametres4Q()17 base = cas.equilibre_4q(p)18 i2 = 0.0419 nouv = cas.equilibre_4q(p, i=i2)20 ct = cas.court_terme_4q(p, i=i2)21 k = 1000.0 # affichage en milliers22 c0, c1 = palette.cat[0], palette.cat[1]23 fig, ax = plt.subplots(figsize=(LARGEUR, LARGEUR * 0.92))24 # bornes25 Smax, Pmax, Rmax, Cmax = 150, 420, 25, 3.226 ax.set_xlim(-Pmax, Smax); ax.set_ylim(-Cmax, Rmax)27 ax.axhline(0, color=palette.ink, lw=0.9); ax.axvline(0, color=palette.ink, lw=0.9)28 ax.grid(False)29 for s in ("left", "bottom"):30 ax.spines[s].set_visible(False)31 ax.set_xticks([]); ax.set_yticks([])32 # --- NE : marché de l'espace, D(R) = S → R = (a − S)/b33 S = np.linspace(60, 150, 50) * k34 ax.plot(S / k, (p.a - S) / p.b / k, color=c0, lw=1.8)35 ax.plot(S / k, (1.0 * p.a - S) / p.b / k, color=c0, lw=0, label="_")36 # --- NW : marché des actifs, P = R / i (P à gauche, R en haut)37 R = np.linspace(0, Rmax, 50) * k38 ax.plot(-R / p.i / k, R / k, color=c0, lw=1.8)39 ax.plot(-R / i2 / k, R / k, color=c1, lw=1.8, ls="--")40 # --- SW : construction, C = (P − c0)/c1 (P à gauche, C en bas)41 P = np.linspace(p.c0, Pmax * k, 50)42 ax.plot(-P / k, -(P - p.c0) / p.c1 / k, color=c0, lw=1.8)43 # --- SE : ajustement du stock, S = C/δ (C en bas, S à droite)44 C = np.linspace(0, Cmax, 50) * k45 ax.plot(C / p.delta / k, -C / k, color=c0, lw=1.8)4647 def rectangle(eq, color, ls, lw=1.0):48 Sx, Rx, Px, Cx = eq["S"] / k, eq["R"] / k, eq["P"] / k, eq["C"] / k49 ax.plot([Sx, Sx], [0, Rx], color=color, lw=lw, ls=ls)50 ax.plot([-Px, Sx], [Rx, Rx], color=color, lw=lw, ls=ls)51 ax.plot([-Px, -Px], [Rx, -Cx], color=color, lw=lw, ls=ls)52 ax.plot([-Px, Sx], [-Cx, -Cx], color=color, lw=lw, ls=ls)53 ax.plot([Sx, Sx], [-Cx, 0], color=color, lw=lw, ls=ls)5455 rectangle(base, c0, "-")56 rectangle(nouv, c1, "--")57 # court terme : stock fixe, prix bondit à R0/i258 ax.plot([-ct["P"] / k, base["S"] / k], [base["R"] / k, base["R"] / k], color=c1, lw=1.0, ls=":")59 ax.plot([-ct["P"] / k, -ct["P"] / k], [base["R"] / k, -ct["C"] / k], color=c1, lw=1.0, ls=":")60 ax.plot([-ct["P"] / k, base["S"] / k], [-ct["C"] / k, -ct["C"] / k], color=c1, lw=1.0, ls=":")61 # points62 ax.plot(base["S"] / k, base["R"] / k, "o", color=c0, ms=4); ax.plot(nouv["S"] / k, nouv["R"] / k, "o", color=c1, ms=4)63 ax.plot(-base["P"] / k, base["R"] / k, "o", color=c0, ms=4); ax.plot(-nouv["P"] / k, nouv["R"] / k, "o", color=c1, ms=4)64 ax.plot(-ct["P"] / k, base["R"] / k, "o", color=c1, ms=4, mfc="white")65 # étiquettes d'axes et de quadrants66 ax.text(Smax, 0.6, "Stock $S$ (milliers de log.)", ha="right", va="bottom", fontsize=8)67 ax.text(-Pmax, 0.6, "Prix $P$ (k\\$/log.)", ha="left", va="bottom", fontsize=8)68 ax.text(1.5, Rmax, "Loyer $R$ (k\\$/log./an)", ha="left", va="top", fontsize=8)69 ax.text(1.5, -Cmax, "Construction $C$ (milliers de log./an)", ha="left", va="bottom", fontsize=8)70 ax.text(Smax * 0.98, Rmax * 0.93, "Marché de l'espace\n$D(R) = S$", ha="right", va="top", fontsize=8, color=palette.ink2)71 ax.text(-Pmax * 0.98, Rmax * 0.93, "Marché des actifs\n$P = R/i$", ha="left", va="top", fontsize=8, color=palette.ink2)72 ax.text(-Pmax * 0.98, -Cmax * 0.93, "Construction\n$C = (P - c_0)/c_1$", ha="left", va="bottom", fontsize=8, color=palette.ink2)73 ax.text(Smax * 0.98, -Cmax * 0.93, "Ajustement du stock\n$\\Delta S = C - \\delta S = 0$", ha="right", va="bottom", fontsize=8, color=palette.ink2)74 # annotations numériques75 ax.annotate(f"$S^*$ = {base['S']/k:.0f}", xy=(base["S"] / k, 0), xytext=(base["S"] / k + 2, 1.2), fontsize=7.5, color=c0)76 ax.annotate(f"{nouv['S']/k:.1f}", xy=(nouv["S"] / k, 0), xytext=(nouv["S"] / k + 2, 3.4), fontsize=7.5, color=c1)77 ax.annotate(f"$R^*$ = {base['R']/k:.1f}", xy=(0, base["R"] / k), xytext=(3, base["R"] / k + 0.6), fontsize=7.5, color=c0)78 ax.annotate(f"{nouv['R']/k:.1f}", xy=(0, nouv["R"] / k), xytext=(3, nouv["R"] / k - 1.9), fontsize=7.5, color=c1)79 ax.annotate(f"$P^*$ = {base['P']/k:.0f}", xy=(-base["P"] / k, 0), xytext=(-base["P"] / k - 6, 1.2), fontsize=7.5, color=c0, ha="right")80 ax.annotate(f"court terme : {ct['P']/k:.0f}", xy=(-ct["P"] / k, 0), xytext=(-ct["P"] / k - 4, -0.9), fontsize=7.5, color=c1, ha="right", va="top")81 ax.annotate(f"$C^*$ = {base['C']/k:.1f}", xy=(0, -base["C"] / k), xytext=(3, -base["C"] / k - 0.1), fontsize=7.5, color=c0, va="top")82 from matplotlib.lines import Line2D83 h = [Line2D([], [], color=c0, lw=1.8, label="équilibre de référence ($i$ = 5 %)"),84 Line2D([], [], color=c1, lw=1.8, ls="--", label="nouvel équilibre de long terme ($i$ = 4 %)"),85 Line2D([], [], color=c1, lw=1.0, ls=":", label="court terme (stock fixe)")]86 ax.legend(handles=h, loc="lower center", bbox_to_anchor=(0.5, -0.06), ncol=3, fontsize=7.5, frameon=False)87 out = savefig(fig, "ch03/ch03-fig-quatre-quadrants.pdf"); print("OK", out)888990if __name__ == "__main__":91 main()92