Fix compass orientation and simplify CI display
- Lock x_label/y_label to Links-Rechts / Progressief-Conservatief after classify_axes; Procrustes sign-fixing in compute_2d_axes already ensures the correct orientation so the heuristic _should_swap_axes call is removed - Remove visual error bars from party axis chart; 95% CI is now shown in hover text (party: score, N=n, 95%-BI: [low, high]) to keep the 1D scatter clean - Remove show_ci checkbox and parameter — CI is always accessible on hover - Update tests to match new hover format and absence of error_x
This commit is contained in:
@@ -88,15 +88,18 @@ class TestBuildPartyAxisFigure:
|
||||
fig = _build_party_axis_figure({}, comp_sel=1, theme=_make_theme())
|
||||
assert fig is None
|
||||
|
||||
def test_with_bootstrap_has_error_x_and_diamonds(self):
|
||||
"""Call WITH bootstrap_data → error_x on marker trace, diamond for N=1."""
|
||||
def test_with_bootstrap_has_diamonds_for_single_mp(self):
|
||||
"""bootstrap_data present → N=1 party gets diamond, others get circle. No error bars."""
|
||||
from explorer import _build_party_axis_figure
|
||||
|
||||
party_scores = _make_party_scores()
|
||||
theme = _make_theme()
|
||||
bootstrap_data = _make_bootstrap_data(party_scores)
|
||||
fig = _build_party_axis_figure(
|
||||
party_scores, comp_sel=1, theme=theme, bootstrap_data=bootstrap_data
|
||||
party_scores,
|
||||
comp_sel=1,
|
||||
theme=theme,
|
||||
bootstrap_data=bootstrap_data,
|
||||
)
|
||||
|
||||
assert isinstance(fig, go.Figure)
|
||||
@@ -104,38 +107,38 @@ class TestBuildPartyAxisFigure:
|
||||
|
||||
marker_trace = fig.data[1]
|
||||
|
||||
# error_x should be present and visible
|
||||
assert marker_trace.error_x is not None
|
||||
assert marker_trace.error_x.visible is True
|
||||
assert marker_trace.error_x.type == "data"
|
||||
assert len(marker_trace.error_x.array) == 3 # 3 parties
|
||||
|
||||
# All error bar values should be non-negative
|
||||
for err in marker_trace.error_x.array:
|
||||
assert err >= 0.0
|
||||
# No visual error bars — CIs are in hover text only
|
||||
assert (
|
||||
marker_trace.error_x.array is None
|
||||
or marker_trace.error_x.visible is not True
|
||||
)
|
||||
|
||||
# Marker symbols: first party (N=1) → diamond, others → circle
|
||||
symbols = list(marker_trace.marker.symbol)
|
||||
assert symbols[0] == "diamond"
|
||||
assert all(s == "circle" for s in symbols[1:])
|
||||
|
||||
def test_with_bootstrap_hover_includes_n(self):
|
||||
"""Hover text includes N=<count> for each party."""
|
||||
def test_with_bootstrap_hover_includes_n_and_ci(self):
|
||||
"""Hover text includes N=<count> and 95%-BI interval for each party."""
|
||||
from explorer import _build_party_axis_figure
|
||||
|
||||
party_scores = _make_party_scores()
|
||||
theme = _make_theme()
|
||||
bootstrap_data = _make_bootstrap_data(party_scores)
|
||||
fig = _build_party_axis_figure(
|
||||
party_scores, comp_sel=1, theme=theme, bootstrap_data=bootstrap_data
|
||||
party_scores,
|
||||
comp_sel=1,
|
||||
theme=theme,
|
||||
bootstrap_data=bootstrap_data,
|
||||
)
|
||||
|
||||
marker_trace = fig.data[1]
|
||||
for ht in marker_trace.hovertext:
|
||||
assert "(N=" in ht
|
||||
assert "95%-BI" in ht
|
||||
|
||||
def test_flip_negates_scores_but_error_bars_stay_positive(self):
|
||||
"""When flip=True, scores are negated but error bar magnitudes stay positive."""
|
||||
def test_flip_negates_scores(self):
|
||||
"""When flip=True, scores are negated relative to flip=False."""
|
||||
from explorer import _build_party_axis_figure
|
||||
|
||||
party_scores = _make_party_scores()
|
||||
@@ -144,10 +147,16 @@ class TestBuildPartyAxisFigure:
|
||||
bootstrap_data = _make_bootstrap_data(party_scores)
|
||||
|
||||
fig_normal = _build_party_axis_figure(
|
||||
party_scores, comp_sel=1, theme=theme_no_flip, bootstrap_data=bootstrap_data
|
||||
party_scores,
|
||||
comp_sel=1,
|
||||
theme=theme_no_flip,
|
||||
bootstrap_data=bootstrap_data,
|
||||
)
|
||||
fig_flipped = _build_party_axis_figure(
|
||||
party_scores, comp_sel=1, theme=theme_flip, bootstrap_data=bootstrap_data
|
||||
party_scores,
|
||||
comp_sel=1,
|
||||
theme=theme_flip,
|
||||
bootstrap_data=bootstrap_data,
|
||||
)
|
||||
|
||||
normal_scores = list(fig_normal.data[1].x)
|
||||
@@ -157,13 +166,17 @@ class TestBuildPartyAxisFigure:
|
||||
for ns, fs in zip(normal_scores, flipped_scores):
|
||||
assert pytest.approx(ns) == -fs
|
||||
|
||||
# Error bars should be the same (positive) in both cases
|
||||
normal_errors = list(fig_normal.data[1].error_x.array)
|
||||
flipped_errors = list(fig_flipped.data[1].error_x.array)
|
||||
for ne, fe in zip(normal_errors, flipped_errors):
|
||||
assert ne >= 0.0
|
||||
assert fe >= 0.0
|
||||
assert pytest.approx(ne) == fe
|
||||
def test_without_bootstrap_hover_is_score_only(self):
|
||||
"""Without bootstrap data, hover text is just 'Party: score' with no CI."""
|
||||
from explorer import _build_party_axis_figure
|
||||
|
||||
party_scores = _make_party_scores()
|
||||
fig = _build_party_axis_figure(party_scores, comp_sel=1, theme=_make_theme())
|
||||
|
||||
marker_trace = fig.data[1]
|
||||
for ht in marker_trace.hovertext:
|
||||
assert "95%-BI" not in ht
|
||||
assert "(N=" not in ht
|
||||
|
||||
|
||||
class TestLoadPartyMpVectorsImportable:
|
||||
|
||||
Reference in New Issue
Block a user