0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 11:41:49 +02:00

refactor(image_widget): old BECImageWidget removed

This commit is contained in:
2025-03-11 14:12:16 +01:00
parent cb39ff3fbd
commit de10609b3c
9 changed files with 649 additions and 1672 deletions

File diff suppressed because it is too large Load Diff

View File

@ -53,10 +53,7 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
"w9": self.w9, "w9": self.w9,
"w10": self.w10, "w10": self.w10,
"d0": self.d0, "d0": self.d0,
"d1": self.d1,
"im": self.im, "im": self.im,
"im_old": self.im_old,
"it_old": self.it_old,
"mi": self.mi, "mi": self.mi,
"mm": self.mm, "mm": self.mm,
"mw": self.mw, "mw": self.mw,
@ -216,11 +213,6 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
self.mm = self.d0.new("BECMotorMapWidget") self.mm = self.d0.new("BECMotorMapWidget")
self.mm.change_motors("samx", "samy") 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.mw = None # self.wf.multi_waveform(monitor="waveform") # , config=config)
self.dock.save_state() self.dock.save_state()

View File

@ -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.device_control.positioner_box import PositionerBox
from bec_widgets.widgets.control.scan_control.scan_control import ScanControl from bec_widgets.widgets.control.scan_control.scan_control import ScanControl
from bec_widgets.widgets.editors.vscode.vscode import VSCodeEditor 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.motor_map.motor_map_widget import BECMotorMapWidget
from bec_widgets.widgets.plots.multi_waveform.multi_waveform_widget import BECMultiWaveformWidget 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.plots_next_gen.waveform.waveform import Waveform
from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_bar import RingProgressBar from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_bar import RingProgressBar
from bec_widgets.widgets.services.bec_queue.bec_queue import BECQueue from bec_widgets.widgets.services.bec_queue.bec_queue import BECQueue
@ -102,7 +102,7 @@ class BECDockArea(BECWidget, QWidget):
filled=True, filled=True,
), ),
"image": MaterialIconAction( "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( "motor_map": MaterialIconAction(
icon_name=BECMotorMapWidget.ICON_NAME, icon_name=BECMotorMapWidget.ICON_NAME,
@ -180,7 +180,7 @@ class BECDockArea(BECWidget, QWidget):
lambda: self._create_widget_from_toolbar(widget_name="BECMultiWaveformWidget") lambda: self._create_widget_from_toolbar(widget_name="BECMultiWaveformWidget")
) )
self.toolbar.widgets["menu_plots"].widgets["image"].triggered.connect( 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( self.toolbar.widgets["menu_plots"].widgets["motor_map"].triggered.connect(
lambda: self._create_widget_from_toolbar(widget_name="BECMotorMapWidget") lambda: self._create_widget_from_toolbar(widget_name="BECMotorMapWidget")

View File

@ -1 +0,0 @@
{'files': ['image_widget.py']}

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -120,10 +120,8 @@ def test_toolbar_add_plot_waveform(bec_dock_area):
def test_toolbar_add_plot_image(bec_dock_area): def test_toolbar_add_plot_image(bec_dock_area):
bec_dock_area.toolbar.widgets["menu_plots"].widgets["image"].trigger() bec_dock_area.toolbar.widgets["menu_plots"].widgets["image"].trigger()
assert "BECImageWidget_0" in bec_dock_area.panels assert "Image_0" in bec_dock_area.panels
assert ( assert bec_dock_area.panels["Image_0"].widgets[0].config.widget_class == "Image"
bec_dock_area.panels["BECImageWidget_0"].widgets[0].config.widget_class == "BECImageWidget"
)
def test_toolbar_add_plot_motor_map(bec_dock_area): def test_toolbar_add_plot_motor_map(bec_dock_area):

View File

@ -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()