mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
fix(motor_map): limit map creating optimized
This commit is contained in:
@ -27,6 +27,27 @@ from bec_widgets.widgets.plots_next_gen.plot_base import PlotBase
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class FilledRectItem(pg.GraphicsObject):
|
||||
"""
|
||||
Custom rectangle item for the motor map plot defined by 4 points and a brush.
|
||||
"""
|
||||
|
||||
def __init__(self, x: float, y: float, width: float, height: float, brush: QtGui.QBrush):
|
||||
super().__init__()
|
||||
self._rect = QtCore.QRectF(x, y, width, height)
|
||||
self._brush = brush
|
||||
self._pen = pg.mkPen(None)
|
||||
|
||||
def boundingRect(self):
|
||||
return self._rect
|
||||
|
||||
def paint(self, painter, *args):
|
||||
painter.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing, True)
|
||||
painter.setBrush(self._brush)
|
||||
painter.setPen(self._pen)
|
||||
painter.drawRect(self.boundingRect())
|
||||
|
||||
|
||||
class MotorConfig(BaseModel):
|
||||
name: str | None = Field(None, description="Motor name.")
|
||||
limits: list[float] | None = Field(None, description="Motor limits.")
|
||||
@ -592,7 +613,6 @@ class MotorMap(PlotBase):
|
||||
motor_x_limit = self.config.x_motor.limits
|
||||
motor_y_limit = self.config.y_motor.limits
|
||||
|
||||
if motor_x_limit is not None or motor_y_limit is not None:
|
||||
self._limit_map = self._make_limit_map(motor_x_limit, motor_y_limit)
|
||||
self.plot_item.addItem(self._limit_map)
|
||||
self._limit_map.setZValue(-1)
|
||||
@ -672,35 +692,51 @@ class MotorMap(PlotBase):
|
||||
self.coord_label.setText(text)
|
||||
self.coord_label.setPos(x, y)
|
||||
|
||||
def _make_limit_map(self, limits_x: list, limits_y: list) -> pg.ImageItem:
|
||||
def _make_limit_map(self, limits_x: list | None, limits_y: list | None) -> FilledRectItem:
|
||||
"""
|
||||
Create a limit map for the motor map plot.
|
||||
Create a limit map for the motor map plot. Each limit can be:
|
||||
- [int, int]
|
||||
- [None, None]
|
||||
- [int, None]
|
||||
- [None, int]
|
||||
- or None
|
||||
If any element of a limit list is None, it is treated as unbounded,
|
||||
and replaced with ±1e6 (or any large float of your choice).
|
||||
|
||||
Args:
|
||||
limits_x(list): Motor limits for the x axis.
|
||||
limits_y(list): Motor limits for the y axis.
|
||||
limits_x(list): Motor limits for the x-axis.
|
||||
limits_y(list): Motor limits for the y-axis.
|
||||
|
||||
Returns:
|
||||
pg.ImageItem: Limit map.
|
||||
FilledRectItem: Limit map.
|
||||
"""
|
||||
|
||||
def fix_limit_pair(limits):
|
||||
if not limits:
|
||||
return [-1e6, 1e6]
|
||||
low, high = limits
|
||||
if low is None:
|
||||
low = -1e6
|
||||
if high is None:
|
||||
high = 1e6
|
||||
return [low, high]
|
||||
|
||||
limits_x = fix_limit_pair(limits_x)
|
||||
limits_y = fix_limit_pair(limits_y)
|
||||
|
||||
limit_x_min, limit_x_max = limits_x
|
||||
limit_y_min, limit_y_max = limits_y
|
||||
|
||||
map_width = int(limit_x_max - limit_x_min + 1)
|
||||
map_height = int(limit_y_max - limit_y_min + 1)
|
||||
|
||||
# Create limits map
|
||||
rect_width = limit_x_max - limit_x_min
|
||||
rect_height = limit_y_max - limit_y_min
|
||||
background_value = self.config.background_value
|
||||
limit_map_data = np.full((map_width, map_height), background_value, dtype=np.float32)
|
||||
limit_map = pg.ImageItem()
|
||||
limit_map.setImage(limit_map_data)
|
||||
|
||||
# Translate and scale the image item to match the motor coordinates
|
||||
tr = QtGui.QTransform()
|
||||
tr.translate(limit_x_min, limit_y_min)
|
||||
limit_map.setTransform(tr)
|
||||
brush_color = pg.mkBrush(background_value, background_value, background_value, 150)
|
||||
|
||||
return limit_map
|
||||
filled_rect = FilledRectItem(
|
||||
x=limit_x_min, y=limit_y_min, width=rect_width, height=rect_height, brush=brush_color
|
||||
)
|
||||
return filled_rect
|
||||
|
||||
def _swap_limit_map(self):
|
||||
"""Swap the limit map."""
|
||||
|
@ -78,7 +78,10 @@ def test_motor_map_properties(qtbot, mocked_client):
|
||||
qtbot.wait(200)
|
||||
assert mm.background_value == 40
|
||||
assert mm.config.background_value == 40
|
||||
np.all(mm._limit_map.image == 40.0)
|
||||
filled_rect = mm._limit_map
|
||||
rect_color = filled_rect._brush.color().getRgb()
|
||||
expected = (40, 40, 40, 150)
|
||||
assert rect_color == expected
|
||||
|
||||
|
||||
def test_motor_map_get_limits(qtbot, mocked_client):
|
||||
@ -205,13 +208,14 @@ def test_motor_map_limit_map(qtbot, mocked_client):
|
||||
# Create a limit map
|
||||
limit_map = mm._make_limit_map([0, 10], [0, 5])
|
||||
|
||||
# Check that the limit map was created with the right type
|
||||
assert isinstance(limit_map, pg.ImageItem)
|
||||
from qtpy import QtCore
|
||||
|
||||
# Check the dimensions of the image data
|
||||
image_data = limit_map.image
|
||||
assert image_data.shape[0] == 11 # 0 to 10 inclusive
|
||||
assert image_data.shape[1] == 6 # 0 to 5 inclusive
|
||||
from bec_widgets.widgets.plots_next_gen.motor_map.motor_map import FilledRectItem
|
||||
|
||||
assert isinstance(limit_map, FilledRectItem)
|
||||
rect = limit_map.boundingRect()
|
||||
# For [0,10] on x and [0,5] on y, width=10, height=5
|
||||
assert rect == QtCore.QRectF(0, 0, 10, 5)
|
||||
|
||||
|
||||
def test_motor_map_change_limits(qtbot, mocked_client):
|
||||
@ -223,8 +227,9 @@ def test_motor_map_change_limits(qtbot, mocked_client):
|
||||
# samy: [-5, 5]
|
||||
|
||||
# Original Limits Map
|
||||
assert mm._limit_map.image.shape[0] == 21 # -10 to 10 inclusive
|
||||
assert mm._limit_map.image.shape[1] == 11 # -5 to 5 inclusive
|
||||
rect = mm._limit_map.boundingRect()
|
||||
assert rect.width() == 20 # -10 to 10 inclusive
|
||||
assert rect.height() == 10 # -5 to 5 inclusive
|
||||
assert mm.config.x_motor.limits == [-10, 10]
|
||||
assert mm.config.y_motor.limits == [-5, 5]
|
||||
|
||||
@ -237,8 +242,9 @@ def test_motor_map_change_limits(qtbot, mocked_client):
|
||||
# Check that the limits map was updated
|
||||
assert mm.config.x_motor.limits == [-20, 20]
|
||||
assert mm.config.y_motor.limits == [-5, 5]
|
||||
assert mm._limit_map.image.shape[0] == 41 # -20 to 20 inclusive
|
||||
assert mm._limit_map.image.shape[1] == 11 # -5 to 5 inclusive -> same as before
|
||||
rect = mm._limit_map.boundingRect()
|
||||
assert rect.width() == 40 # -20 to 20 inclusive
|
||||
assert rect.height() == 10 # -5 to 5 inclusive -> same as before
|
||||
|
||||
# Change back the limits
|
||||
mm.dev["samx"].limits = [-10, 10]
|
||||
|
Reference in New Issue
Block a user