mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-04-14 20:50:55 +02:00
Compare commits
5 Commits
v0.80.0
...
feature/as
| Author | SHA1 | Date | |
|---|---|---|---|
| 70fd1b7be4 | |||
|
|
fc3a69bbb0 | ||
| 9594be2606 | |||
|
|
96fd239608 | ||
| 61de7e9e22 |
26
CHANGELOG.md
26
CHANGELOG.md
@@ -1,5 +1,17 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.81.0 (2024-07-06)
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(color_button): can get colors in RGBA or HEX ([`9594be2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9594be260680d11c8550ff74ffb8d679e5a5b8f6))
|
||||
|
||||
## v0.80.1 (2024-07-06)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(entry_validator): check for entry == "" ([`61de7e9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/61de7e9e221c766b9fb3ec23246da6a11c96a986))
|
||||
|
||||
## v0.80.0 (2024-07-06)
|
||||
|
||||
### Feature
|
||||
@@ -129,17 +141,3 @@
|
||||
### Feature
|
||||
|
||||
* feat(widgets): added simple bec queue widget ([`3faee98`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3faee98ec80041a27e4c1f1156178de6f9dcdc63))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor(dispatcher): cleanup ([`ca02132`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ca02132c8d18535b37e9192e00459d2aca6ba5cf))
|
||||
|
||||
## v0.74.1 (2024-06-26)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(rings): rings properties updated right after setting ([`c8b7367`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c8b7367815b095f8e4aa8b819481efb701f2e542))
|
||||
|
||||
### Test
|
||||
|
||||
* test(bec_figure): tests for removing widgets with rpc e2e ([`a268caa`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a268caaa30711fcc7ece542d24578d74cbf65c77))
|
||||
|
||||
@@ -134,7 +134,10 @@ class BECDispatcher:
|
||||
cls.qapp = None
|
||||
|
||||
def connect_slot(
|
||||
self, slot: Callable, topics: Union[EndpointInfo, str, list[Union[EndpointInfo, str]]]
|
||||
self,
|
||||
slot: Callable,
|
||||
topics: Union[EndpointInfo, str, list[Union[EndpointInfo, str]]],
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Connect widget's pyqt slot, so that it is called on new pub/sub topic message.
|
||||
|
||||
@@ -144,7 +147,7 @@ class BECDispatcher:
|
||||
topics (EndpointInfo | str | list): A topic or list of topics that can typically be acquired via bec_lib.MessageEndpoints
|
||||
"""
|
||||
slot = QtThreadSafeCallback(slot)
|
||||
self.client.connector.register(topics, cb=slot)
|
||||
self.client.connector.register(topics, cb=slot, **kwargs)
|
||||
topics_str, _ = self.client.connector._convert_endpointinfo(topics)
|
||||
self._slots[slot].update(set(topics_str))
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class EntryValidator:
|
||||
device = self.devices[name]
|
||||
description = device.describe()
|
||||
|
||||
if entry is None:
|
||||
if entry is None or entry == "":
|
||||
entry = next(iter(device._hints), name) if hasattr(device, "_hints") else name
|
||||
if entry not in description:
|
||||
raise ValueError(f"Entry '{entry}' not found in device '{name}' signals")
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal
|
||||
|
||||
import pyqtgraph as pg
|
||||
|
||||
|
||||
@@ -15,3 +19,18 @@ class ColorButton(pg.ColorButton):
|
||||
self.colorDialog.setCurrentColor(self.color())
|
||||
self.colorDialog.open()
|
||||
self.colorDialog.exec()
|
||||
|
||||
def get_color(self, format: Literal["RGBA", "HEX"] = "RGBA") -> tuple | str:
|
||||
"""
|
||||
Get the color of the button in the specified format.
|
||||
|
||||
Args:
|
||||
format(Literal["RGBA", "HEX"]): The format of the returned color.
|
||||
|
||||
Returns:
|
||||
tuple|str: The color in the specified format.
|
||||
"""
|
||||
if format == "RGBA":
|
||||
return self.color().getRgb()
|
||||
if format == "HEX":
|
||||
return self.color().name()
|
||||
|
||||
@@ -7,6 +7,7 @@ from typing import Any, Literal, Optional
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
from bec_lib import messages
|
||||
from bec_lib.device import ReadoutPriority
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_lib.scan_data import ScanData
|
||||
from pydantic import Field, ValidationError
|
||||
@@ -327,7 +328,7 @@ class BECWaveform(BECPlotBase):
|
||||
color_map_z: Optional[str] = "plasma",
|
||||
label: Optional[str] = None,
|
||||
validate_bec: bool = True,
|
||||
source: str = "scan_segment",
|
||||
source: Optional[str] = None,
|
||||
dap: Optional[str] = None,
|
||||
**kwargs,
|
||||
) -> BECCurve:
|
||||
@@ -349,8 +350,6 @@ class BECWaveform(BECPlotBase):
|
||||
Returns:
|
||||
BECCurve: The curve object.
|
||||
"""
|
||||
# Check if curve already exists
|
||||
curve_source = source
|
||||
|
||||
# Get entry if not provided and validate
|
||||
x_entry, y_entry, z_entry = self._validate_signal_entries(
|
||||
@@ -362,6 +361,7 @@ class BECWaveform(BECPlotBase):
|
||||
else:
|
||||
label = label or f"{y_name}-{y_entry}"
|
||||
|
||||
# Check if curve already exists
|
||||
curve_exits = self._check_curve_id(label, self._curves_data)
|
||||
if curve_exits:
|
||||
raise ValueError(f"Curve with ID '{label}' already exists in widget '{self.gui_id}'.")
|
||||
@@ -373,6 +373,18 @@ class BECWaveform(BECPlotBase):
|
||||
)[-1]
|
||||
)
|
||||
|
||||
if source is None:
|
||||
if validate_bec:
|
||||
curve_source = (
|
||||
"async_readback"
|
||||
if self.dev[y_name].readout_priority == ReadoutPriority.ASYNC
|
||||
else "scan_segment"
|
||||
)
|
||||
else:
|
||||
curve_source = "scan_segment"
|
||||
else:
|
||||
curve_source = source
|
||||
|
||||
# Create curve by config
|
||||
curve_config = CurveConfig(
|
||||
widget_class="BECCurve",
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Literal, Optional
|
||||
from typing import TYPE_CHECKING, Literal, Optional
|
||||
|
||||
import pyqtgraph as pg
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from pydantic_core import PydanticCustomError
|
||||
from qtpy import QtCore
|
||||
|
||||
from bec_widgets.utils import BECConnector, Colors, ConnectionConfig
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import numpy as np
|
||||
|
||||
from bec_widgets.widgets.figure.plots.waveform import BECWaveform1D
|
||||
|
||||
|
||||
@@ -103,6 +105,14 @@ class BECCurve(BECConnector, pg.PlotDataItem):
|
||||
if kwargs:
|
||||
self.set(**kwargs)
|
||||
|
||||
self._async_info = {}
|
||||
|
||||
if self.config.source == "async_readback":
|
||||
# get updates on new scans in order to change the subscription to the correct async readback
|
||||
self.bec_dispatcher.connect_slot(
|
||||
self.on_scan_status_update, MessageEndpoints.scan_status()
|
||||
)
|
||||
|
||||
def apply_config(self):
|
||||
pen_style_map = {
|
||||
"solid": QtCore.Qt.SolidLine,
|
||||
@@ -137,6 +147,49 @@ class BECCurve(BECConnector, pg.PlotDataItem):
|
||||
else:
|
||||
raise ValueError(f"Source {self.config.source} do not allow custom data setting.")
|
||||
|
||||
def on_scan_status_update(self, content: dict, metadata: dict):
|
||||
"""
|
||||
Update the async info with the latest scan status.
|
||||
"""
|
||||
scan_id = content.get("scan_id")
|
||||
if scan_id == self._async_info.get("scan_id"):
|
||||
return
|
||||
active_subscription = self._async_info.get("active_subscription")
|
||||
if active_subscription:
|
||||
self.bec_dispatcher.disconnect_slot(self.on_async_update, active_subscription)
|
||||
self._async_info["scan_id"] = scan_id
|
||||
self._async_info["active_subscription"] = MessageEndpoints.device_async_readback(
|
||||
scan_id, self.config.signals.y.name
|
||||
)
|
||||
self._async_info["data"] = []
|
||||
self.bec_dispatcher.connect_slot(
|
||||
self.on_async_update,
|
||||
MessageEndpoints.device_async_readback(scan_id, self.config.signals.y.name),
|
||||
from_start=True,
|
||||
)
|
||||
|
||||
def on_async_update(self, content: dict, metadata: dict):
|
||||
"""
|
||||
Update the curve with the latest async readback data.
|
||||
"""
|
||||
async_update = metadata.get("async_update")
|
||||
if not async_update:
|
||||
return
|
||||
signals = content.get("signals")
|
||||
if not signals:
|
||||
return
|
||||
y_data = signals.get(self.config.signals.y.name, {}).get("value", [])
|
||||
if y_data is None:
|
||||
return
|
||||
if async_update == "extend":
|
||||
self._async_info["data"].extend(y_data)
|
||||
elif async_update == "replace":
|
||||
self._async_info["data"] = y_data
|
||||
else:
|
||||
print(f"Warning: Unsupported async update type {async_update}.")
|
||||
|
||||
self.setData(self._async_info["data"])
|
||||
|
||||
def set(self, **kwargs):
|
||||
"""
|
||||
Set the properties of the curve.
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "bec_widgets"
|
||||
version = "0.80.0"
|
||||
version = "0.81.0"
|
||||
description = "BEC Widgets"
|
||||
requires-python = ">=3.10"
|
||||
classifiers = [
|
||||
|
||||
Reference in New Issue
Block a user