spb/wp10_uqo Public
UQO Working Paper No. 10 — The assessment gap in Quebec: vertical and horizontal inequity in municipal property assessment.
TeX 55.9%
Python 44%
1# Author: Simon-Pierre Boucher — contact@spboucher.ai2"""Shared matplotlib style for all WP10 figures — print-journal calibre.34Conventions (Journal of Finance house style):5 - no titles inside figures (captions carry the message); multi-panel6 figures use bold "Panel A." headers set flush left above each axes;7 - Times-compatible serif text with STIX math, 8–9 pt;8 - thin, recessive axes (0.6 pt), outward ticks, no top/right spines;9 - one accent hue per figure; a second hue only for genuine polarity or a10 second series, always doubled by a linestyle/marker difference;11 - shaded confidence bands rather than cap-heavy error bars;12 - direct labels instead of legend boxes wherever the geometry allows.1314The two data hues (#2e6da4, #c04848) pass the full colour-vision validation15suite (lightness band, chroma floor, CVD separation, contrast) on a white16surface; INK and GREY are reserved for marks-as-ink and reference lines.17"""18import matplotlib1920matplotlib.use("Agg")21import matplotlib.pyplot as plt # noqa: E4022223INK = "#1a1a1a" # primary marks (points, bars, text)24BLUE = "#2e6da4" # accent series / fitted lines25RED = "#c04848" # contrast series / polarity26GREY = "#8a8a8a" # reference lines27LIGHT = "#d9d9d9" # fills, bands28GRID = "#e3e3e3" # gridlines2930# Sequential blues for ordered series (light → dark, one hue)31BLUES = ["#c6d7e8", "#9dbcd8", "#74a1c8", "#4b86b8", "#2e6da4", "#1d4a75"]3233TEXTWIDTH = 6.3 # \textwidth in inches (1in margins, letter paper)343536def apply_style() -> None:37 plt.rcParams.update({38 "font.family": "serif",39 "font.serif": ["Times New Roman", "Times", "STIXGeneral", "DejaVu Serif"],40 "mathtext.fontset": "stix",41 "font.size": 9,42 "axes.labelsize": 9,43 "xtick.labelsize": 8,44 "ytick.labelsize": 8,45 "legend.fontsize": 8,46 "figure.dpi": 150,47 "savefig.dpi": 300,48 "axes.spines.top": False,49 "axes.spines.right": False,50 "axes.linewidth": 0.6,51 "xtick.major.width": 0.6,52 "ytick.major.width": 0.6,53 "xtick.major.size": 3,54 "ytick.major.size": 3,55 "xtick.direction": "out",56 "ytick.direction": "out",57 "axes.grid": False,58 "grid.color": GRID,59 "grid.linewidth": 0.5,60 "legend.frameon": False,61 "lines.linewidth": 1.3,62 "lines.markersize": 4.5,63 "figure.constrained_layout.use": False,64 })656667def panel_label(ax, text: str) -> None:68 """Bold flush-left panel header above the axes (JoF style)."""69 ax.set_title(text, loc="left", fontsize=9, fontweight="bold", pad=8)707172def ygrid(ax) -> None:73 """Recessive horizontal gridlines drawn beneath the data."""74 ax.grid(axis="y", linewidth=0.5, color=GRID)75 ax.set_axisbelow(True)76