Spaces:
Runtime error
Runtime error
| """Shared chart styling: palette, matplotlib defaults and figure saving.""" | |
| from pathlib import Path | |
| import matplotlib as mpl | |
| import matplotlib.pyplot as plt | |
| # --- Diverging poles for sentiment polarity --- | |
| NEGATIVE = "#e34948" # red pole | |
| NEUTRAL = "#898781" # neutral gray midpoint | |
| POSITIVE = "#2a78d6" # blue pole | |
| #: Sentiment label -> colour. | |
| SENTIMENT_COLORS = { | |
| "Negative": NEGATIVE, | |
| "Neutral": NEUTRAL, | |
| "Positive": POSITIVE, | |
| } | |
| # --- Categorical slots (first three validate on all pairs) --- | |
| SERIES = ("#2a78d6", "#eb6834", "#1baf7a") | |
| # --- Sequential blue ramp, light -> dark (magnitude) --- | |
| SEQUENTIAL = ["#cde2fb", "#b7d3f6", "#9ec5f4", "#86b6ef", "#6da7ec", | |
| "#5598e7", "#3987e5", "#2a78d6", "#256abf", "#1c5cab", | |
| "#184f95", "#104281", "#0d366b"] | |
| # --- Chrome and ink --- | |
| SURFACE = "#fcfcfb" | |
| INK = "#0b0b0b" | |
| INK_SECONDARY = "#52514e" | |
| INK_MUTED = "#898781" | |
| GRIDLINE = "#e1e0d9" | |
| BASELINE = "#c3c2b7" | |
| ACCENT = "#2a78d6" | |
| #: Default folder for saved charts. | |
| PLOTS_SUBDIR = "plots" | |
| def sequential_cmap(): | |
| """Return the one-hue blue ramp as a matplotlib colormap.""" | |
| return mpl.colors.LinearSegmentedColormap.from_list("asa_blue", SEQUENTIAL) | |
| def apply_chart_style(): | |
| """Set matplotlib defaults: thin marks, hairline solid grid, recessive axes.""" | |
| mpl.rcParams.update({ | |
| "figure.facecolor": SURFACE, | |
| "axes.facecolor": SURFACE, | |
| "savefig.facecolor": SURFACE, | |
| "font.family": ["DejaVu Sans"], | |
| "font.size": 10, | |
| "text.color": INK, | |
| "axes.labelcolor": INK_SECONDARY, | |
| "axes.edgecolor": BASELINE, | |
| "axes.linewidth": 0.8, | |
| "axes.titlecolor": INK, | |
| "axes.titlesize": 12, | |
| "axes.titleweight": "normal", # DejaVu has no medium; avoids a warning | |
| "axes.titlepad": 12, | |
| "axes.grid": True, | |
| "axes.axisbelow": True, | |
| "grid.color": GRIDLINE, | |
| "grid.linewidth": 0.8, | |
| "grid.linestyle": "-", # never dashed - dashes read as a threshold | |
| "xtick.color": INK_MUTED, | |
| "ytick.color": INK_MUTED, | |
| "xtick.labelcolor": INK_SECONDARY, | |
| "ytick.labelcolor": INK_SECONDARY, | |
| "xtick.direction": "out", | |
| "ytick.direction": "out", | |
| "legend.frameon": False, | |
| "legend.fontsize": 9, | |
| "figure.autolayout": False, | |
| }) | |
| def strip_spines(ax, keep=("left", "bottom")): | |
| """Remove chart-junk spines, keeping only the ones that carry meaning.""" | |
| for side, spine in ax.spines.items(): | |
| spine.set_visible(side in keep) | |
| def finish(fig, save_path=None, show=True, dpi=150): | |
| """Save and/or show ``fig``, then close it when it is not being shown.""" | |
| fig.tight_layout() | |
| written = None | |
| if save_path is not None: | |
| written = Path(save_path) | |
| written.parent.mkdir(parents=True, exist_ok=True) | |
| fig.savefig(written, dpi=dpi, bbox_inches="tight") | |
| if show: | |
| plt.show() | |
| else: | |
| plt.close(fig) | |
| return written | |