From f5710e05c88da331b5b3d82344603b0b4f0ea30a Mon Sep 17 00:00:00 2001 From: Uriah Finkel Date: Tue, 18 Aug 2026 13:57:50 +0300 Subject: [PATCH 1/3] Improve interactive calibration panel geometry --- .../calibration/_interactive_aspect.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/rtichoke/calibration/_interactive_aspect.py b/src/rtichoke/calibration/_interactive_aspect.py index de8c44ef..10c70aff 100644 --- a/src/rtichoke/calibration/_interactive_aspect.py +++ b/src/rtichoke/calibration/_interactive_aspect.py @@ -5,20 +5,30 @@ from plotly.graph_objs._figure import Figure +_CALIBRATION_DOMAIN = [0.22, 1.0] +_HISTOGRAM_DOMAIN = [0.0, 0.16] +_HEIGHT_RATIO = 1.30 + + def enforce_square_calibration_panel(fig: Figure) -> Figure: - """Keep the upper calibration panel on a 1:1 predicted/observed scale. + """Keep the upper calibration panel square without squeezing it horizontally. - Calibration figures include a histogram in a separate lower subplot. The - aspect-ratio constraint therefore belongs only to the upper calibration - panel, not to the full Plotly widget or to the histogram. + Calibration figures include a histogram in a separate lower subplot. The + requested ``size`` therefore defines the widget width, while the widget is + made taller so the upper calibration panel can remain square. The histogram + keeps its own unconstrained rectangular panel below it. """ + width = fig.layout.width or 600 + fig.update_layout(height=round(width * _HEIGHT_RATIO)) fig.update_yaxes( + domain=_CALIBRATION_DOMAIN, scaleanchor="x", scaleratio=1, constrain="domain", row=1, col=1, ) + fig.update_yaxes(domain=_HISTOGRAM_DOMAIN, row=2, col=1) return fig From 81426cf9d64516dca0ebd052b45914936bffdf9e Mon Sep 17 00:00:00 2001 From: Uriah Finkel Date: Tue, 18 Aug 2026 13:58:05 +0300 Subject: [PATCH 2/3] Test calibration panel geometry --- tests/test_calibration_interactive_aspect.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_calibration_interactive_aspect.py b/tests/test_calibration_interactive_aspect.py index 30db43c6..38655141 100644 --- a/tests/test_calibration_interactive_aspect.py +++ b/tests/test_calibration_interactive_aspect.py @@ -11,6 +11,13 @@ def _assert_square_main_panel(fig): assert fig.layout.yaxis2.scaleanchor is None +def _assert_tall_widget_geometry(fig): + assert fig.layout.height > fig.layout.width + assert fig.layout.height == round(fig.layout.width * 1.30) + assert list(fig.layout.yaxis.domain) == [0.22, 1.0] + assert list(fig.layout.yaxis2.domain) == [0.0, 0.16] + + def test_interactive_calibration_main_panel_is_square(): probs = {"model": np.linspace(0.05, 0.95, 20)} reals = np.array([0, 1] * 10) @@ -20,6 +27,7 @@ def test_interactive_calibration_main_panel_is_square(): probs, reals, calibration_type=calibration_type ) _assert_square_main_panel(fig) + _assert_tall_widget_geometry(fig) assert list(fig.layout.xaxis.range) == list(fig.layout.yaxis.range) @@ -42,4 +50,5 @@ def test_interactive_calibration_times_main_panel_is_square(): ) _assert_square_main_panel(fig) + _assert_tall_widget_geometry(fig) assert list(fig.layout.xaxis.range) == list(fig.layout.yaxis.range) From 5fa1c6c51062ebb195657c64e7f5075c0ca2fdd7 Mon Sep 17 00:00:00 2001 From: Uriah Finkel Date: Tue, 18 Aug 2026 16:18:59 +0300 Subject: [PATCH 3/3] Use approximate comparisons for calibration limits --- tests/test_calibration.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_calibration.py b/tests/test_calibration.py index adc52c0a..2afcb948 100644 --- a/tests/test_calibration.py +++ b/tests/test_calibration.py @@ -1,5 +1,6 @@ import numpy as np import polars as pl +import pytest from rtichoke.calibration.calibration import ( _define_limits_for_calibration_plot, @@ -55,6 +56,6 @@ def test_calibration_limits_keep_padding_without_leaving_probability_scale(): near_one = pl.DataFrame({"x": [0.30, 0.99], "y": [0.40, 0.98]}) mid_range = pl.DataFrame({"x": [0.20, 0.80], "y": [0.25, 0.75]}) - assert _define_limits_for_calibration_plot(near_zero) == [0.0, 0.7345] - assert _define_limits_for_calibration_plot(near_one) == [0.2655, 1.0] - assert _define_limits_for_calibration_plot(mid_range) == [0.17, 0.8300000000000001] + assert _define_limits_for_calibration_plot(near_zero) == pytest.approx([0.0, 0.7345]) + assert _define_limits_for_calibration_plot(near_one) == pytest.approx([0.2655, 1.0]) + assert _define_limits_for_calibration_plot(mid_range) == pytest.approx([0.17, 0.83])