0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 03:31:50 +02:00

WIP Image again adjusted inheritance order...

This commit is contained in:
2025-04-06 16:41:17 +02:00
parent 426bd07788
commit 70469c83cc

View File

@ -126,17 +126,15 @@ class Image(PlotBase):
**kwargs,
):
self._color_bar = None
self._main_image = None
if config is None:
config = ImageConfig(widget_class=self.__class__.__name__)
super().__init__(
parent=parent, config=config, client=client, gui_id=gui_id, popups=popups, **kwargs
)
self._main_image = ImageItem(parent_image=self)
# For PropertyManager identification
self.setObjectName("Image")
self.plot_item.addItem(self._main_image)
self.scan_id = None
# Default Color map to magma
@ -145,6 +143,10 @@ class Image(PlotBase):
################################################################################
# Widget Specific GUI interactions
################################################################################
def _init_main_image(self):
self._main_image = ImageItem(parent_image=self)
self.plot_item.addItem(self._main_image)
def _init_toolbar(self):
# add to the first position
@ -270,7 +272,7 @@ class Image(PlotBase):
style(Literal["full", "simple"]): The type of colorbar to enable.
vrange(tuple): The range of values to use for the colorbar.
"""
autorange_state = self._main_image.autorange
autorange_state = self.main_image.autorange
if enabled:
if self._color_bar:
if self.config.color_bar == "full":
@ -280,14 +282,14 @@ class Image(PlotBase):
if style == "simple":
self._color_bar = pg.ColorBarItem(colorMap=self.config.color_map)
self._color_bar.setImageItem(self._main_image)
self._color_bar.setImageItem(self.main_image)
self._color_bar.sigLevelsChangeFinished.connect(
lambda: self.setProperty("autorange", False)
)
elif style == "full":
self._color_bar = pg.HistogramLUTItem()
self._color_bar.setImageItem(self._main_image)
self._color_bar.setImageItem(self.main_image)
self._color_bar.gradient.loadPreset(self.config.color_map)
self._color_bar.sigLevelsChanged.connect(
lambda: self.setProperty("autorange", False)
@ -374,7 +376,7 @@ class Image(PlotBase):
"""
try:
self.config.color_map = value
self._main_image.color_map = value
self.main_image.color_map = value
if self._color_bar:
if self.config.color_bar == "simple":
@ -390,7 +392,7 @@ class Image(PlotBase):
"""
Set the v_range of the main image.
"""
vmin, vmax = self._main_image.v_range
vmin, vmax = self.main_image.v_range
return QPointF(vmin, vmax)
@v_range.setter
@ -406,7 +408,7 @@ class Image(PlotBase):
vmin, vmax = value.x(), value.y()
self._main_image.v_range = (vmin, vmax)
self.main_image.v_range = (vmin, vmax)
# propagate to colorbar if exists
if self._color_bar:
@ -495,7 +497,7 @@ class Image(PlotBase):
"""
The name of the monitor to use for the image.
"""
return self._main_image.config.monitor
return self.main_image.config.monitor
@monitor.setter
def monitor(self, value: str):
@ -505,7 +507,7 @@ class Image(PlotBase):
Args:
value(str): The name of the monitor to set.
"""
if self._main_image.config.monitor == value:
if self.main_image.config.monitor == value:
return
try:
self.entry_validator.validate_monitor(value)
@ -516,6 +518,8 @@ class Image(PlotBase):
@property
def main_image(self) -> ImageItem:
"""Access the main image item."""
if self._main_image is None:
self._init_main_image()
return self._main_image
################################################################################
@ -526,7 +530,7 @@ class Image(PlotBase):
"""
Whether autorange is enabled.
"""
return self._main_image.autorange
return self.main_image.autorange
@autorange.setter
def autorange(self, enabled: bool):
@ -536,9 +540,9 @@ class Image(PlotBase):
Args:
enabled(bool): Whether to enable autorange.
"""
self._main_image.autorange = enabled
if enabled and self._main_image.raw_data is not None:
self._main_image.apply_autorange()
self.main_image.autorange = enabled
if enabled and self.main_image.raw_data is not None:
self.main_image.apply_autorange()
self._sync_colorbar_levels()
self._sync_autorange_switch()
@ -552,7 +556,7 @@ class Image(PlotBase):
- "mean": Use the mean value of the image for autoranging.
"""
return self._main_image.autorange_mode
return self.main_image.autorange_mode
@autorange_mode.setter
def autorange_mode(self, mode: str):
@ -565,7 +569,7 @@ class Image(PlotBase):
# for qt Designer
if mode not in ["max", "mean"]:
return
self._main_image.autorange_mode = mode
self.main_image.autorange_mode = mode
self._sync_autorange_switch()
@ -578,11 +582,11 @@ class Image(PlotBase):
enabled(bool): Whether to enable autorange.
mode(str): The autorange mode. Options are "max" or "mean".
"""
if self._main_image is not None:
self._main_image.autorange = enabled
self._main_image.autorange_mode = mode
if self.main_image is not None:
self.main_image.autorange = enabled
self.main_image.autorange_mode = mode
if enabled:
self._main_image.apply_autorange()
self.main_image.apply_autorange()
self._sync_colorbar_levels()
def _sync_autorange_switch(self):
@ -590,13 +594,13 @@ class Image(PlotBase):
Synchronize the autorange switch with the current autorange state and mode if changed from outside.
"""
self.autorange_switch.block_all_signals(True)
self.autorange_switch.set_default_action(f"auto_range_{self._main_image.autorange_mode}")
self.autorange_switch.set_state_all(self._main_image.autorange)
self.autorange_switch.set_default_action(f"auto_range_{self.main_image.autorange_mode}")
self.autorange_switch.set_state_all(self.main_image.autorange)
self.autorange_switch.block_all_signals(False)
def _sync_colorbar_levels(self):
"""Immediately propagate current levels to the active colorbar."""
vrange = self._main_image.v_range
vrange = self.main_image.v_range
if self._color_bar:
self._color_bar.blockSignals(True)
self.v_range = vrange
@ -623,7 +627,7 @@ class Image(PlotBase):
"""
Whether FFT postprocessing is enabled.
"""
return self._main_image.fft
return self.main_image.fft
@fft.setter
def fft(self, enable: bool):
@ -633,14 +637,14 @@ class Image(PlotBase):
Args:
enable(bool): Whether to enable FFT postprocessing.
"""
self._main_image.fft = enable
self.main_image.fft = enable
@SafeProperty(bool)
def log(self) -> bool:
"""
Whether logarithmic scaling is applied.
"""
return self._main_image.log
return self.main_image.log
@log.setter
def log(self, enable: bool):
@ -650,14 +654,14 @@ class Image(PlotBase):
Args:
enable(bool): Whether to enable logarithmic scaling.
"""
self._main_image.log = enable
self.main_image.log = enable
@SafeProperty(int)
def rotation(self) -> int:
"""
The number of 90° rotations to apply.
"""
return self._main_image.rotation
return self.main_image.rotation
@rotation.setter
def rotation(self, value: int):
@ -667,14 +671,14 @@ class Image(PlotBase):
Args:
value(int): The number of 90° rotations to apply.
"""
self._main_image.rotation = value
self.main_image.rotation = value
@SafeProperty(bool)
def transpose(self) -> bool:
"""
Whether the image is transposed.
"""
return self._main_image.transpose
return self.main_image.transpose
@transpose.setter
def transpose(self, enable: bool):
@ -684,7 +688,7 @@ class Image(PlotBase):
Args:
enable(bool): Whether to enable transposing the image.
"""
self._main_image.transpose = enable
self.main_image.transpose = enable
################################################################################
# High Level methods for API
@ -712,27 +716,27 @@ class Image(PlotBase):
ImageItem: The image object.
"""
if self._main_image.config.monitor is not None:
self.disconnect_monitor(self._main_image.config.monitor)
if self.main_image.config.monitor is not None:
self.disconnect_monitor(self.main_image.config.monitor)
self.entry_validator.validate_monitor(monitor)
self._main_image.config.monitor = monitor
self.main_image.config.monitor = monitor
if monitor_type == "1d":
self._main_image.config.source = "device_monitor_1d"
self._main_image.config.monitor_type = "1d"
self.main_image.config.source = "device_monitor_1d"
self.main_image.config.monitor_type = "1d"
elif monitor_type == "2d":
self._main_image.config.source = "device_monitor_2d"
self._main_image.config.monitor_type = "2d"
self.main_image.config.source = "device_monitor_2d"
self.main_image.config.monitor_type = "2d"
elif monitor_type == "auto":
self._main_image.config.source = "auto"
self.main_image.config.source = "auto"
logger.warning(
f"Updates for '{monitor}' will be fetch from both 1D and 2D monitor endpoints."
)
self._main_image.config.monitor_type = "auto"
self.main_image.config.monitor_type = "auto"
self.set_image_update(monitor=monitor, type=monitor_type)
if color_map is not None:
self._main_image.color_map = color_map
self.main_image.color_map = color_map
if color_bar is not None:
self.enable_colorbar(True, color_bar)
if vrange is not None:
@ -740,20 +744,20 @@ class Image(PlotBase):
self._sync_device_selection()
return self._main_image
return self.main_image
def _sync_device_selection(self):
"""
Synchronize the device selection with the current monitor.
"""
if self._main_image.config.monitor is not None:
if self.main_image.config.monitor is not None:
for combo in (
self.selection_bundle.device_combo_box,
self.selection_bundle.dim_combo_box,
):
combo.blockSignals(True)
self.selection_bundle.device_combo_box.set_device(self._main_image.config.monitor)
self.selection_bundle.dim_combo_box.setCurrentText(self._main_image.config.monitor_type)
self.selection_bundle.device_combo_box.set_device(self.main_image.config.monitor)
self.selection_bundle.dim_combo_box.setCurrentText(self.main_image.config.monitor_type)
for combo in (
self.selection_bundle.device_combo_box,
self.selection_bundle.dim_combo_box,
@ -793,7 +797,7 @@ class Image(PlotBase):
self.on_image_update_2d, MessageEndpoints.device_monitor_2d(monitor)
)
print(f"Connected to {monitor} with type {type}")
self._main_image.config.monitor = monitor
self.main_image.config.monitor = monitor
def disconnect_monitor(self, monitor: str):
"""
@ -808,7 +812,7 @@ class Image(PlotBase):
self.bec_dispatcher.disconnect_slot(
self.on_image_update_2d, MessageEndpoints.device_monitor_2d(monitor)
)
self._main_image.config.monitor = None
self.main_image.config.monitor = None
########################################
# 1D updates
@ -829,13 +833,13 @@ class Image(PlotBase):
return
if current_scan_id != self.scan_id:
self.scan_id = current_scan_id
self._main_image.clear()
self._main_image.buffer = []
self._main_image.max_len = 0
image_buffer = self.adjust_image_buffer(self._main_image, data)
self.main_image.clear()
self.main_image.buffer = []
self.main_image.max_len = 0
image_buffer = self.adjust_image_buffer(self.main_image, data)
if self._color_bar is not None:
self._color_bar.blockSignals(True)
self._main_image.set_data(image_buffer)
self.main_image.set_data(image_buffer)
if self._color_bar is not None:
self._color_bar.blockSignals(False)
@ -886,7 +890,7 @@ class Image(PlotBase):
data = msg["data"]
if self._color_bar is not None:
self._color_bar.blockSignals(True)
self._main_image.set_data(data)
self.main_image.set_data(data)
if self._color_bar is not None:
self._color_bar.blockSignals(False)
@ -914,9 +918,9 @@ class Image(PlotBase):
"""
Disconnect the image update signals and clean up the image.
"""
if self._main_image.config.monitor is not None:
self.disconnect_monitor(self._main_image.config.monitor)
self._main_image.config.monitor = None
if self.main_image.config.monitor is not None:
self.disconnect_monitor(self.main_image.config.monitor)
self.main_image.config.monitor = None
if self._color_bar:
if self.config.color_bar == "full":