Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "baycomp_plotting"
version = "1.2.0"
version = "1.2.1"
description = "Extra plotting functionality for baycomp's Bayesian classifier comparison posteriors."
readme = "README.md"
license = { file = "LICENSE" }
Expand Down
10 changes: 8 additions & 2 deletions src/baycomp_plotting/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ def _add_posterior(ax, p, label: str, ls="-", color: str = Color.BLUE) -> None:
upper bound) and ``zo`` (z-order counter, decremented for each posterior so
earlier ones stay on top).
"""
if not (p.var > 0):
raise ValueError(
f"Cannot draw density: posterior variance is {p.var!r}. "
"The two classifiers likely produced identical scores; "
"the posterior is degenerate and has no density to plot."
)
targs = (p.df, p.mean, np.sqrt(p.var))
x = np.linspace(
min(stats.t.ppf(0.005, *targs), -1.05 * p.rope),
Expand Down Expand Up @@ -205,8 +211,8 @@ def dens(p, label: str, ls="-", color: str = Color.BLUE):

fig, ax = plt.subplots()
fig.patch.set_alpha(0)
ax.axvline(0.01, c="darkorange", linewidth=2, zorder=101)
ax.axvline(-0.01, c="darkorange", linewidth=2, zorder=101)
ax.axvline(p.rope, c="darkorange", linewidth=2, zorder=101)
ax.axvline(-p.rope, c="darkorange", linewidth=2, zorder=101)
ax.spines["right"].set_visible(False)
ax.spines["top"].set_visible(False)
ax.spines["bottom"].set_visible(False)
Expand Down
39 changes: 39 additions & 0 deletions tests/test_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,42 @@ def test_tern_renders_three_vertex_labels(self, signed_rank_posterior):
assert any("R" in t for t in text_contents)
assert any("ROPE" in t for t in text_contents)
plt.close(fig)


class TestRopeAxvline:
"""The two orange axvlines must reflect the posterior's ``rope`` parameter,
not a hardcoded value.
"""

@pytest.mark.parametrize("rope", [0.001, 0.01, 0.05])
def test_axvlines_match_rope(self, rng, rope):
bc = pytest.importorskip("baycomp")
base = rng.normal(0.85, 0.015, 10)
x = base + rng.normal(0.0, 0.005, 10)
y = base + rng.normal(0.015, 0.005, 10)
posterior = bc.CorrelatedTTest(x, y, rope=rope, runs=1)

fig = bplt.dens(posterior, label="X")
ax = fig.axes[0]
vlines = sorted(
line.get_xdata()[0] for line in ax.lines
if line.get_xdata()[0] == line.get_xdata()[1] # vertical line
)
# Two of those vertical lines should be at +/- rope
assert pytest.approx(rope, abs=1e-12) in vlines
assert pytest.approx(-rope, abs=1e-12) in vlines
plt.close(fig)


class TestDegeneratePosterior:
"""``dens`` should fail loudly when the posterior is degenerate (var=0),
instead of crashing on NaN axis limits inside matplotlib.
"""

def test_var_zero_raises_value_error(self, rng):
bc = pytest.importorskip("baycomp")
identical = (rng.uniform(size=20) < 0.85).astype(float)
posterior = bc.CorrelatedTTest(identical, identical.copy(), rope=0.01, runs=1)

with pytest.raises(ValueError, match="degenerate"):
bplt.dens(posterior, label="X")
Loading