SPB Git
7.2 KB · 125 lines python
1#!/usr/bin/env python32"""Chapitre 10 — figures Matplotlib :3  ch10-fig-chronologie-cadres.pdf   chronologie documentaire des cadres normatifs (dates du registre C) ;4  ch10-fig-matrice-normes.pdf       statistiques descriptives de la matrice des dispositions (sources/normes-C.csv) ;5  ch10-fig-grille-controle.pdf      grille de détection des douze éléments dans quatre extraits FICTIFS.6Usage (racine du dépôt) : PYTHONPATH=analysis/python python3 analysis/python/figures/ch10_figures.py"""7from __future__ import annotations8import sys, pathlib, datetime as dt9import matplotlib.pyplot as plt10import matplotlib.dates as mdates11from matplotlib.lines import Line2D12from matplotlib.patches import Patch1314sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))15sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / "cases"))16from traite.style import setup, palette, savefig, LARGEUR17import ch10_matrice_normes as mn18import ch10_controle_rapport as cr1920def fig_chronologie(ch):21    fig, ax = plt.subplots(figsize=(LARGEUR, 4.0))22    ch = ch.copy()23    ch["ordre"] = ch["effet"].rank(method="first")24    ch = ch.sort_values("effet")25    col = {"en_vigueur": palette.cat[0], "remplace": palette.ink2, "projet": palette.cat[1], "reference": palette.cat[2]}26    fin_axe = dt.date(2028, 6, 30)27    labels = []28    for i, (_, r) in enumerate(ch.iterrows()):29        c = col[r["statut"]]30        fin = r["fin"] if r["fin"] is not None else (r["effet"] if r["statut"] == "projet" else fin_axe)31        ls = ":" if r["statut"] == "projet" else "-"32        if r["statut"] != "projet":33            ax.plot([r["effet"], fin], [i, i], color=c, lw=2.2, solid_capstyle="butt", alpha=0.9 if r["statut"] != "remplace" else 0.6)34        if r["publication"] is not None:35            ax.plot([r["publication"], r["effet"]], [i, i], color=c, lw=1.0, ls=ls)36            ax.plot(r["publication"], i, marker="o", mfc="white", mec=c, ms=5.5, mew=1.3)37        ax.plot(r["effet"], i, marker="o", color=c, ms=5.5)38        if r["statut"] == "projet":39            ax.plot(r["effet"], i, marker="o", mfc="white", mec=c, ms=5.5, mew=1.3)40        if r["fin"] is not None:41            ax.plot(r["fin"], i, marker="|", color=c, ms=9, mew=1.6)42        labels.append(r["cadre"] + (" *" if r.get("verification") == "partielle" else ""))43    ax.axvline(mn.DATE_REF, color=palette.ink2, lw=0.8, ls="--")44    ax.text(mn.DATE_REF, len(ch) - 0.4, " 31 oct. 2026", fontsize=7.5, color=palette.ink2, va="bottom")45    ax.set_yticks(range(len(ch))); ax.set_yticklabels(labels, fontsize=8)46    ax.tick_params(axis="y", length=0)47    ax.set_ylim(-0.7, len(ch) - 0.3)48    ax.set_xlim(dt.date(2012, 6, 1), fin_axe)49    ax.xaxis.set_major_locator(mdates.YearLocator(2)); ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y"))50    ax.grid(axis="y", visible=False)51    for s in ("left",): ax.spines[s].set_visible(False)52    h = [Line2D([0], [0], color=col["en_vigueur"], lw=2.2, label="en vigueur au 31 oct. 2026"),53         Line2D([0], [0], color=col["remplace"], lw=2.2, alpha=0.6, label="remplacé"),54         Line2D([0], [0], color=col["reference"], lw=2.2, label="norme de référence (IAAO)"),55         Line2D([0], [0], color=col["projet"], lw=1.0, ls=":", marker="o", mfc="white", label="projet (date proposée)"),56         Line2D([0], [0], color=palette.ink2, lw=0, marker="o", mfc="white", mec=palette.ink2, label="publication → entrée en vigueur")]57    ax.legend(handles=h, loc="upper center", bbox_to_anchor=(0.5, -0.14), fontsize=7.5, ncol=3, frameon=False)58    ax.set_xlabel("Année")59    savefig(fig, "ch10/ch10-fig-chronologie-cadres.pdf")6061def fig_matrice(st):62    fig, (a1, a2) = plt.subplots(1, 2, figsize=(LARGEUR, 2.9), gridspec_kw={"width_ratios": [1.15, 1]})63    fam = st["par_famille"].sort_values()64    couleurs = [palette.cat[0] if f.startswith("OEAQ") else palette.ink2 for f in fam.index]65    a1.barh(fam.index, fam.values, color=couleurs, height=0.62)66    for y, v in enumerate(fam.values):67        a1.text(v + 0.6, y, str(v), va="center", fontsize=8, color=palette.ink)68    a1.set_xlabel("Dispositions (n = %d)" % st["n"]); a1.set_xlim(0, fam.max() * 1.18)69    a1.set_title("Par famille de sources", loc="left", fontsize=9)70    a1.grid(axis="y", visible=False)71    top = st["par_chapitre"].head(10).sort_values()72    couleurs2 = [palette.cat[0] if c == "ch10" else palette.ink2 for c in top.index]73    a2.barh([c.replace("ch", "ch. ") for c in top.index], top.values, color=couleurs2, height=0.62)74    for y, v in enumerate(top.values):75        a2.text(v + 0.6, y, str(v), va="center", fontsize=8, color=palette.ink)76    a2.set_xlabel("Renvois vers le chapitre"); a2.set_xlim(0, top.max() * 1.18)77    a2.set_title("Dix chapitres les plus visés", loc="left", fontsize=9)78    a2.grid(axis="y", visible=False)79    fig.tight_layout(w_pad=2.0)80    savefig(fig, "ch10/ch10-fig-matrice-normes.pdf")8182LIBELLES_COURTS = {1: "Identification physique et légale", 2: "Droits de propriété évalués", 3: "But et fin de l'évaluation",83                   4: "Définition de la valeur", 5: "Date d'évaluation", 6: "Étendue du travail", 7: "Réserves et hypothèses",84                   8: "Information et raisonnement", 9: "Usage le meilleur et le plus profitable", 10: "Rejet d'une méthode",85                   11: "Conformité et écarts aux directives", 12: "Attestation"}8687def fig_grille(out):88    extraits = list(cr.EXTRAITS.keys())89    fig, ax = plt.subplots(figsize=(LARGEUR, 3.4))90    for j, e in enumerate(cr.ELEMENTS):91        for i, nom in enumerate(extraits):92            strict = out["controle"][(nom, "strict")][e.cle][0]93            souple = out["controle"][(nom, "souple")][e.cle][0]94            if strict:95                ax.scatter(i, j, s=120, marker="s", color=palette.cat[0], zorder=3)96            elif souple:97                ax.scatter(i, j, s=120, marker="s", facecolor="white", edgecolor=palette.cat[1], linewidth=1.6, zorder=3)98            else:99                ax.scatter(i, j, s=40, marker="x", color=palette.ink2, linewidth=1.0, zorder=3)100    ax.set_xticks(range(len(extraits)))101    ax.set_xticklabels([f"Extrait {n}\n{out['taux'][(n,'strict')]*12:.0f}/12 (strict)" for n in extraits], fontsize=8)102    ax.set_yticks(range(len(cr.ELEMENTS)))103    ax.set_yticklabels([f"{e.no}. {LIBELLES_COURTS[e.no]}" for e in cr.ELEMENTS], fontsize=7.5)104    ax.invert_yaxis(); ax.set_xlim(-0.6, len(extraits) - 0.4)105    ax.grid(False)106    for s in ("left", "bottom"): ax.spines[s].set_visible(False)107    ax.tick_params(length=0)108    h = [Line2D([0], [0], marker="s", color=palette.cat[0], lw=0, ms=8, label="détecté (lexique strict)"),109         Line2D([0], [0], marker="s", mfc="white", mec=palette.cat[1], mew=1.6, lw=0, ms=8, label="détecté seulement par le lexique souple"),110         Line2D([0], [0], marker="x", color=palette.ink2, lw=0, ms=6, label="non détecté")]111    ax.legend(handles=h, loc="upper center", bbox_to_anchor=(0.5, -0.16), ncol=3, fontsize=7.5, frameon=False)112    savefig(fig, "ch10/ch10-fig-grille-controle.pdf")113114def main():115    setup()116    res = mn.main(verbose=False)117    out = cr.main(verbose=False)118    fig_chronologie(res["chronologie"])119    fig_matrice(res["stats"])120    fig_grille(out)121    print("figures du chapitre 10 écrites dans assets/figures/ch10/")122123if __name__ == "__main__":124    main()125
Files · d2b579d9e218b409826a327e9268215b1d11dd98
Menu

Theme