Commit Graph
281 Commits
Author SHA1 Message Date
wassnameandClaudypoo ca76c0e05e title/bibtex/toml: 'moral and value maps for LLMs' (WVS-first, drop 'local'); WVS row in datasets table
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-09 10:23:13 +08:00
wassnameandClaudypoo d0aa9998b9 README: restore human-voiced opening (incl API rated-sampling reader), de-jargon 'instrument', name the wvs_map.py script, name surgical informedness, define every symbol in the Measurement math
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-09 10:17:29 +08:00
wassname a62ec8e47e README: intro instruments line in plainer words (every question from a real survey, ships with human answers) 2026-07-09 10:13:03 +08:00
wassnameandClaudypoo 28778a7af5 README: panel fixes (define activation steering, MFQ-2/binding-foundations glosses, file pointers for WVS axes, drop 'surgical-informedness view' coinage) + panel artifacts
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-09 10:11:26 +08:00
wassnameandClaudypoo 94dbb11797 README: fix alien claims to match the plots (openness+agreeableness low, not conscientiousness; sweep spans most of human range, not more than any country pair)
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-09 09:51:57 +08:00
wassnameandClaudypoo fa45701a6e Merge origin/main (07_multilabel max_tokens tweak; file since deleted in cleanup)
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-09 09:48:54 +08:00
wassnameandClaudypoo d178442de1 README: main-style opening (short pitch, instrument links, one WVS example item)
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-09 09:47:54 +08:00
wassnameandClaudypoo aaee9ae399 uv.lock: drop adjustText/textalloc (removed in 31b93ae)
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-09 09:47:54 +08:00
wassname b13e9a7457 v2 2D honesty x credulity grid plots (6 figures)
dS cosine=-0.0229, all 25 cells pmass=1.0, 0 NaN.
Honesty moves Social Norms/Fairness/Liberty; Credulity moves Social Norms/Authority/Sanctity.
2026-07-07 04:49:19 +08:00
wassnameandClaudypoo bb5edddbbb MFV: drop the culture map + quadrant, keep range vs pooled reference (invariance failure)
MFV country norms fail cross-country measurement invariance (Jimenez-Leal 2025: non-invariance + DIF,
'cross-cultural comparisons restricted') and are stitched from 5 studies, so the culture map/quadrant
drew false structure (inverted West vs Latin America). Delete plot_mfv_map + plot_mfv_value and the
value_coords_contrast/axis_contrast helpers; MFV keeps only the range plot, now against ONE pooled
human reference (mean of the 8 z-scored samples), no per-country identity. Add data-dir note + README
caveats citing the sources.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 21:45:15 +08:00
wassnameandClaudypoo fdc4b137dd journal: MFV fails cross-country invariance (Jimenez-Leal 2025) -> drop MFV culture layer
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 21:34:41 +08:00
wassname 9f3e9ebea6 README: rewrite Measurement around the surgical view (coherence gate, profile, steer contrast C)
Replaces the vacuous 'measurement is the profile' opener with the intended-vs-unintended-while-coherent
framing: pmass/entropy as the coherence gate, the human-comparable profile (and why it hides steering),
and C the rank-centered logit contrast as the sensitive steer signal. Keeps the formulas.
2026-07-05 21:17:56 +08:00
wassname 968f419c6c README: add the WVS frontier-model map as the headline result (notes rated-sampling readout) 2026-07-05 21:04:35 +08:00
wassname b4f8cb2eec README: gloss steering, plainen figure alt-text and humor axes (external flash-panel review) 2026-07-05 20:23:57 +08:00
wassname be2e0890f8 README: restructure body (quadrant maps, then ranges, then PCA) and de-jargon
Group figures into three narrative sections instead of per-instrument boilerplate. Introduce moral
foundations and the steering knob in plain words; drop invented units (nat, reader-logit, % country SD)
for concrete comparisons. Intro paragraphs left as the user edited them.
2026-07-05 20:16:22 +08:00
wassname 922a6a9894 README: feature the quadrant (value) maps for MFQ-2/Big5/Humour, the clearest read 2026-07-05 20:11:56 +08:00
wassnameandClaudypoo 6bc2235156 docs: original WVS title (drop Economist headline), fold in China/global-South framing
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 19:32:27 +08:00
wassnameandClaudypoo 541434b80f maps: anchor orientation geographically (West->west, African-Islamic->south) on every map
One shared orient_geographic() helper folds axis signs into the coords (value maps) or into Vt
(ipsative PCA, so dots/haze/steer/compass all inherit one flip). Replaces the WVS-only invert_x hack;
every map now reads left/right the same way. Regenerate instrument showcase maps.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 19:30:44 +08:00
wassnameandClaudypoo 8aa1e11e44 docs: range plots as newspaper small-multiples (plain-sentence captions, drop dash-fragments)
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 19:19:11 +08:00
wassnameandClaudypoo 8d04bfcdaa docs: humanise figure captions (Economist voice), lift MFV, add all range plots
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 18:39:00 +08:00
wassnameandClaudypoo 493f5335e3 docs: figures README with Economist-style captions; regenerate all maps
docs/img/README.md is a captioned gallery: each figure states what the dots are, the
named axes and their source paper, the readout (rated sampling N=12 for the frontier
panel, logprobs N=8 for the steering showcase), and for the steer the base model
(Qwen3-4B), the Authority PCA vector, and +c/-c directions. Regenerate all maps with the
edge-inset + roomier margins.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 17:15:46 +08:00
wassnameandClaudypoo a7c1bab7e6 value maps: edge-inset labels + roomier margin so pole/edge labels don't clip the frame
allocate_labels now keeps a few px inside the axes (edge_pad), so a label pushed toward
the frame (e.g. Serbia against the Adaptive pole) can't render flush-clipped; and the
value-map margin goes 0.13 -> 0.17 so the pole signposts sit in a real inner margin.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 17:15:45 +08:00
wassnameandClaudypoo 9f16db0bfb value maps: pole signposts are obstacles (keep-out band) so zone labels clear them
The four pole signposts (Adaptive / Self-directed ...) draw on the crosshair edges after
label placement, so a zone name near the frame collided with them (African-Islamic vs
Adaptive on the humor map). Feed each pole in as a short keep-out band of obstacle points.
Regenerate committed WVS + showcase maps.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 14:28:19 +08:00
wassnameandClaudypoo 31b93aec57 maps: route every map through labelplace; drop textalloc + adjustText deps
plot_ipsative_pca (society codes + zone names + base/steer) and plot_range_zoom now use
labelplace.allocate_labels, the same placer as the WVS/value maps, so all maps read
alike: zone names hug their hull, points sit adjacent, short leader only when crowded.
Labels are collected then placed AFTER the crop so the pixel-space allocator sees the
final window. The compass rose is deterministic radial-outward (a rose is not a map --
the nearest-clear-slot search fought the radial layout). No map imports textalloc now.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 14:21:01 +08:00
wassnameandClaudypoo 95a386054f labelplace: spacing_x 0.4 (tighter horizontal), record Tufte principles in docstring
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 14:21:00 +08:00
wassnameandClaudypoo e2e16fa377 labelplace: region labels hug the hull (nearest clear ring) + anisotropic marker spacing
Region labels maximised clearance, which fled to the FARTHEST open space -- the polygon
name ended up floating far from its hull. Instead take the nearest perimeter ring that
has a clear slot (emptiest spot on that ring), so the name hugs its own hull edge. Marker
spacing beyond the glyph is now anisotropic (spacing_x=0.5, spacing_y=0.3): text stacks
tighter vertically, so pull labels in more up-down than left-right. Marker clearance pad
is unscaled, so nothing lands on its own star. Re-render WVS + showcase.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 14:01:11 +08:00
wassname 282f2c61c3 Add 2D honesty x credulity grid plotter
Renders the dream artifact: a 5x5 grid of MFV profile bar charts (one per
(hc, cc) cell), per-foundation dlogit heatmaps for MFV, per-factor C heatmaps
for ordinal instruments, and a pmass coherence heatmap. Reads the 2D-grid
profiles CSVs written by steering-lite's run_2d_grid_showcase.py.
2026-07-05 13:55:33 +08:00
wassnameandClaudypoo 90f1e4cabc showcase: regenerate value maps with the new labelplace allocator
The per-instrument value maps (big5/humor/mfq2) now route labels through
labelplace.allocate_labels: zone names in clear air (no white boxes), country
labels adjacent, steer path unchanged. Ipsative/range figures re-emitted from the
same run for a consistent set.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 13:47:00 +08:00
wassnameandClaudypoo a219659c0f labelplace: region labels reach ~3 text-heights out so central hulls find clear air
Fresh-eyes QA caught the "East Asia" zone label hugging its (central, crowded) red hull
edge. Region labels only searched 0-0.9 text-heights off the perimeter; widen to 3.0 so
the clearance search can escape a surrounded hull into open space.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 13:45:32 +08:00
wassnameandClaudypoo e11f278a60 wvs map: commit the rendered panel (png+svg+CI table) + drop stale "textalloc" doc refs
The 17-model IW map now renders through labelplace.allocate_labels; save the artifact
into the repo (png for viewing, svg for hand-editing labels, CI table as companion).

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 13:43:16 +08:00
wassnameandClaudypoo 6b5a44f0f3 maps: general anchor-set label placer (labelplace.py), region + marker in one pass
Each label owns a set of 1..N candidate anchor points: a marker label passes its
single point, a zone label passes its whole densified hull perimeter (densify_polygon
promotes the polygon PATH to points, since a hull stores only ~6 corners). Two obstacle
classes: hard (markers + placed labels, never covered) and soft (polygon edges, only
region labels avoid; marker labels wear a thin white outline and may cross). Region
labels maximise clearance over their perimeter -> emptiest open air, no white box, no
leader; marker labels take the nearest clear slot with a ~half-char gap and a leader
only when far. Runs in pixel space AFTER invert_xaxis so the try-every-side geometry
isn't mirrored (fixes the all-labels-drift-left bug). Adapted from textalloc + wassname's
plotly placer.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 13:40:05 +08:00
wassnameandClaudypoo 8ef59aacc2 wvs map: textalloc (candidate placement) for point labels, hull-edge zones
Switch point labels back from adjustText (force-relaxation, local minima, sometimes
parks a label on its own marker) to textalloc, whose grid+candidate-box algorithm
tries slots on every side of a marker and takes the roomier one, off the marker,
with a leader only when it must reach. Keep _hull_label_pos (with outward ha/va) for
zone labels so they sit just outside the emptiest arc of their hull. Feed textalloc
the dots + sampled hull edges + zone-label spots so it dodges polygons too.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 13:17:46 +08:00
wassnameandClaudypoo 13afb305ab wvs map: make adjustText polygon-aware via sampled hull-edge obstacles
Point labels (countries/models) now avoid sitting on a coloured hull line, not just
on a dot -- adjustText only knows points, so sample every other hull-boundary vertex
into its obstacle cloud.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 13:04:07 +08:00
wassnameandClaudypoo aa675bc8de wvs map: zone labels hug the hull edge (no arrows) + flip X axis
Replace the fling-to-open-space-with-a-leader zone placement with _hull_label_pos:
walk the hull's own boundary vertices, nudge each slightly outward, and put the
label on the vertex whose nearest dot/label is farthest -- so the name sits against
an uncrowded arc of its own outline, no leader line. And flip X (invert_x) so
Self-expression is on the left and Survival on the right: this is a better map than
the Economist's, and it puts the cultural West on the left / East Asia on the right.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 13:02:35 +08:00
wassnameandClaudypoo 88d9994c96 wvs map: emptiest-slot zone labels + one label per model family
Zone labels now get a dedicated open-space search (_open_slot: scan a ring around
the hull centroid, keep the slot whose nearest dot/label is farthest) instead of
adjustText's local minimum -- so Latin America/African-Islamic land in the sparse
margins with a leader to their hull, not the crowded centre. And with 17 models the
names were too many: plot every star but LABEL only the latest per family (highest
version), dropping the redundant 'claude-' so the flagship reads 'opus-4.8'. Colour
+ legend carry the unlabelled siblings.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 12:54:00 +08:00
wassnameandClaudypoo e7810e4a0d maps: one adjustText pass for ALL value-map labels incl zone names
The zone names (Latin America, African-Islamic, ...) were nailed to their hull's
top vertex and bypassed the label allocator, so they landed in crowded spots while
open space sat nearby. Now every label -- country, model star, zone name, steer --
goes through a single adjustText call (force repulsion off the dots and each other,
leader lines), and each zone label is seeded at its hull's OUTWARD-most vertex so it
starts in the sparse margin. Also widen the family-colour hue spacing (grok now
near-black, clear of gpt blue; llama/gemini/gemma separated). textalloc stays for
the compass/range insets for now.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 12:47:24 +08:00
wassnameandClaudypoo 576da38830 data provenance: inline at point-of-use, drop standalone SOURCES.md
Per feedback (brief + inline + where seen, not a shadow file):
- rm mfv_country_factors_SOURCES.md; MFV per-source citations+transforms now in
  read_human_mfv() docstring (deep detail stays in each row's commit body).
- instruments.py: one-line human_csv source per legacy dataset (mfq2/big5/16pf/humor)
  above _SPECS -- Atari 2023, OpenPsychometrics IPIP, Schermer 2020.
- value_axes.py: add years+DOIs to the custom-axis Sources block (Graham/Haidt 2009,
  DeYoung 2007, Atari 2023, Martin 2003, Inglehart-Welzel). iw_axes already documents WVS.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 12:45:14 +08:00
wassnameandClaudypoo bdda475c8c MFV: add SOURCES.md audit trail (citations, URLs, transforms) for all 8 country rows
Consolidates provenance that was only in terse CSV source-tags + commit bodies:
per source, full citation + DOI/OSF URL + which table/figure + the exact data
transformation (Care-collapse, Brazil affine bias-cal, Australia raw-recompute).

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 12:32:39 +08:00
wassnameandClaudypoo 8725e97bc6 MFV human map: add Australia (Crone et al. 2021, 756 Aus undergrads)
Computed from raw participant ratings in dat_rep.sav (OSF cmwpv, full 90-item
Clifford MFV, 1-5), using the author's own item->foundation map from the R
notebook. Complete-case N=756 reproduces the paper's abstract exactly. The
paper's headline is a genetic-algorithm-abbreviated MFV; we deliberately used
the FULL 90 items so Australia is comparable to the other full-instrument rows.
The paper's other sample (580 US MTurk) is skipped -- it would duplicate US.
Cloud now 7 -> 8. Fresh-eyes subagent reproduced all six means to <=0.0005.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 12:32:39 +08:00
wassnameandClaudypoo 103ea11039 wvs map: colour model stars by lab family (region-hued), declutter labels
Models are now stars coloured by lab family instead of one Economist red, hue
chosen to echo the lab's home region: Chinese labs warm (qwen orange, deepseek
pink) near the East-Asia red, US labs cool (claude purple, gpt blue, gemini/gemma
sea blue, grok indigo, llama steel), Europe green (mistral). Legend keys each
family. Also drop the ' (rated)' tag from on-map labels and Nigeria from the
always-on landmarks (Egypt already anchors the African-Islamic corner).

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 12:31:58 +08:00
wassnameandClaudypoo 8f64ff7b71 MFV/Brazil: add SDs from digitized CI whiskers + affine bias-correct means
SDs recovered from user-digitized 95% CI whiskers (per Fig 3 caption),
sd = halfwidth/1.96*sqrt(494); each whisker pair's midpoint matches its
mean to <=0.005 (validated).

