mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-04-14 04:30:54 +02:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ea467c5fc | ||
| 4f69f5da45 | |||
| d8547c7a56 | |||
| 3484507c75 | |||
| 8abebb7286 |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,6 +1,27 @@
|
||||
# CHANGELOG
|
||||
|
||||
|
||||
## v2.8.0 (2025-05-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **ImageProcessing**: Use target widget as parent
|
||||
([`d8547c7`](https://github.com/bec-project/bec_widgets/commit/d8547c7a56cea72dd41a2020c47adfd93969139f))
|
||||
|
||||
### Features
|
||||
|
||||
- **plot_base**: Add option to specify units
|
||||
([`3484507`](https://github.com/bec-project/bec_widgets/commit/3484507c75500dc1b1a53853ff01937ad9ad8913))
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **server**: Minor cleanup of imports
|
||||
([`8abebb7`](https://github.com/bec-project/bec_widgets/commit/8abebb72862c44d32a24f5e692319dec7a0891bf))
|
||||
|
||||
- **toolbar**: Add warning if no parent is provided as it may lead to segfaults
|
||||
([`4f69f5d`](https://github.com/bec-project/bec_widgets/commit/4f69f5da45420d92fd985801a8920ecf10166554))
|
||||
|
||||
|
||||
## v2.7.1 (2025-05-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -6,7 +6,6 @@ import os
|
||||
import signal
|
||||
import sys
|
||||
from contextlib import redirect_stderr, redirect_stdout
|
||||
from typing import cast
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_lib.service_config import ServiceConfig
|
||||
|
||||
@@ -7,6 +7,7 @@ from abc import ABC, abstractmethod
|
||||
from collections import defaultdict
|
||||
from typing import Dict, List, Literal, Tuple
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_qthemes._icon.material_icons import material_icon
|
||||
from qtpy.QtCore import QSize, Qt, QTimer
|
||||
from qtpy.QtGui import QAction, QColor, QIcon
|
||||
@@ -31,6 +32,8 @@ from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import
|
||||
|
||||
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
# Ensure that icons are shown in menus (especially on macOS)
|
||||
QApplication.setAttribute(Qt.AA_DontShowIconsInMenus, False)
|
||||
|
||||
@@ -173,6 +176,10 @@ class MaterialIconAction(ToolBarAction):
|
||||
filled=self.filled,
|
||||
color=self.color,
|
||||
)
|
||||
if parent is None:
|
||||
logger.warning(
|
||||
"MaterialIconAction was created without a parent. Please consider adding one. Using None as parent may cause issues."
|
||||
)
|
||||
self.action = QAction(icon=self.icon, text=self.tooltip, parent=parent)
|
||||
self.action.setCheckable(self.checkable)
|
||||
|
||||
|
||||
@@ -11,18 +11,31 @@ class ImageProcessingToolbarBundle(ToolbarBundle):
|
||||
super().__init__(bundle_id=bundle_id, actions=[], **kwargs)
|
||||
self.target_widget = target_widget
|
||||
|
||||
self.fft = MaterialIconAction(icon_name="fft", tooltip="Toggle FFT", checkable=True)
|
||||
self.log = MaterialIconAction(icon_name="log_scale", tooltip="Toggle Log", checkable=True)
|
||||
self.fft = MaterialIconAction(
|
||||
icon_name="fft", tooltip="Toggle FFT", checkable=True, parent=self.target_widget
|
||||
)
|
||||
self.log = MaterialIconAction(
|
||||
icon_name="log_scale", tooltip="Toggle Log", checkable=True, parent=self.target_widget
|
||||
)
|
||||
self.transpose = MaterialIconAction(
|
||||
icon_name="transform", tooltip="Transpose Image", checkable=True
|
||||
icon_name="transform",
|
||||
tooltip="Transpose Image",
|
||||
checkable=True,
|
||||
parent=self.target_widget,
|
||||
)
|
||||
self.right = MaterialIconAction(
|
||||
icon_name="rotate_right", tooltip="Rotate image clockwise by 90 deg"
|
||||
icon_name="rotate_right",
|
||||
tooltip="Rotate image clockwise by 90 deg",
|
||||
parent=self.target_widget,
|
||||
)
|
||||
self.left = MaterialIconAction(
|
||||
icon_name="rotate_left", tooltip="Rotate image counterclockwise by 90 deg"
|
||||
icon_name="rotate_left",
|
||||
tooltip="Rotate image counterclockwise by 90 deg",
|
||||
parent=self.target_widget,
|
||||
)
|
||||
self.reset = MaterialIconAction(
|
||||
icon_name="reset_settings", tooltip="Reset Image Settings", parent=self.target_widget
|
||||
)
|
||||
self.reset = MaterialIconAction(icon_name="reset_settings", tooltip="Reset Image Settings")
|
||||
|
||||
self.add_action("fft", self.fft)
|
||||
self.add_action("log", self.log)
|
||||
|
||||
@@ -112,8 +112,10 @@ class PlotBase(BECWidget, QWidget):
|
||||
self.fps_label = QLabel(alignment=Qt.AlignmentFlag.AlignRight)
|
||||
self._user_x_label = ""
|
||||
self._x_label_suffix = ""
|
||||
self._x_axis_units = ""
|
||||
self._user_y_label = ""
|
||||
self._y_label_suffix = ""
|
||||
self._y_axis_units = ""
|
||||
|
||||
# Plot Indicator Items
|
||||
self.tick_item = BECTickItem(parent=self, plot_item=self.plot_item)
|
||||
@@ -473,12 +475,31 @@ class PlotBase(BECWidget, QWidget):
|
||||
self._x_label_suffix = suffix
|
||||
self._apply_x_label()
|
||||
|
||||
@property
|
||||
def x_label_units(self) -> str:
|
||||
"""
|
||||
The units of the x-axis.
|
||||
"""
|
||||
return self._x_axis_units
|
||||
|
||||
@x_label_units.setter
|
||||
def x_label_units(self, units: str):
|
||||
"""
|
||||
The units of the x-axis.
|
||||
|
||||
Args:
|
||||
units(str): The units to set.
|
||||
"""
|
||||
self._x_axis_units = units
|
||||
self._apply_x_label()
|
||||
|
||||
@property
|
||||
def x_label_combined(self) -> str:
|
||||
"""
|
||||
The final label shown on the axis = user portion + suffix.
|
||||
The final label shown on the axis = user portion + suffix + [units].
|
||||
"""
|
||||
return self._user_x_label + self._x_label_suffix
|
||||
units = f" [{self._x_axis_units}]" if self._x_axis_units else ""
|
||||
return self._user_x_label + self._x_label_suffix + units
|
||||
|
||||
def _apply_x_label(self):
|
||||
"""
|
||||
@@ -521,12 +542,31 @@ class PlotBase(BECWidget, QWidget):
|
||||
self._y_label_suffix = suffix
|
||||
self._apply_y_label()
|
||||
|
||||
@property
|
||||
def y_label_units(self) -> str:
|
||||
"""
|
||||
The units of the y-axis.
|
||||
"""
|
||||
return self._y_axis_units
|
||||
|
||||
@y_label_units.setter
|
||||
def y_label_units(self, units: str):
|
||||
"""
|
||||
The units of the y-axis.
|
||||
|
||||
Args:
|
||||
units(str): The units to set.
|
||||
"""
|
||||
self._y_axis_units = units
|
||||
self._apply_y_label()
|
||||
|
||||
@property
|
||||
def y_label_combined(self) -> str:
|
||||
"""
|
||||
The final y label shown on the axis = user portion + suffix.
|
||||
The final y label shown on the axis = user portion + suffix + [units].
|
||||
"""
|
||||
return self._user_y_label + self._y_label_suffix
|
||||
units = f" [{self._y_axis_units}]" if self._y_axis_units else ""
|
||||
return self._user_y_label + self._y_label_suffix + units
|
||||
|
||||
def _apply_y_label(self):
|
||||
"""
|
||||
|
||||
@@ -1468,7 +1468,7 @@ class Waveform(PlotBase):
|
||||
x_data = data.get(x_name, {}).get(x_entry, {}).get(access_key, [0])
|
||||
else: # history data
|
||||
x_data = data.get(x_name, {}).get(x_entry, {}).read().get("value", [0])
|
||||
new_suffix = f" [custom: {x_name}-{x_entry}]"
|
||||
new_suffix = f" (custom: {x_name}-{x_entry})"
|
||||
|
||||
# 2 User wants timestamp
|
||||
if self.x_axis_mode["name"] == "timestamp":
|
||||
@@ -1477,19 +1477,19 @@ class Waveform(PlotBase):
|
||||
else: # history data
|
||||
timestamps = data[device_name][device_entry].read().get("timestamp", [0])
|
||||
x_data = timestamps
|
||||
new_suffix = " [timestamp]"
|
||||
new_suffix = " (timestamp)"
|
||||
|
||||
# 3 User wants index
|
||||
if self.x_axis_mode["name"] == "index":
|
||||
x_data = None
|
||||
new_suffix = " [index]"
|
||||
new_suffix = " (index)"
|
||||
|
||||
# 4 Best effort automatic mode
|
||||
if self.x_axis_mode["name"] is None or self.x_axis_mode["name"] == "auto":
|
||||
# 4.1 If there are async curves, use index
|
||||
if len(self._async_curves) > 0:
|
||||
x_data = None
|
||||
new_suffix = " [auto: index]"
|
||||
new_suffix = " (auto: index)"
|
||||
# 4.2 If there are sync curves, use the first device from the scan report
|
||||
else:
|
||||
try:
|
||||
@@ -1503,7 +1503,7 @@ class Waveform(PlotBase):
|
||||
x_data = data.get(x_name, {}).get(x_entry, {}).get(access_key, None)
|
||||
else:
|
||||
x_data = data.get(x_name, {}).get(x_entry, {}).read().get("value", None)
|
||||
new_suffix = f" [auto: {x_name}-{x_entry}]"
|
||||
new_suffix = f" (auto: {x_name}-{x_entry})"
|
||||
self._update_x_label_suffix(new_suffix)
|
||||
return x_data
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "bec_widgets"
|
||||
version = "2.7.1"
|
||||
version = "2.8.0"
|
||||
description = "BEC Widgets"
|
||||
requires-python = ">=3.10"
|
||||
classifiers = [
|
||||
|
||||
@@ -51,10 +51,11 @@ def test_set_x_label_emits_signal(qtbot, mocked_client):
|
||||
"""
|
||||
pb = create_widget(qtbot, PlotBase, client=mocked_client)
|
||||
with qtbot.waitSignal(pb.property_changed, timeout=500) as signal:
|
||||
pb.x_label = "Voltage (V)"
|
||||
assert signal.args == ["x_label", "Voltage (V)"]
|
||||
assert pb.x_label == "Voltage (V)"
|
||||
assert pb.plot_item.getAxis("bottom").labelText == "Voltage (V)"
|
||||
pb.x_label = "Voltage"
|
||||
assert signal.args == ["x_label", "Voltage"]
|
||||
assert pb.x_label == "Voltage"
|
||||
pb.x_label_units = "V"
|
||||
assert pb.plot_item.getAxis("bottom").labelText == "Voltage [V]"
|
||||
|
||||
|
||||
def test_set_y_label_emits_signal(qtbot, mocked_client):
|
||||
@@ -63,10 +64,11 @@ def test_set_y_label_emits_signal(qtbot, mocked_client):
|
||||
"""
|
||||
pb = create_widget(qtbot, PlotBase, client=mocked_client)
|
||||
with qtbot.waitSignal(pb.property_changed, timeout=500) as signal:
|
||||
pb.y_label = "Current (A)"
|
||||
assert signal.args == ["y_label", "Current (A)"]
|
||||
assert pb.y_label == "Current (A)"
|
||||
assert pb.plot_item.getAxis("left").labelText == "Current (A)"
|
||||
pb.y_label = "Current"
|
||||
assert signal.args == ["y_label", "Current"]
|
||||
assert pb.y_label == "Current"
|
||||
pb.y_label_units = "A"
|
||||
assert pb.plot_item.getAxis("left").labelText == "Current [A]"
|
||||
|
||||
|
||||
def test_set_x_min_max(qtbot, mocked_client):
|
||||
|
||||
Reference in New Issue
Block a user