SPB Git
3.1 KB · 66 lines python
1"""Style graphique du traité (Matplotlib). Palette validée : styles/palette.json.2Usage :3    from traite.style import setup, palette, savefig, LARGEUR, DEMI4    setup(); fig, ax = plt.subplots(figsize=(LARGEUR, 3.2)); ... savefig(fig, "ch16/ch16-fig-x.pdf")"""5from __future__ import annotations6import json, pathlib7import matplotlib as mpl8import matplotlib.pyplot as plt9from matplotlib import font_manager1011ROOT = pathlib.Path(__file__).resolve().parents[3]12_P = json.loads((ROOT / "styles/palette.json").read_text())13LARGEUR = 135 / 25.4   # pouces (pleine largeur de texte)14DEMI = 65 / 25.41516class _Palette:17    cat = _P["categorical"]; seq = _P["sequential_blue"]; div = _P["diverging"]; status = _P["status"]18    surface = _P["surface"]; ink = _P["text_primary"]; ink2 = _P["text_secondary"]; grid = _P["grid"]19    brand = _P["brand_primary"]; brand2 = _P["brand_secondary"]20    @staticmethod21    def cmap_seq(): return mpl.colors.LinearSegmentedColormap.from_list("traite_seq", _P["sequential_blue"])22    @staticmethod23    def cmap_div(): d = _P["diverging"]; return mpl.colors.LinearSegmentedColormap.from_list("traite_div", [d["neg"], d["mid"], d["pos"]])24palette = _Palette()2526def _register_fonts():27    import subprocess28    for name in ("SourceSans3-Regular.otf", "SourceSans3-Bold.otf", "SourceSans3-It.otf", "SourceSans3-Semibold.otf"):29        try:30            p = subprocess.run(["kpsewhich", name], capture_output=True, text=True, timeout=10).stdout.strip()31            if p: font_manager.fontManager.addfont(p)32        except Exception:33            pass3435def setup():36    _register_fonts()37    fam = "Source Sans 3" if any(f.name == "Source Sans 3" for f in font_manager.fontManager.ttflist) else "DejaVu Sans"38    mpl.rcParams.update({39        "font.family": fam, "font.size": 8.5, "axes.titlesize": 9, "axes.labelsize": 8.5, "legend.fontsize": 8,40        "xtick.labelsize": 8, "ytick.labelsize": 8, "figure.facecolor": palette.surface, "axes.facecolor": palette.surface,41        "savefig.facecolor": palette.surface, "axes.edgecolor": palette.ink2, "axes.labelcolor": palette.ink,42        "xtick.color": palette.ink2, "ytick.color": palette.ink2, "text.color": palette.ink,43        "axes.spines.top": False, "axes.spines.right": False, "axes.grid": True, "grid.color": palette.grid,44        "grid.linewidth": 0.6, "axes.axisbelow": True, "lines.linewidth": 1.6, "lines.markersize": 5,45        "axes.prop_cycle": mpl.cycler(color=palette.cat), "legend.frameon": False, "figure.dpi": 150,46        "pdf.fonttype": 42, "axes.formatter.use_locale": False, "axes.unicode_minus": True,47    })4849def fmt_dollars(x, pos=None):50    """Formate 452500 → « 452 500 $ » (espace fine insécable)."""51    s = f"{x:,.0f}".replace(",", " ")52    return f"{s} $"5354def fmt_milliers(x, pos=None):55    return f"{x:,.0f}".replace(",", " ")5657def fmt_pct(x, pos=None, dec=1):58    return (f"{x*100:.{dec}f}".replace(".", ",")) + " %"5960def savefig(fig, rel_path: str, **kw):61    out = ROOT / "assets/figures" / rel_path62    out.parent.mkdir(parents=True, exist_ok=True)63    fig.savefig(out, bbox_inches="tight", **kw)64    plt.close(fig)65    return out66
Files · b89896847ac1aae8938f8bc73852056ce0ce4556
Menu

Theme