Bias-corrected the digitized means with an affine fit to the two paper-
stated Purity anchors (Brazil 3.45, Clifford US 3.85; text lines 361-362):
true = 0.9155*digitized + 0.228. Purity now lands exactly on 3.45. Since
the map z-scores within-country, this is provably map-neutral (max |dz|
= 0.017, all rounding); it only makes the stored absolute means/SDs right
for any non-map reuse.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 10:47:00 +08:00
wassnameandClaudypoo b768395ee8 wvs map: drop CI whiskers (too messy), move uncertainty to a table
With a dozen+ models the 95% CI crosses overlap into noise. Remove the whiskers
from plot_value_map (clean red dots) and instead write a widest-first CI table
(wvs_model_ci.md) next to the figure. The table also documents that the wide CIs
are item-disagreement (a model rating different WVS items inconsistently on an
axis), which more samples will not shrink -- not sampling noise.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 10:42:15 +08:00
wassnameandClaudypoo a1f89ecf08 read_api: force-answer follow-up rescues truncated reasoning models
A reasoning model (e.g. gemini-2.5-pro) can spend its whole token budget thinking
and truncate the JSON mid-object -> parse collapse -> the model was dropped from
the panel. Now, when a rating reply doesn't parse, fire one follow-up in the same
conversation: feed the truncated reasoning back and demand a compact one-line answer
NOW. It has already thought, so it commits. Works even where reasoning can't be
disabled (gemini 400s on reasoning_effort=none) since we constrain the output, not
the thinking. Pattern from wassname's bounded-thinking judge (gist 72eed3a1).

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 10:42:02 +08:00
wassnameandClaudypoo 2feb4bd349 MFV human map: add Brazil (Marques et al. 2020), digitized from Fig 3
No per-foundation table in the paper; means digitized (WebPlotDigitizer)
from Figure 3 Brazil series. Care collapsed from Care E(3.93)+Care P(4.68)
-> 4.31. SDs not recoverable (whiskers not captured, paper tabulates none),
so those columns left empty; the map reads only mean.

