mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
refactor(image_widget): old BECImageWidget removed
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -53,10 +53,7 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
||||
"w9": self.w9,
|
||||
"w10": self.w10,
|
||||
"d0": self.d0,
|
||||
"d1": self.d1,
|
||||
"im": self.im,
|
||||
"im_old": self.im_old,
|
||||
"it_old": self.it_old,
|
||||
"mi": self.mi,
|
||||
"mm": self.mm,
|
||||
"mw": self.mw,
|
||||
@ -216,11 +213,6 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
||||
self.mm = self.d0.new("BECMotorMapWidget")
|
||||
self.mm.change_motors("samx", "samy")
|
||||
|
||||
self.d1 = self.dock.new(name="dock_1", position="right")
|
||||
self.im_old = self.d1.new("BECImageWidget")
|
||||
self.im_old.image("waveform", "1d")
|
||||
self.it_old = self.im_old._image._images["device_monitor_1d"]["waveform"]
|
||||
|
||||
self.mw = None # self.wf.multi_waveform(monitor="waveform") # , config=config)
|
||||
|
||||
self.dock.save_state()
|
||||
|
@ -25,9 +25,9 @@ from bec_widgets.widgets.containers.dock.dock import BECDock, DockConfig
|
||||
from bec_widgets.widgets.control.device_control.positioner_box import PositionerBox
|
||||
from bec_widgets.widgets.control.scan_control.scan_control import ScanControl
|
||||
from bec_widgets.widgets.editors.vscode.vscode import VSCodeEditor
|
||||
from bec_widgets.widgets.plots.image.image_widget import BECImageWidget
|
||||
from bec_widgets.widgets.plots.motor_map.motor_map_widget import BECMotorMapWidget
|
||||
from bec_widgets.widgets.plots.multi_waveform.multi_waveform_widget import BECMultiWaveformWidget
|
||||
from bec_widgets.widgets.plots_next_gen.image.image import Image
|
||||
from bec_widgets.widgets.plots_next_gen.waveform.waveform import Waveform
|
||||
from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_bar import RingProgressBar
|
||||
from bec_widgets.widgets.services.bec_queue.bec_queue import BECQueue
|
||||
@ -102,7 +102,7 @@ class BECDockArea(BECWidget, QWidget):
|
||||
filled=True,
|
||||
),
|
||||
"image": MaterialIconAction(
|
||||
icon_name=BECImageWidget.ICON_NAME, tooltip="Add Image", filled=True
|
||||
icon_name=Image.ICON_NAME, tooltip="Add Image", filled=True
|
||||
),
|
||||
"motor_map": MaterialIconAction(
|
||||
icon_name=BECMotorMapWidget.ICON_NAME,
|
||||
@ -180,7 +180,7 @@ class BECDockArea(BECWidget, QWidget):
|
||||
lambda: self._create_widget_from_toolbar(widget_name="BECMultiWaveformWidget")
|
||||
)
|
||||
self.toolbar.widgets["menu_plots"].widgets["image"].triggered.connect(
|
||||
lambda: self._create_widget_from_toolbar(widget_name="BECImageWidget")
|
||||
lambda: self._create_widget_from_toolbar(widget_name="Image")
|
||||
)
|
||||
self.toolbar.widgets["menu_plots"].widgets["motor_map"].triggered.connect(
|
||||
lambda: self._create_widget_from_toolbar(widget_name="BECMotorMapWidget")
|
||||
|
@ -1 +0,0 @@
|
||||
{'files': ['image_widget.py']}
|
@ -1,58 +0,0 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
import os
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
|
||||
import bec_widgets
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from bec_widgets.widgets.plots.image.image_widget import BECImageWidget
|
||||
|
||||
DOM_XML = """
|
||||
<ui language='c++'>
|
||||
<widget class='BECImageWidget' name='bec_image_widget'>
|
||||
</widget>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
|
||||
|
||||
|
||||
class BECImageWidgetPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._form_editor = None
|
||||
|
||||
def createWidget(self, parent):
|
||||
t = BECImageWidget(parent)
|
||||
return t
|
||||
|
||||
def domXml(self):
|
||||
return DOM_XML
|
||||
|
||||
def group(self):
|
||||
return "BEC Plots"
|
||||
|
||||
def icon(self):
|
||||
return designer_material_icon(BECImageWidget.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "bec_image_widget"
|
||||
|
||||
def initialize(self, form_editor):
|
||||
self._form_editor = form_editor
|
||||
|
||||
def isContainer(self):
|
||||
return False
|
||||
|
||||
def isInitialized(self):
|
||||
return self._form_editor is not None
|
||||
|
||||
def name(self):
|
||||
return "BECImageWidget"
|
||||
|
||||
def toolTip(self):
|
||||
return "BECImageWidget"
|
||||
|
||||
def whatsThis(self):
|
||||
return self.toolTip()
|
@ -1,516 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from typing import Literal, Optional
|
||||
|
||||
import pyqtgraph as pg
|
||||
from bec_lib.device import ReadoutPriority
|
||||
from qtpy.QtWidgets import QComboBox, QVBoxLayout, QWidget
|
||||
|
||||
from bec_widgets.qt_utils.error_popups import SafeSlot, WarningPopupUtility
|
||||
from bec_widgets.qt_utils.settings_dialog import SettingsDialog
|
||||
from bec_widgets.qt_utils.toolbar import (
|
||||
DeviceSelectionAction,
|
||||
MaterialIconAction,
|
||||
ModularToolBar,
|
||||
SeparatorAction,
|
||||
WidgetAction,
|
||||
)
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
from bec_widgets.widgets.containers.figure import BECFigure
|
||||
from bec_widgets.widgets.containers.figure.plots.axis_settings import AxisSettings
|
||||
from bec_widgets.widgets.containers.figure.plots.image.image import ImageConfig
|
||||
from bec_widgets.widgets.containers.figure.plots.image.image_item import BECImageItem
|
||||
from bec_widgets.widgets.control.device_input.base_classes.device_input_base import BECDeviceFilter
|
||||
from bec_widgets.widgets.control.device_input.device_combobox.device_combobox import DeviceComboBox
|
||||
|
||||
|
||||
# TODO will be deprecated
|
||||
class BECImageWidget(BECWidget, QWidget):
|
||||
PLUGIN = True
|
||||
ICON_NAME = "image"
|
||||
USER_ACCESS = [
|
||||
"image",
|
||||
"set",
|
||||
"set_title",
|
||||
"set_x_label",
|
||||
"set_y_label",
|
||||
"set_x_scale",
|
||||
"set_y_scale",
|
||||
"set_x_lim",
|
||||
"set_y_lim",
|
||||
"set_vrange",
|
||||
"set_fft",
|
||||
"set_transpose",
|
||||
"set_rotation",
|
||||
"set_log",
|
||||
"set_grid",
|
||||
"enable_fps_monitor",
|
||||
"lock_aspect_ratio",
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent: QWidget | None = None,
|
||||
config: ImageConfig | dict = None,
|
||||
client=None,
|
||||
gui_id: str | None = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
if config is None:
|
||||
config = ImageConfig(widget_class=self.__class__.__name__)
|
||||
else:
|
||||
if isinstance(config, dict):
|
||||
config = ImageConfig(**config)
|
||||
super().__init__(client=client, gui_id=gui_id, **kwargs)
|
||||
QWidget.__init__(self, parent)
|
||||
self.layout = QVBoxLayout(self)
|
||||
self.layout.setSpacing(0)
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.fig = BECFigure()
|
||||
self.dim_combo_box = QComboBox()
|
||||
self.dim_combo_box.addItems(["1d", "2d"])
|
||||
self.toolbar = ModularToolBar(
|
||||
actions={
|
||||
"monitor": DeviceSelectionAction(
|
||||
"Monitor:",
|
||||
DeviceComboBox(
|
||||
device_filter=BECDeviceFilter.DEVICE,
|
||||
readout_priority_filter=[ReadoutPriority.ASYNC],
|
||||
),
|
||||
),
|
||||
"monitor_type": WidgetAction(widget=self.dim_combo_box),
|
||||
"connect": MaterialIconAction(icon_name="link", tooltip="Connect Device"),
|
||||
"separator_0": SeparatorAction(),
|
||||
"save": MaterialIconAction(icon_name="save", tooltip="Open Export Dialog"),
|
||||
"separator_1": SeparatorAction(),
|
||||
"drag_mode": MaterialIconAction(
|
||||
icon_name="open_with", tooltip="Drag Mouse Mode", checkable=True
|
||||
),
|
||||
"rectangle_mode": MaterialIconAction(
|
||||
icon_name="frame_inspect", tooltip="Rectangle Zoom Mode", checkable=True
|
||||
),
|
||||
"auto_range": MaterialIconAction(
|
||||
icon_name="open_in_full", tooltip="Autorange Plot"
|
||||
),
|
||||
"auto_range_image": MaterialIconAction(
|
||||
icon_name="hdr_auto", tooltip="Autorange Image Intensity", checkable=True
|
||||
),
|
||||
"aspect_ratio": MaterialIconAction(
|
||||
icon_name="aspect_ratio", tooltip="Lock image aspect ratio", checkable=True
|
||||
),
|
||||
"separator_2": SeparatorAction(),
|
||||
"FFT": MaterialIconAction(icon_name="fft", tooltip="Toggle FFT", checkable=True),
|
||||
"log": MaterialIconAction(
|
||||
icon_name="log_scale", tooltip="Toggle log scale", checkable=True
|
||||
),
|
||||
"transpose": MaterialIconAction(
|
||||
icon_name="transform", tooltip="Transpose Image", checkable=True
|
||||
),
|
||||
"rotate_right": MaterialIconAction(
|
||||
icon_name="rotate_right", tooltip="Rotate image clockwise by 90 deg"
|
||||
),
|
||||
"rotate_left": MaterialIconAction(
|
||||
icon_name="rotate_left", tooltip="Rotate image counterclockwise by 90 deg"
|
||||
),
|
||||
"reset": MaterialIconAction(
|
||||
icon_name="reset_settings", tooltip="Reset Image Settings"
|
||||
),
|
||||
"separator_3": SeparatorAction(),
|
||||
"fps_monitor": MaterialIconAction(
|
||||
icon_name="speed", tooltip="Show FPS Monitor", checkable=True
|
||||
),
|
||||
"axis_settings": MaterialIconAction(
|
||||
icon_name="settings", tooltip="Open Configuration Dialog"
|
||||
),
|
||||
},
|
||||
target_widget=self,
|
||||
)
|
||||
|
||||
self.layout.addWidget(self.toolbar)
|
||||
self.layout.addWidget(self.fig)
|
||||
|
||||
self.warning_util = WarningPopupUtility(self)
|
||||
|
||||
self._image = self.fig.image()
|
||||
self._image.apply_config(config)
|
||||
self.rotation = 0
|
||||
|
||||
self.config = config
|
||||
|
||||
self._hook_actions()
|
||||
|
||||
self.toolbar.widgets["drag_mode"].action.setChecked(True)
|
||||
self.toolbar.widgets["auto_range_image"].action.setChecked(True)
|
||||
|
||||
def _hook_actions(self):
|
||||
self.toolbar.widgets["connect"].action.triggered.connect(self._connect_action)
|
||||
# sepatator
|
||||
self.toolbar.widgets["save"].action.triggered.connect(self.export)
|
||||
# sepatator
|
||||
self.toolbar.widgets["drag_mode"].action.triggered.connect(self.enable_mouse_pan_mode)
|
||||
self.toolbar.widgets["rectangle_mode"].action.triggered.connect(
|
||||
self.enable_mouse_rectangle_mode
|
||||
)
|
||||
self.toolbar.widgets["auto_range"].action.triggered.connect(self.toggle_auto_range)
|
||||
self.toolbar.widgets["auto_range_image"].action.triggered.connect(
|
||||
self.toggle_image_autorange
|
||||
)
|
||||
self.toolbar.widgets["aspect_ratio"].action.triggered.connect(self.toggle_aspect_ratio)
|
||||
# sepatator
|
||||
self.toolbar.widgets["FFT"].action.triggered.connect(self.toggle_fft)
|
||||
self.toolbar.widgets["log"].action.triggered.connect(self.toggle_log)
|
||||
self.toolbar.widgets["transpose"].action.triggered.connect(self.toggle_transpose)
|
||||
self.toolbar.widgets["rotate_left"].action.triggered.connect(self.rotate_left)
|
||||
self.toolbar.widgets["rotate_right"].action.triggered.connect(self.rotate_right)
|
||||
self.toolbar.widgets["reset"].action.triggered.connect(self.reset_settings)
|
||||
# sepatator
|
||||
self.toolbar.widgets["axis_settings"].action.triggered.connect(self.show_axis_settings)
|
||||
self.toolbar.widgets["fps_monitor"].action.toggled.connect(self.enable_fps_monitor)
|
||||
|
||||
###################################
|
||||
# Dialog Windows
|
||||
###################################
|
||||
@SafeSlot(popup_error=True)
|
||||
def _connect_action(self):
|
||||
monitor_combo = self.toolbar.widgets["monitor"].device_combobox
|
||||
monitor_name = monitor_combo.currentText()
|
||||
monitor_type = self.toolbar.widgets["monitor_type"].widget.currentText()
|
||||
self.image(monitor=monitor_name, monitor_type=monitor_type)
|
||||
monitor_combo.setStyleSheet("QComboBox { background-color: " "; }")
|
||||
|
||||
def show_axis_settings(self):
|
||||
dialog = SettingsDialog(
|
||||
self,
|
||||
settings_widget=AxisSettings(),
|
||||
window_title="Axis Settings",
|
||||
config=self._config_dict["axis"],
|
||||
)
|
||||
dialog.exec()
|
||||
|
||||
###################################
|
||||
# User Access Methods from image
|
||||
###################################
|
||||
@SafeSlot(popup_error=True)
|
||||
def image(
|
||||
self,
|
||||
monitor: str,
|
||||
monitor_type: Optional[Literal["1d", "2d"]] = "2d",
|
||||
color_map: Optional[str] = "magma",
|
||||
color_bar: Optional[Literal["simple", "full"]] = "full",
|
||||
downsample: Optional[bool] = True,
|
||||
opacity: Optional[float] = 1.0,
|
||||
vrange: Optional[tuple[int, int]] = None,
|
||||
# post_processing: Optional[PostProcessingConfig] = None,
|
||||
**kwargs,
|
||||
) -> BECImageItem:
|
||||
if self.toolbar.widgets["monitor"].device_combobox.currentText() != monitor:
|
||||
self.toolbar.widgets["monitor"].device_combobox.setCurrentText(monitor)
|
||||
self.toolbar.widgets["monitor"].device_combobox.setStyleSheet(
|
||||
"QComboBox {{ background-color: " "; }}"
|
||||
)
|
||||
if self.toolbar.widgets["monitor_type"].widget.currentText() != monitor_type:
|
||||
self.toolbar.widgets["monitor_type"].widget.setCurrentText(monitor_type)
|
||||
self.toolbar.widgets["monitor_type"].widget.setStyleSheet(
|
||||
"QComboBox {{ background-color: " "; }}"
|
||||
)
|
||||
return self._image.image(
|
||||
monitor=monitor,
|
||||
monitor_type=monitor_type,
|
||||
color_map=color_map,
|
||||
color_bar=color_bar,
|
||||
downsample=downsample,
|
||||
opacity=opacity,
|
||||
vrange=vrange,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def set_vrange(self, vmin: float, vmax: float, name: str = None):
|
||||
"""
|
||||
Set the range of the color bar.
|
||||
If name is not specified, then set vrange for all images.
|
||||
|
||||
Args:
|
||||
vmin(float): Minimum value of the color bar.
|
||||
vmax(float): Maximum value of the color bar.
|
||||
name(str): The name of the image. If None, apply to all images.
|
||||
"""
|
||||
self._image.set_vrange(vmin, vmax, name)
|
||||
|
||||
def set_color_map(self, color_map: str, name: str = None):
|
||||
"""
|
||||
Set the color map of the image.
|
||||
If name is not specified, then set color map for all images.
|
||||
|
||||
Args:
|
||||
cmap(str): The color map of the image.
|
||||
name(str): The name of the image. If None, apply to all images.
|
||||
"""
|
||||
self._image.set_color_map(color_map, name)
|
||||
|
||||
def set_fft(self, enable: bool = False, name: str = None):
|
||||
"""
|
||||
Set the FFT of the image.
|
||||
If name is not specified, then set FFT for all images.
|
||||
|
||||
Args:
|
||||
enable(bool): Whether to perform FFT on the monitor data.
|
||||
name(str): The name of the image. If None, apply to all images.
|
||||
"""
|
||||
self._image.set_fft(enable, name)
|
||||
self.toolbar.widgets["FFT"].action.setChecked(enable)
|
||||
|
||||
def set_transpose(self, enable: bool = False, name: str = None):
|
||||
"""
|
||||
Set the transpose of the image.
|
||||
If name is not specified, then set transpose for all images.
|
||||
|
||||
Args:
|
||||
enable(bool): Whether to transpose the monitor data before displaying.
|
||||
name(str): The name of the image. If None, apply to all images.
|
||||
"""
|
||||
self._image.set_transpose(enable, name)
|
||||
self.toolbar.widgets["transpose"].action.setChecked(enable)
|
||||
|
||||
def set_rotation(self, deg_90: int = 0, name: str = None):
|
||||
"""
|
||||
Set the rotation of the image.
|
||||
If name is not specified, then set rotation for all images.
|
||||
|
||||
Args:
|
||||
deg_90(int): The rotation angle of the monitor data before displaying.
|
||||
name(str): The name of the image. If None, apply to all images.
|
||||
"""
|
||||
self._image.set_rotation(deg_90, name)
|
||||
|
||||
def set_log(self, enable: bool = False, name: str = None):
|
||||
"""
|
||||
Set the log of the image.
|
||||
If name is not specified, then set log for all images.
|
||||
|
||||
Args:
|
||||
enable(bool): Whether to perform log on the monitor data.
|
||||
name(str): The name of the image. If None, apply to all images.
|
||||
"""
|
||||
self._image.set_log(enable, name)
|
||||
self.toolbar.widgets["log"].action.setChecked(enable)
|
||||
|
||||
###################################
|
||||
# User Access Methods from Plotbase
|
||||
###################################
|
||||
|
||||
def set(self, **kwargs):
|
||||
"""
|
||||
Set the properties of the plot widget.
|
||||
|
||||
Args:
|
||||
**kwargs: Keyword arguments for the properties to be set.
|
||||
|
||||
Possible properties:
|
||||
- title: str
|
||||
- x_label: str
|
||||
- y_label: str
|
||||
- x_scale: Literal["linear", "log"]
|
||||
- y_scale: Literal["linear", "log"]
|
||||
- x_lim: tuple
|
||||
- y_lim: tuple
|
||||
- legend_label_size: int
|
||||
"""
|
||||
self._image.set(**kwargs)
|
||||
|
||||
def set_title(self, title: str):
|
||||
"""
|
||||
Set the title of the plot widget.
|
||||
|
||||
Args:
|
||||
title(str): Title of the plot.
|
||||
"""
|
||||
self._image.set_title(title)
|
||||
|
||||
def set_x_label(self, x_label: str):
|
||||
"""
|
||||
Set the x-axis label of the plot widget.
|
||||
|
||||
Args:
|
||||
x_label(str): Label of the x-axis.
|
||||
"""
|
||||
self._image.set_x_label(x_label)
|
||||
|
||||
def set_y_label(self, y_label: str):
|
||||
"""
|
||||
Set the y-axis label of the plot widget.
|
||||
|
||||
Args:
|
||||
y_label(str): Label of the y-axis.
|
||||
"""
|
||||
self._image.set_y_label(y_label)
|
||||
|
||||
def set_x_scale(self, x_scale: Literal["linear", "log"]):
|
||||
"""
|
||||
Set the scale of the x-axis of the plot widget.
|
||||
|
||||
Args:
|
||||
x_scale(Literal["linear", "log"]): Scale of the x-axis.
|
||||
"""
|
||||
self._image.set_x_scale(x_scale)
|
||||
|
||||
def set_y_scale(self, y_scale: Literal["linear", "log"]):
|
||||
"""
|
||||
Set the scale of the y-axis of the plot widget.
|
||||
|
||||
Args:
|
||||
y_scale(Literal["linear", "log"]): Scale of the y-axis.
|
||||
"""
|
||||
self._image.set_y_scale(y_scale)
|
||||
|
||||
def set_x_lim(self, x_lim: tuple):
|
||||
"""
|
||||
Set the limits of the x-axis of the plot widget.
|
||||
|
||||
Args:
|
||||
x_lim(tuple): Limits of the x-axis.
|
||||
"""
|
||||
self._image.set_x_lim(x_lim)
|
||||
|
||||
def set_y_lim(self, y_lim: tuple):
|
||||
"""
|
||||
Set the limits of the y-axis of the plot widget.
|
||||
|
||||
Args:
|
||||
y_lim(tuple): Limits of the y-axis.
|
||||
"""
|
||||
self._image.set_y_lim(y_lim)
|
||||
|
||||
def set_grid(self, x_grid: bool, y_grid: bool):
|
||||
"""
|
||||
Set the grid visibility of the plot widget.
|
||||
|
||||
Args:
|
||||
x_grid(bool): Visibility of the x-axis grid.
|
||||
y_grid(bool): Visibility of the y-axis grid.
|
||||
"""
|
||||
self._image.set_grid(x_grid, y_grid)
|
||||
|
||||
def lock_aspect_ratio(self, lock: bool):
|
||||
"""
|
||||
Lock the aspect ratio of the plot widget.
|
||||
|
||||
Args:
|
||||
lock(bool): Lock the aspect ratio.
|
||||
"""
|
||||
self._image.lock_aspect_ratio(lock)
|
||||
|
||||
###################################
|
||||
# Toolbar Actions
|
||||
###################################
|
||||
@SafeSlot()
|
||||
def toggle_auto_range(self):
|
||||
"""
|
||||
Set the auto range of the plot widget from the toolbar.
|
||||
"""
|
||||
self._image.set_auto_range(True, "xy")
|
||||
|
||||
@SafeSlot()
|
||||
def toggle_fft(self):
|
||||
checked = self.toolbar.widgets["FFT"].action.isChecked()
|
||||
self.set_fft(checked)
|
||||
|
||||
@SafeSlot()
|
||||
def toggle_log(self):
|
||||
checked = self.toolbar.widgets["log"].action.isChecked()
|
||||
self.set_log(checked)
|
||||
|
||||
@SafeSlot()
|
||||
def toggle_transpose(self):
|
||||
checked = self.toolbar.widgets["transpose"].action.isChecked()
|
||||
self.set_transpose(checked)
|
||||
|
||||
@SafeSlot()
|
||||
def rotate_left(self):
|
||||
self.rotation = (self.rotation + 1) % 4
|
||||
self.set_rotation(self.rotation)
|
||||
|
||||
@SafeSlot()
|
||||
def rotate_right(self):
|
||||
self.rotation = (self.rotation - 1) % 4
|
||||
self.set_rotation(self.rotation)
|
||||
|
||||
@SafeSlot()
|
||||
def reset_settings(self):
|
||||
self.set_log(False)
|
||||
self.set_fft(False)
|
||||
self.set_transpose(False)
|
||||
self.rotation = 0
|
||||
self.set_rotation(0)
|
||||
|
||||
self.toolbar.widgets["FFT"].action.setChecked(False)
|
||||
self.toolbar.widgets["log"].action.setChecked(False)
|
||||
self.toolbar.widgets["transpose"].action.setChecked(False)
|
||||
|
||||
@SafeSlot()
|
||||
def toggle_image_autorange(self):
|
||||
"""
|
||||
Enable the auto range of the image intensity.
|
||||
"""
|
||||
checked = self.toolbar.widgets["auto_range_image"].action.isChecked()
|
||||
self._image.set_autorange(checked)
|
||||
|
||||
@SafeSlot()
|
||||
def toggle_aspect_ratio(self):
|
||||
"""
|
||||
Enable the auto range of the image intensity.
|
||||
"""
|
||||
checked = self.toolbar.widgets["aspect_ratio"].action.isChecked()
|
||||
self._image.lock_aspect_ratio(checked)
|
||||
|
||||
@SafeSlot()
|
||||
def enable_mouse_rectangle_mode(self):
|
||||
self.toolbar.widgets["rectangle_mode"].action.setChecked(True)
|
||||
self.toolbar.widgets["drag_mode"].action.setChecked(False)
|
||||
self._image.plot_item.getViewBox().setMouseMode(pg.ViewBox.RectMode)
|
||||
|
||||
@SafeSlot()
|
||||
def enable_mouse_pan_mode(self):
|
||||
self.toolbar.widgets["drag_mode"].action.setChecked(True)
|
||||
self.toolbar.widgets["rectangle_mode"].action.setChecked(False)
|
||||
self._image.plot_item.getViewBox().setMouseMode(pg.ViewBox.PanMode)
|
||||
|
||||
@SafeSlot()
|
||||
def enable_fps_monitor(self, enabled: bool):
|
||||
"""
|
||||
Enable the FPS monitor of the plot widget.
|
||||
|
||||
Args:
|
||||
enabled(bool): If True, enable the FPS monitor.
|
||||
"""
|
||||
self._image.enable_fps_monitor(enabled)
|
||||
if self.toolbar.widgets["fps_monitor"].action.isChecked() != enabled:
|
||||
self.toolbar.widgets["fps_monitor"].action.setChecked(enabled)
|
||||
|
||||
def export(self):
|
||||
"""
|
||||
Show the export dialog for the plot widget.
|
||||
"""
|
||||
self._image.export()
|
||||
|
||||
def cleanup(self):
|
||||
self.fig.cleanup()
|
||||
self.toolbar.close()
|
||||
self.toolbar.deleteLater()
|
||||
return super().cleanup()
|
||||
|
||||
|
||||
def main(): # pragma: no cover
|
||||
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
widget = BECImageWidget()
|
||||
widget.image("waveform", "1d")
|
||||
widget.show()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
@ -1,15 +0,0 @@
|
||||
def main(): # pragma: no cover
|
||||
from qtpy import PYSIDE6
|
||||
|
||||
if not PYSIDE6:
|
||||
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
||||
return
|
||||
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
||||
|
||||
from bec_widgets.widgets.plots.image.bec_image_widget_plugin import BECImageWidgetPlugin
|
||||
|
||||
QPyDesignerCustomWidgetCollection.addCustomWidget(BECImageWidgetPlugin())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
@ -120,10 +120,8 @@ def test_toolbar_add_plot_waveform(bec_dock_area):
|
||||
|
||||
def test_toolbar_add_plot_image(bec_dock_area):
|
||||
bec_dock_area.toolbar.widgets["menu_plots"].widgets["image"].trigger()
|
||||
assert "BECImageWidget_0" in bec_dock_area.panels
|
||||
assert (
|
||||
bec_dock_area.panels["BECImageWidget_0"].widgets[0].config.widget_class == "BECImageWidget"
|
||||
)
|
||||
assert "Image_0" in bec_dock_area.panels
|
||||
assert bec_dock_area.panels["Image_0"].widgets[0].config.widget_class == "Image"
|
||||
|
||||
|
||||
def test_toolbar_add_plot_motor_map(bec_dock_area):
|
||||
|
@ -1,224 +0,0 @@
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pyqtgraph as pg
|
||||
import pytest
|
||||
|
||||
from bec_widgets.widgets.control.device_input.base_classes.device_input_base import BECDeviceFilter
|
||||
from bec_widgets.widgets.plots.image.image_widget import BECImageWidget
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def image_widget(qtbot, mocked_client):
|
||||
widget = BECImageWidget(client=mocked_client())
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_image(image_widget):
|
||||
image_mock = MagicMock()
|
||||
image_widget._image = image_mock
|
||||
return image_mock
|
||||
|
||||
|
||||
def test_image_widget_init(image_widget):
|
||||
assert image_widget is not None
|
||||
assert image_widget.client is not None
|
||||
assert isinstance(image_widget, BECImageWidget)
|
||||
assert image_widget.config.widget_class == "BECImageWidget"
|
||||
assert image_widget._image is not None
|
||||
|
||||
assert (
|
||||
BECDeviceFilter.DEVICE
|
||||
in image_widget.toolbar.widgets["monitor"].device_combobox.config.device_filter
|
||||
)
|
||||
assert image_widget.toolbar.widgets["drag_mode"].action.isChecked() == True
|
||||
assert image_widget.toolbar.widgets["rectangle_mode"].action.isChecked() == False
|
||||
assert image_widget.toolbar.widgets["auto_range"].action.isChecked() == False
|
||||
assert image_widget.toolbar.widgets["auto_range_image"].action.isChecked() == True
|
||||
assert image_widget.toolbar.widgets["FFT"].action.isChecked() == False
|
||||
assert image_widget.toolbar.widgets["transpose"].action.isChecked() == False
|
||||
assert image_widget.toolbar.widgets["log"].action.isChecked() == False
|
||||
|
||||
|
||||
###################################
|
||||
# Toolbar Actions
|
||||
###################################
|
||||
def test_toolbar_connect_action(image_widget, mock_image, qtbot):
|
||||
combo_device = image_widget.toolbar.widgets["monitor"].device_combobox
|
||||
combo_device.setCurrentText("eiger")
|
||||
qtbot.wait(200)
|
||||
assert combo_device.currentText() == "eiger"
|
||||
combo_dim = image_widget.toolbar.widgets["monitor_type"].widget
|
||||
combo_dim.setCurrentText("2d")
|
||||
qtbot.wait(200)
|
||||
assert combo_dim.currentText() == "2d"
|
||||
action = image_widget.toolbar.widgets["connect"].action
|
||||
action.trigger()
|
||||
image_widget._image.image.assert_called_once_with(
|
||||
monitor="eiger",
|
||||
monitor_type="2d",
|
||||
color_map="magma",
|
||||
color_bar="full",
|
||||
downsample=True,
|
||||
opacity=1.0,
|
||||
vrange=None,
|
||||
)
|
||||
|
||||
|
||||
def test_image_toolbar_drag_mode_action_triggered(image_widget, qtbot):
|
||||
action_drag = image_widget.toolbar.widgets["drag_mode"].action
|
||||
action_rectangle = image_widget.toolbar.widgets["rectangle_mode"].action
|
||||
action_drag.trigger()
|
||||
assert action_drag.isChecked() == True
|
||||
assert action_rectangle.isChecked() == False
|
||||
|
||||
|
||||
def test_image_toolbar_rectangle_mode_action_triggered(image_widget, qtbot):
|
||||
action_drag = image_widget.toolbar.widgets["drag_mode"].action
|
||||
action_rectangle = image_widget.toolbar.widgets["rectangle_mode"].action
|
||||
action_rectangle.trigger()
|
||||
assert action_drag.isChecked() == False
|
||||
assert action_rectangle.isChecked() == True
|
||||
|
||||
|
||||
def test_image_toolbar_auto_range(image_widget, mock_image):
|
||||
action = image_widget.toolbar.widgets["auto_range"].action
|
||||
action.trigger()
|
||||
image_widget._image.set_auto_range.assert_called_once_with(True, "xy")
|
||||
|
||||
|
||||
def test_image_toolbar_enable_mouse_pan_mode(qtbot, image_widget):
|
||||
action_drag = image_widget.toolbar.widgets["drag_mode"].action
|
||||
action_rectangle = image_widget.toolbar.widgets["rectangle_mode"].action
|
||||
|
||||
mock_view_box = MagicMock()
|
||||
image_widget._image.plot_item.getViewBox = MagicMock(return_value=mock_view_box)
|
||||
|
||||
image_widget.enable_mouse_pan_mode()
|
||||
|
||||
assert action_drag.isChecked() == True
|
||||
assert action_rectangle.isChecked() == False
|
||||
mock_view_box.setMouseMode.assert_called_once_with(pg.ViewBox.PanMode)
|
||||
|
||||
|
||||
def test_image_toolbar_auto_range_image(image_widget, mock_image):
|
||||
action = image_widget.toolbar.widgets["auto_range_image"].action
|
||||
action.trigger()
|
||||
assert action.isChecked() == False
|
||||
image_widget._image.set_autorange.assert_called_once_with(False)
|
||||
|
||||
|
||||
def test_image_toolbar_FFT(image_widget, mock_image):
|
||||
action = image_widget.toolbar.widgets["FFT"].action
|
||||
action.trigger()
|
||||
assert action.isChecked() == True
|
||||
image_widget._image.set_fft.assert_called_once_with(True, None)
|
||||
|
||||
|
||||
def test_image_toolbar_log(image_widget, mock_image):
|
||||
action = image_widget.toolbar.widgets["log"].action
|
||||
action.trigger()
|
||||
assert action.isChecked() == True
|
||||
image_widget._image.set_log.assert_called_once_with(True, None)
|
||||
|
||||
|
||||
def test_image_toggle_transpose(image_widget, mock_image):
|
||||
action = image_widget.toolbar.widgets["transpose"].action
|
||||
action.trigger()
|
||||
assert action.isChecked() == True
|
||||
image_widget._image.set_transpose.assert_called_once_with(True, None)
|
||||
|
||||
|
||||
def test_image_toolbar_rotation(image_widget, mock_image):
|
||||
action_left = image_widget.toolbar.widgets["rotate_left"].action
|
||||
action_right = image_widget.toolbar.widgets["rotate_right"].action
|
||||
|
||||
action_left.trigger()
|
||||
image_widget._image.set_rotation(1, None)
|
||||
action_right.trigger()
|
||||
image_widget._image.set_rotation(2, None)
|
||||
|
||||
action_right.trigger()
|
||||
image_widget._image.set_rotation(1, None)
|
||||
|
||||
|
||||
###################################
|
||||
# Wrapper methods for ImageShow
|
||||
###################################
|
||||
|
||||
|
||||
def test_image_set_image(image_widget, mock_image):
|
||||
image_widget.image(monitor="image", monitor_type="2d")
|
||||
image_widget._image.image.assert_called_once_with(
|
||||
monitor="image",
|
||||
monitor_type="2d",
|
||||
color_map="magma",
|
||||
color_bar="full",
|
||||
downsample=True,
|
||||
opacity=1.0,
|
||||
vrange=None,
|
||||
)
|
||||
|
||||
|
||||
def test_image_vrange(image_widget, mock_image):
|
||||
image_widget.set_vrange(0, 1)
|
||||
image_widget._image.set_vrange.assert_called_once_with(0, 1, None)
|
||||
|
||||
|
||||
def test_image_set_color_map(image_widget, mock_image):
|
||||
image_widget.set_color_map("viridis")
|
||||
image_widget._image.set_color_map.assert_called_once_with("viridis", None)
|
||||
|
||||
|
||||
def test_image_widget_set_title(image_widget, mock_image):
|
||||
image_widget.set_title("Title Label")
|
||||
image_widget._image.set_title.assert_called_once_with("Title Label")
|
||||
|
||||
|
||||
def test_image_widget_set_x_label(image_widget, mock_image):
|
||||
image_widget.set_x_label("X Label")
|
||||
image_widget._image.set_x_label.assert_called_once_with("X Label")
|
||||
|
||||
|
||||
def test_image_widget_set_y_label(image_widget, mock_image):
|
||||
image_widget.set_y_label("Y Label")
|
||||
image_widget._image.set_y_label.assert_called_once_with("Y Label")
|
||||
|
||||
|
||||
def test_image_widget_set_x_scale(image_widget, mock_image):
|
||||
image_widget.set_x_scale("linear")
|
||||
image_widget._image.set_x_scale.assert_called_once_with("linear")
|
||||
|
||||
|
||||
def test_image_widget_set_y_scale(image_widget, mock_image):
|
||||
image_widget.set_y_scale("log")
|
||||
image_widget._image.set_y_scale.assert_called_once_with("log")
|
||||
|
||||
|
||||
def test_image_widget_set_x_lim(image_widget, mock_image):
|
||||
image_widget.set_x_lim((0, 10))
|
||||
image_widget._image.set_x_lim.assert_called_once_with((0, 10))
|
||||
|
||||
|
||||
def test_image_widget_set_y_lim(image_widget, mock_image):
|
||||
image_widget.set_y_lim((0, 10))
|
||||
image_widget._image.set_y_lim.assert_called_once_with((0, 10))
|
||||
|
||||
|
||||
def test_image_widget_set_grid(image_widget, mock_image):
|
||||
image_widget.set_grid(True, False)
|
||||
image_widget._image.set_grid.assert_called_once_with(True, False)
|
||||
|
||||
|
||||
def test_image_widget_lock_aspect_ratio(image_widget, mock_image):
|
||||
image_widget.lock_aspect_ratio(True)
|
||||
image_widget._image.lock_aspect_ratio.assert_called_once_with(True)
|
||||
|
||||
|
||||
def test_image_widget_export(image_widget, mock_image):
|
||||
image_widget.export()
|
||||
image_widget._image.export.assert_called_once()
|
Reference in New Issue
Block a user