Arabic-Sentiment-Analysis / utils /chart_style.py
mhamza-007's picture
Upload 56 files
d840583 verified
Raw
History Blame Contribute Delete
3.02 kB
"""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