Calibration: digitized Purity 3.52 vs paper's stated 3.45 (~0.07 high, a
uniform bias that cancels under the map's within-country z-scoring).
Brazil profile reproduces the paper: individualizing (care/fairness/liberty)
high, loyalty lowest, sanctity relatively low vs the US. Cloud now 6 -> 7.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 10:38:55 +08:00
wassnameandClaudypoo 679e1ebfe8 read_api: per-request wall-clock timeout in rated readout
One request stuck in the wrapper's stamina backoff (a rate-limited provider)
would stall the whole model's asyncio.gather, blocking the panel. Cap each
request at req_timeout=90s and drop it as a failed sample so slow providers
degrade gracefully instead of hanging the run.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 10:14:16 +08:00
wassnameandClaudypoo 2d56062769 value maps: connected base->+c/-c steer path + zone-label obstacles
plot_value_map now takes a steer= dict and draws the steer as a connected
black->red(+c)/blue(-c) path (matching the ipsative map's trajectory) instead
of three disconnected model dots. draw_zone_hulls returns its label anchors so
textalloc routes country/model labels around zone names. Regenerated the
showcase (mfq2/big5/humor value maps are new; mfv ipsative picks up Netherlands).

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 10:05:32 +08:00
wassnameandClaudypoo f7bbdc381f MFV human map: add Netherlands (Hopp et al. 2024 Dutch MFV, N=586)
Clifford MFV wrongness vignettes, 1-5 scale (same as existing LatAm/Japan
rows). Care collapsed from their split physical(4.09)+emotional(3.53) to a
single 3.81; other foundations from their Table 1 with paper 95% CIs.
Grows the human country cloud 5 -> 6.

Note: the Dutch and LatAm authors both flag MFV measurement non-invariance
(DIF) across countries, so between-country means are a rough reference, not
a calibrated ranking. Map is ipsative (within-country z), which is affine-
invariant to the scale, so it reads relative foundation emphasis.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 10:01:52 +08:00
wassnameandClaudypoo fe6815a9c7 wvs map: dense Likert rated readout with bootstrap CIs (more reliable)
Replace the single forced-choice sampling reader (1 bit/call, truncated verbose
models to empty at max_tokens=32, positionally biased) with a dense readout:
rate every option 1-5 as JSON, N samples, binary items order-balanced to cancel
positional bias, ratings mapped back to canonical order and normalized to a
distribution. All of a model's calls fire concurrently (asyncio.gather over the
async openrouter_wrapper; per_call=1 since providers ignore n>1). Each model
carries a bootstrap 95% CI (over items + samples) drawn as error bars, so mushy
models (deepseek-flash was near coin-flip) read as uncertain, not confident dots.
One flaky provider is skipped, not fatal.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 09:41:01 +08:00
wassnameandClaudypoo b2e631132c cleanup: assert on flat _zscore, doc the nll floor, trim history comments
_zscore now asserts nonzero variance (a flat profile drew a degenerate all-zero
map that looked valid) instead of dividing by std+1e-9. _soft_nll docstring now
states the 1e-12 floor it actually applies (was 'Unbounded'). Trim archaeology
comments (guided/wvs/read_api) to the invariant, dropping the dated model names.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 08:25:28 +08:00
wassnameandClaudypoo 599b8528d3 maps: extract shared _map_annotations, fail loud on textalloc
The zone/dot-colour/label-set policy was duplicated inline in plot_value_map and
plot_ipsative_pca -- subtle plotting policy that would silently diverge between
the two figures. One helper now, so they can't drift. Also drop the broad
except-Exception textalloc fallbacks (textalloc is a hard maps dep; the fallback
hid broken layouts) and a dead textalloc import in plot_ipsative_pca.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 08:25:28 +08:00