wvs_map: bake title + repo attribution inside the axes, add top headroom

Draw the title and github.com/wassname/moral-maps note in the empty bottom-left
INSIDE the axes so a crop can't strip attribution and there's no whitespace band.
Give the models overlay extra top headroom so the most-secular model stars and
their labels seat inside the frame instead of spilling above it. Regenerate PNG+SVG.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
This commit is contained in:
wassname
2026-07-09 16:02:29 +08:00
co-authored by Claudypoo
parent 48dcec6300
commit cfd334512a
4 changed files with 12017 additions and 11038 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 303 KiB

After

Width:  |  Height:  |  Size: 350 KiB

+12001 -11032
View File
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 413 KiB

After

Width:  |  Height:  |  Size: 434 KiB

+6 -2
View File
@@ -285,7 +285,9 @@ def main() -> None:
# Render through the SHARED value-map renderer (same one the instrument value maps use): pole
# signposts through the human median, 4 auto-selected zone hulls, auto-placed labels, model stars.
_, emph = zones_for(countries)
# Title + caption live in the README (nicer voice, editable), not baked into the figure.
# The hero map (unlike the instrument maps) bakes on a title + an attribution note carrying the
# repo URL, so copies shared around the web stay credited and self-explanatory. Everything else
# still leans on the README voice.
# Drop the " (rated)" readout tag from the on-map labels (the cache/CI-table keep it) -- the map is
# crowded and every model here is rated, so the tag adds nothing.
plot_models = {k.replace(" (rated)", ""): v for k, v in models.items()}
@@ -305,7 +307,9 @@ def main() -> None:
fig = maps.plot_value_map(
"WVS Inglehart-Welzel", countries, P,
("Survival", "Self-expression", "Traditional", "Secular-Rational"),
models=plot_models, model_labels=model_labels, emphasize=emph)
models=plot_models, model_labels=model_labels, emphasize=emph,
title="Frontier LLMs on the\nWorld Values Survey",
note="17 models, rated sampling\ngithub.com/wassname/moral-maps")
fig.savefig(args.out, dpi=200, bbox_inches="tight")
logger.info(f"wrote {args.out}")
+10 -4
View File
@@ -369,6 +369,9 @@ def plot_value_map(display: str, countries: list[str], P: np.ndarray,
ax.margins(0.17) # roomy edges: the pole signposts sit in the inner
ax.autoscale(False) # margin and edge labels (Serbia, Adaptive) need to fit.
if models: # the WVS overlay stacks the most-secular model stars
y0, y1 = ax.get_ylim() # against the top edge; add top headroom so their
ax.set_ylim(y0, y1 + 0.22 * (y1 - y0)) # stars + labels seat INSIDE the frame. -- Claude
# Orientation is already baked into the coords (orient_geographic above), so the pixel-space label
# allocator sees the final left/right; no ax.invert_xaxis() that would mirror every placed label.
# ONE placement pass for everything (see labelplace.allocate_labels). Each zone name is a REGION
@@ -403,12 +406,15 @@ def plot_value_map(display: str, countries: list[str], P: np.ndarray,
# NO legend: each model family already has a directly-placed, family-coloured label on the map, so a
# swatch legend would just duplicate that ink (Tufte eraser test). Grey dots read as societies from
# the labelled examples (Sweden, Japan...); the count lives in the README caption.
# Title + caption are OFF by default -- the README carries the headline + sources (nicer voice
# there than baked jargon). Pass title/note only for a standalone figure.
# Title + caption default OFF (the README carries them). When passed (the hero WVS map) draw them
# INSIDE the axes, in the empty bottom-left corner, so a crop of the PNG can't strip the attribution
# and there's no external white band. -- Claude
if title:
ax.set_title(title, fontsize=12, loc="left")
ax.text(0.012, 0.075, title, transform=ax.transAxes, ha="left", va="bottom",
fontsize=11, fontweight="bold", color="#333", zorder=11, linespacing=1.05)
if note:
fig.text(0.02, 0.015, note, ha="left", va="bottom", fontsize=7.5, color="#999")
ax.text(0.012, 0.02, note, transform=ax.transAxes, ha="left", va="bottom",
fontsize=7.5, color="#8a857a", zorder=11, linespacing=1.1)
return fig