fix(plot_base): preserve fractional values when setting ranges from tuples

This commit is contained in:
2026-07-16 13:45:30 +02:00
committed by Jan Wyzula
parent b77649954f
commit 170a9c0b1d
3 changed files with 42 additions and 5 deletions
+3 -1
View File
@@ -623,7 +623,9 @@ class PlotBase(BECWidget, QWidget):
raise TypeError("Limits must be numbers.")
if min_val > max_val:
raise ValueError("Minimum limit cannot be greater than maximum limit.")
return QPoint(*tuple)
# QPointF, not QPoint: QPoint truncates to int and silently discarded the
# fractional part of every range set from a tuple (v_range, x/y limits).
return QPointF(*tuple)
################################################################################
# X limits, has to be SaveProperty("QPointF") because of the tuple conversion for designer,
+29 -4
View File
@@ -100,6 +100,30 @@ def test_set_vrange(qtbot, mocked_client):
assert bec_image_view.main_image.config.v_range == (10, 100)
@pytest.mark.parametrize("colorbar_type", [None, "simple", "full"])
def test_set_vrange_keeps_fractional_values(qtbot, mocked_client, colorbar_type):
"""Regression: tuple ranges went through QPoint, which truncates to int, so
e.g. v_max = 10.5 could never produce a non-integer level."""
bec_image_view = create_widget(qtbot, Image, client=mocked_client)
bec_image_view.main_image.set_data(np.arange(100, dtype=float).reshape(10, 10))
if colorbar_type is not None:
bec_image_view.enable_colorbar(True, colorbar_type)
bec_image_view.v_range = (0.25, 10.5)
assert bec_image_view.v_range == QPointF(0.25, 10.5)
assert bec_image_view.main_image.v_range == (0.25, 10.5)
bec_image_view.v_max = 42.5
assert bec_image_view.main_image.v_range == (0.25, 42.5)
bec_image_view.v_min = 0.75
assert bec_image_view.main_image.v_range == (0.75, 42.5)
if colorbar_type == "simple":
assert bec_image_view._color_bar.levels() == (0.75, 42.5)
elif colorbar_type == "full":
assert tuple(bec_image_view._color_bar.getLevels()) == (0.75, 42.5)
def test_enable_simple_colorbar(qtbot, mocked_client):
bec_image_view = create_widget(qtbot, Image, client=mocked_client)
bec_image_view.enable_simple_colorbar = True
@@ -142,11 +166,12 @@ def test_colorbar_menu_set_levels_updates_vrange(qtbot, mocked_client):
bec_image_view.enable_full_colorbar = True
assert bec_image_view.autorange is True
# Simulate the "Set levels…" context-menu action (image scaling via the region).
bec_image_view._color_bar.sigColorLevelsChangeRequested.emit((0, 50))
# Simulate the "Set levels…" context-menu action (image scaling via the
# region); fractional values must survive (regression: QPoint truncation).
bec_image_view._color_bar.sigColorLevelsChangeRequested.emit((0.5, 50.5))
assert bec_image_view.v_range == QPointF(0, 50)
assert bec_image_view.main_image.levels == (0, 50)
assert bec_image_view.v_range == QPointF(0.5, 50.5)
assert bec_image_view.main_image.levels == (0.5, 50.5)
# Setting explicit levels disables autorange.
assert bec_image_view.autorange is False
@@ -528,3 +528,13 @@ def test_minimal_crosshair_precision_after_hook(qtbot, mocked_client):
assert sig.args == ["minimal_crosshair_precision", 1]
assert pb.crosshair.min_precision == 1
def test_limits_accept_fractional_values(qtbot, mocked_client):
"""Regression: tuple limits were converted through QPoint, silently truncating
fractional values to integers."""
pb = create_widget(qtbot, PlotBase, client=mocked_client)
pb.x_limits = (0.5, 9.25)
pb.y_limits = (-1.75, 3.5)
assert (pb.x_limits.x(), pb.x_limits.y()) == (0.5, 9.25)
assert (pb.y_limits.x(), pb.y_limits.y()) == (-1.75, 3.5)