mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
fix(cli): find_widget_by_id for BECImageShow changed to be compatible with RPC logic
This commit is contained in:
@ -555,7 +555,7 @@ class BECImageShow(RPCBase):
|
|||||||
Args:
|
Args:
|
||||||
vmin(float): Minimum value of the color bar.
|
vmin(float): Minimum value of the color bar.
|
||||||
vmax(float): Maximum value of the color bar.
|
vmax(float): Maximum value of the color bar.
|
||||||
name(str): The name of the image.
|
name(str): The name of the image. If None, apply to all images.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@rpc_call
|
@rpc_call
|
||||||
@ -565,7 +565,7 @@ class BECImageShow(RPCBase):
|
|||||||
If name is not specified, then set color map for all images.
|
If name is not specified, then set color map for all images.
|
||||||
Args:
|
Args:
|
||||||
cmap(str): The color map of the image.
|
cmap(str): The color map of the image.
|
||||||
name(str): The name of the image.
|
name(str): The name of the image. If None, apply to all images.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@ -585,7 +585,67 @@ class BECImageItem(RPCBase):
|
|||||||
@rpc_call
|
@rpc_call
|
||||||
def set(self, **kwargs):
|
def set(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
None
|
Set the properties of the image.
|
||||||
|
Args:
|
||||||
|
**kwargs: Keyword arguments for the properties to be set.
|
||||||
|
Possible properties:
|
||||||
|
- downsample
|
||||||
|
- color_map
|
||||||
|
- monitor
|
||||||
|
- opacity
|
||||||
|
- vrange
|
||||||
|
- fft
|
||||||
|
- log
|
||||||
|
- rot
|
||||||
|
- transpose
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_fft(self, enable: "bool" = False):
|
||||||
|
"""
|
||||||
|
Set the FFT of the image.
|
||||||
|
Args:
|
||||||
|
enable(bool): Whether to perform FFT on the monitor data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_log(self, enable: "bool" = False):
|
||||||
|
"""
|
||||||
|
Set the log of the image.
|
||||||
|
Args:
|
||||||
|
enable(bool): Whether to perform log on the monitor data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_rotation(self, deg_90: "int" = 0):
|
||||||
|
"""
|
||||||
|
Set the rotation of the image.
|
||||||
|
Args:
|
||||||
|
deg_90(int): The rotation angle of the monitor data before displaying.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_transpose(self, enable: "bool" = False):
|
||||||
|
"""
|
||||||
|
Set the transpose of the image.
|
||||||
|
Args:
|
||||||
|
enable(bool): Whether to transpose the image.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_opacity(self, opacity: "float" = 1.0):
|
||||||
|
"""
|
||||||
|
Set the opacity of the image.
|
||||||
|
Args:
|
||||||
|
opacity(float): The opacity of the image.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@rpc_call
|
||||||
|
def set_autorange(self, autorange: "bool" = True):
|
||||||
|
"""
|
||||||
|
Set the autorange of the color bar.
|
||||||
|
Args:
|
||||||
|
autorange(bool): Whether to autorange the color bar.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@rpc_call
|
@rpc_call
|
||||||
|
@ -132,7 +132,6 @@ class RPCBase:
|
|||||||
print(f"RPCBase: {rpc_msg}")
|
print(f"RPCBase: {rpc_msg}")
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
receiver = self._root._gui_id
|
receiver = self._root._gui_id
|
||||||
# self._client.connector.send(MessageEndpoints.gui_instructions(receiver), rpc_msg)
|
|
||||||
self._client.connector.set_and_publish(MessageEndpoints.gui_instructions(receiver), rpc_msg)
|
self._client.connector.set_and_publish(MessageEndpoints.gui_instructions(receiver), rpc_msg)
|
||||||
|
|
||||||
if not wait_for_rpc_response:
|
if not wait_for_rpc_response:
|
||||||
|
@ -62,9 +62,9 @@ class BECWidgetsCLIServer:
|
|||||||
item = widget.find_widget_by_id(gui_id)
|
item = widget.find_widget_by_id(gui_id)
|
||||||
if item:
|
if item:
|
||||||
return item
|
return item
|
||||||
raise NotImplementedError(
|
# raise NotImplementedError(
|
||||||
f"gui_id lookup for widget of type {widget.__class__.__name__} not implemented"
|
# f"gui_id lookup for widget of type {widget.__class__.__name__} not implemented"
|
||||||
)
|
# )
|
||||||
|
|
||||||
raise ValueError(f"Object with gui_id {gui_id} not found")
|
raise ValueError(f"Object with gui_id {gui_id} not found")
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ class BECWidgetsCLIServer:
|
|||||||
"config": obj.config.model_dump(),
|
"config": obj.config.model_dump(),
|
||||||
"__rpc__": True,
|
"__rpc__": True,
|
||||||
}
|
}
|
||||||
return obj
|
return obpyj
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__": # pragma: no cover
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
@ -607,6 +607,7 @@ class BECFigureMainWindow(QMainWindow):
|
|||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
self.figure.cleanup()
|
self.figure.cleanup()
|
||||||
|
self.figure.client.shutdown()
|
||||||
if self.safe_close == True:
|
if self.safe_close == True:
|
||||||
print("Safe close")
|
print("Safe close")
|
||||||
event.accept()
|
event.accept()
|
||||||
|
@ -31,6 +31,7 @@ class ProcessingConfig(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class ImageItemConfig(ConnectionConfig):
|
class ImageItemConfig(ConnectionConfig):
|
||||||
|
parent_id: Optional[str] = Field(None, description="The parent plot of the image.")
|
||||||
monitor: Optional[str] = Field(None, description="The name of the monitor.")
|
monitor: Optional[str] = Field(None, description="The name of the monitor.")
|
||||||
source: Optional[str] = Field(None, description="The source of the curve.")
|
source: Optional[str] = Field(None, description="The source of the curve.")
|
||||||
color_map: Optional[str] = Field("magma", description="The color map of the image.")
|
color_map: Optional[str] = Field("magma", description="The color map of the image.")
|
||||||
@ -42,6 +43,7 @@ class ImageItemConfig(ConnectionConfig):
|
|||||||
color_bar: Optional[Literal["simple", "full"]] = Field(
|
color_bar: Optional[Literal["simple", "full"]] = Field(
|
||||||
"simple", description="The type of the color bar."
|
"simple", description="The type of the color bar."
|
||||||
)
|
)
|
||||||
|
autorange: Optional[bool] = Field(True, description="Whether to autorange the color bar.")
|
||||||
processing: ProcessingConfig = Field(
|
processing: ProcessingConfig = Field(
|
||||||
default_factory=ProcessingConfig, description="The post processing of the image."
|
default_factory=ProcessingConfig, description="The post processing of the image."
|
||||||
)
|
)
|
||||||
@ -57,6 +59,12 @@ class ImageConfig(WidgetConfig):
|
|||||||
class BECImageItem(BECConnector, pg.ImageItem):
|
class BECImageItem(BECConnector, pg.ImageItem):
|
||||||
USER_ACCESS = [
|
USER_ACCESS = [
|
||||||
"set",
|
"set",
|
||||||
|
"set_fft",
|
||||||
|
"set_log",
|
||||||
|
"set_rotation",
|
||||||
|
"set_transpose",
|
||||||
|
"set_opacity",
|
||||||
|
"set_autorange",
|
||||||
"set_color_map",
|
"set_color_map",
|
||||||
"set_auto_downsample",
|
"set_auto_downsample",
|
||||||
"set_monitor",
|
"set_monitor",
|
||||||
@ -89,13 +97,30 @@ class BECImageItem(BECConnector, pg.ImageItem):
|
|||||||
self.set(**kwargs)
|
self.set(**kwargs)
|
||||||
|
|
||||||
def apply_config(self):
|
def apply_config(self):
|
||||||
|
"""
|
||||||
|
Apply current configuration.
|
||||||
|
"""
|
||||||
self.set_color_map(self.config.color_map)
|
self.set_color_map(self.config.color_map)
|
||||||
self.set_auto_downsample(self.config.downsample)
|
self.set_auto_downsample(self.config.downsample)
|
||||||
if self.config.vrange is not None:
|
if self.config.vrange is not None:
|
||||||
self.set_vrange(vrange=self.config.vrange)
|
self.set_vrange(vrange=self.config.vrange)
|
||||||
# self.set_color_bar(self.config.color_bar)
|
|
||||||
|
|
||||||
def set(self, **kwargs):
|
def set(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Set the properties of the image.
|
||||||
|
Args:
|
||||||
|
**kwargs: Keyword arguments for the properties to be set.
|
||||||
|
Possible properties:
|
||||||
|
- downsample
|
||||||
|
- color_map
|
||||||
|
- monitor
|
||||||
|
- opacity
|
||||||
|
- vrange
|
||||||
|
- fft
|
||||||
|
- log
|
||||||
|
- rot
|
||||||
|
- transpose
|
||||||
|
"""
|
||||||
method_map = {
|
method_map = {
|
||||||
"downsample": self.set_auto_downsample,
|
"downsample": self.set_auto_downsample,
|
||||||
"color_map": self.set_color_map,
|
"color_map": self.set_color_map,
|
||||||
@ -114,23 +139,58 @@ class BECImageItem(BECConnector, pg.ImageItem):
|
|||||||
print(f"Warning: '{key}' is not a recognized property.")
|
print(f"Warning: '{key}' is not a recognized property.")
|
||||||
|
|
||||||
def set_fft(self, enable: bool = False):
|
def set_fft(self, enable: bool = False):
|
||||||
|
"""
|
||||||
|
Set the FFT of the image.
|
||||||
|
Args:
|
||||||
|
enable(bool): Whether to perform FFT on the monitor data.
|
||||||
|
"""
|
||||||
self.config.processing.fft = enable
|
self.config.processing.fft = enable
|
||||||
|
|
||||||
def set_log(self, enable: bool = False):
|
def set_log(self, enable: bool = False):
|
||||||
|
"""
|
||||||
|
Set the log of the image.
|
||||||
|
Args:
|
||||||
|
enable(bool): Whether to perform log on the monitor data.
|
||||||
|
"""
|
||||||
self.config.processing.log = enable
|
self.config.processing.log = enable
|
||||||
if enable and self.color_bar and self.config.color_bar == "full":
|
if enable and self.color_bar and self.config.color_bar == "full":
|
||||||
self.color_bar.autoHistogramRange()
|
self.color_bar.autoHistogramRange()
|
||||||
|
|
||||||
def set_rotation(self, deg_90: int = 0):
|
def set_rotation(self, deg_90: int = 0):
|
||||||
|
"""
|
||||||
|
Set the rotation of the image.
|
||||||
|
Args:
|
||||||
|
deg_90(int): The rotation angle of the monitor data before displaying.
|
||||||
|
"""
|
||||||
self.config.processing.rotation = deg_90
|
self.config.processing.rotation = deg_90
|
||||||
|
|
||||||
def set_transpose(self, enable: bool = False):
|
def set_transpose(self, enable: bool = False):
|
||||||
|
"""
|
||||||
|
Set the transpose of the image.
|
||||||
|
Args:
|
||||||
|
enable(bool): Whether to transpose the image.
|
||||||
|
"""
|
||||||
self.config.processing.transpose = enable
|
self.config.processing.transpose = enable
|
||||||
|
|
||||||
def set_opacity(self, opacity: float = 1.0):
|
def set_opacity(self, opacity: float = 1.0):
|
||||||
|
"""
|
||||||
|
Set the opacity of the image.
|
||||||
|
Args:
|
||||||
|
opacity(float): The opacity of the image.
|
||||||
|
"""
|
||||||
self.setOpacity(opacity)
|
self.setOpacity(opacity)
|
||||||
self.config.opacity = opacity
|
self.config.opacity = opacity
|
||||||
|
|
||||||
|
def set_autorange(self, autorange: bool = True):
|
||||||
|
"""
|
||||||
|
Set the autorange of the color bar.
|
||||||
|
Args:
|
||||||
|
autorange(bool): Whether to autorange the color bar.
|
||||||
|
"""
|
||||||
|
self.config.autorange = autorange
|
||||||
|
if self.color_bar is not None:
|
||||||
|
self.color_bar.autoHistogramRange()
|
||||||
|
|
||||||
def set_color_map(self, cmap: str = "magma"):
|
def set_color_map(self, cmap: str = "magma"):
|
||||||
"""
|
"""
|
||||||
Set the color map of the image.
|
Set the color map of the image.
|
||||||
@ -173,6 +233,7 @@ class BECImageItem(BECConnector, pg.ImageItem):
|
|||||||
vmin, vmax = vrange
|
vmin, vmax = vrange
|
||||||
self.setLevels([vmin, vmax])
|
self.setLevels([vmin, vmax])
|
||||||
self.config.vrange = (vmin, vmax)
|
self.config.vrange = (vmin, vmax)
|
||||||
|
self.config.autorange = False
|
||||||
if self.color_bar is not None:
|
if self.color_bar is not None:
|
||||||
if self.config.color_bar == "simple":
|
if self.config.color_bar == "simple":
|
||||||
self.color_bar.setLevels(low=vmin, high=vmax)
|
self.color_bar.setLevels(low=vmin, high=vmax)
|
||||||
@ -215,24 +276,6 @@ class BECImageItem(BECConnector, pg.ImageItem):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("style should be 'simple' or 'full'")
|
raise ValueError("style should be 'simple' or 'full'")
|
||||||
|
|
||||||
def _update_color_bar_for_log(self):
|
|
||||||
"""
|
|
||||||
Update the color bar to reflect a logarithmic scale.
|
|
||||||
"""
|
|
||||||
...
|
|
||||||
# if self.config.vrange:
|
|
||||||
# vmin, vmax = self.config.vrange
|
|
||||||
# offset = 1e-6
|
|
||||||
# vmin_log, vmax_log = np.log10(vmin + offset), np.log10(vmax + offset)
|
|
||||||
# if self.config.color_bar == "simple":
|
|
||||||
# self.color_bar.setLevels(low=vmin_log, high=vmax_log)
|
|
||||||
# elif self.config.color_bar == "full":
|
|
||||||
# self.color_bar.setImageItem(self)
|
|
||||||
# self.color_bar.setLevels(min=vmin_log, max=vmax_log)
|
|
||||||
# self.color_bar.setHistogramRange(
|
|
||||||
# vmin_log - 0.1 * vmin_log, vmax_log + 0.1 * vmax_log
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
class BECImageShow(BECPlotBase):
|
class BECImageShow(BECPlotBase):
|
||||||
USER_ACCESS = [
|
USER_ACCESS = [
|
||||||
@ -286,6 +329,20 @@ class BECImageShow(BECPlotBase):
|
|||||||
Args:
|
Args:
|
||||||
item_id(str): The gui_id of the widget.
|
item_id(str): The gui_id of the widget.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BECImageItem: The widget with the given gui_id.
|
||||||
|
"""
|
||||||
|
for source, images in self._images.items():
|
||||||
|
for monitor, image_item in images.items():
|
||||||
|
if image_item.gui_id == item_id:
|
||||||
|
return image_item
|
||||||
|
|
||||||
|
def find_image_by_monitor(self, item_id: str) -> BECImageItem:
|
||||||
|
"""
|
||||||
|
Find the widget by its gui_id.
|
||||||
|
Args:
|
||||||
|
item_id(str): The gui_id of the widget.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BECImageItem: The widget with the given gui_id.
|
BECImageItem: The widget with the given gui_id.
|
||||||
"""
|
"""
|
||||||
@ -294,7 +351,7 @@ class BECImageShow(BECPlotBase):
|
|||||||
if key == item_id and isinstance(value, BECImageItem):
|
if key == item_id and isinstance(value, BECImageItem):
|
||||||
return value
|
return value
|
||||||
elif isinstance(value, dict):
|
elif isinstance(value, dict):
|
||||||
result = self.find_widget_by_id(item_id)
|
result = self.find_image_by_monitor(item_id)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -344,6 +401,7 @@ class BECImageShow(BECPlotBase):
|
|||||||
"""
|
"""
|
||||||
if isinstance(config, dict):
|
if isinstance(config, dict):
|
||||||
config = ImageItemConfig(**config)
|
config = ImageItemConfig(**config)
|
||||||
|
config.parent_id = self.gui_id
|
||||||
name = config.monitor if config.monitor is not None else config.gui_id
|
name = config.monitor if config.monitor is not None else config.gui_id
|
||||||
image = self._add_image_object(source=config.source, name=name, config=config)
|
image = self._add_image_object(source=config.source, name=name, config=config)
|
||||||
return image
|
return image
|
||||||
@ -468,7 +526,7 @@ class BECImageShow(BECPlotBase):
|
|||||||
image_id (str, optional): The ID of the specific image to apply the setting to. If None, applies to all images.
|
image_id (str, optional): The ID of the specific image to apply the setting to. If None, applies to all images.
|
||||||
"""
|
"""
|
||||||
if image_id:
|
if image_id:
|
||||||
image = self.find_widget_by_id(image_id)
|
image = self.find_image_by_monitor(image_id)
|
||||||
if image:
|
if image:
|
||||||
getattr(image, setting_method_name)(*args, **kwargs)
|
getattr(image, setting_method_name)(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
@ -610,7 +668,7 @@ class BECImageShow(BECPlotBase):
|
|||||||
data(np.ndarray): The data to be updated.
|
data(np.ndarray): The data to be updated.
|
||||||
"""
|
"""
|
||||||
image_to_update = self._images["device_monitor"][device]
|
image_to_update = self._images["device_monitor"][device]
|
||||||
image_to_update.updateImage(data)
|
image_to_update.updateImage(data, autoLevels=image_to_update.config.autorange)
|
||||||
|
|
||||||
def _connect_device_monitor(self, monitor: str):
|
def _connect_device_monitor(self, monitor: str):
|
||||||
"""
|
"""
|
||||||
@ -618,7 +676,7 @@ class BECImageShow(BECPlotBase):
|
|||||||
Args:
|
Args:
|
||||||
monitor(str): The name of the monitor.
|
monitor(str): The name of the monitor.
|
||||||
"""
|
"""
|
||||||
image_item = self.find_widget_by_id(monitor)
|
image_item = self.find_image_by_monitor(monitor)
|
||||||
try:
|
try:
|
||||||
previous_monitor = image_item.config.monitor
|
previous_monitor = image_item.config.monitor
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -637,6 +695,7 @@ class BECImageShow(BECPlotBase):
|
|||||||
def _add_image_object(
|
def _add_image_object(
|
||||||
self, source: str, name: str, config: ImageItemConfig, data=None
|
self, source: str, name: str, config: ImageItemConfig, data=None
|
||||||
) -> BECImageItem: # TODO fix types
|
) -> BECImageItem: # TODO fix types
|
||||||
|
config.parent_id = self.gui_id
|
||||||
image = BECImageItem(config=config, parent_image=self)
|
image = BECImageItem(config=config, parent_image=self)
|
||||||
self.plot_item.addItem(image)
|
self.plot_item.addItem(image)
|
||||||
self._images[source][name] = image
|
self._images[source][name] = image
|
||||||
@ -668,13 +727,13 @@ class BECImageShow(BECPlotBase):
|
|||||||
Clean up the widget.
|
Clean up the widget.
|
||||||
"""
|
"""
|
||||||
print(f"Cleaning up {self.gui_id}")
|
print(f"Cleaning up {self.gui_id}")
|
||||||
for monitor in self._images["device_monitor"]:
|
# for monitor in self._images["device_monitor"]:
|
||||||
self.bec_dispatcher.disconnect_slot(
|
# self.bec_dispatcher.disconnect_slot(
|
||||||
self.on_image_update, MessageEndpoints.device_monitor(monitor)
|
# self.on_image_update, MessageEndpoints.device_monitor(monitor)
|
||||||
)
|
# )
|
||||||
if self.thread.isRunning():
|
# if self.thread is not None and self.thread.isRunning():
|
||||||
self.thread.quit()
|
# self.thread.quit()
|
||||||
self.thread.wait()
|
# self.thread.wait()
|
||||||
|
|
||||||
|
|
||||||
class ImageProcessor:
|
class ImageProcessor:
|
||||||
|
Reference in New Issue
Block a user