mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
refactor: replace connect with connect_slot
This commit is contained in:
@ -2,11 +2,10 @@ import argparse
|
|||||||
import itertools
|
import itertools
|
||||||
import os
|
import os
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from threading import RLock
|
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
from bec_lib import BECClient
|
from bec_lib import BECClient
|
||||||
from bec_lib.core import BECMessage, MessageEndpoints, ServiceConfig
|
from bec_lib.core import BECMessage, ServiceConfig
|
||||||
from bec_lib.core.redis_connector import RedisConsumerThreaded
|
from bec_lib.core.redis_connector import RedisConsumerThreaded
|
||||||
from PyQt5.QtCore import QObject, pyqtSignal
|
from PyQt5.QtCore import QObject, pyqtSignal
|
||||||
|
|
||||||
@ -31,9 +30,6 @@ class _Connection:
|
|||||||
|
|
||||||
|
|
||||||
class _BECDispatcher(QObject):
|
class _BECDispatcher(QObject):
|
||||||
new_scan = pyqtSignal(dict, dict)
|
|
||||||
scan_segment = pyqtSignal(dict, dict)
|
|
||||||
|
|
||||||
def __init__(self, bec_config=None):
|
def __init__(self, bec_config=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.client = BECClient()
|
self.client = BECClient()
|
||||||
@ -44,35 +40,8 @@ class _BECDispatcher(QObject):
|
|||||||
bec_config = "bec_config.yaml"
|
bec_config = "bec_config.yaml"
|
||||||
|
|
||||||
self.client.initialize(config=ServiceConfig(config_path=bec_config))
|
self.client.initialize(config=ServiceConfig(config_path=bec_config))
|
||||||
|
|
||||||
self._slot_signal_map = {"on_scan_segment": self.scan_segment, "on_new_scan": self.new_scan}
|
|
||||||
self._connections = {}
|
self._connections = {}
|
||||||
|
|
||||||
self._scan_id = None
|
|
||||||
scan_lock = RLock()
|
|
||||||
|
|
||||||
def _scan_segment_cb(msg):
|
|
||||||
msg = BECMessage.ScanMessage.loads(msg.value)[0]
|
|
||||||
with scan_lock:
|
|
||||||
# TODO: use ScanStatusMessage instead?
|
|
||||||
scan_id = msg.content["scanID"]
|
|
||||||
if self._scan_id != scan_id:
|
|
||||||
self._scan_id = scan_id
|
|
||||||
self.new_scan.emit(msg.content, msg.metadata)
|
|
||||||
self.scan_segment.emit(msg.content, msg.metadata)
|
|
||||||
|
|
||||||
scan_segment_topic = MessageEndpoints.scan_segment()
|
|
||||||
self._scan_segment_thread = self.client.connector.consumer(
|
|
||||||
topics=scan_segment_topic, cb=_scan_segment_cb
|
|
||||||
)
|
|
||||||
self._scan_segment_thread.start()
|
|
||||||
|
|
||||||
def connect(self, widget):
|
|
||||||
for slot_name, signal in self._slot_signal_map.items():
|
|
||||||
slot = getattr(widget, slot_name, None)
|
|
||||||
if callable(slot):
|
|
||||||
signal.connect(slot)
|
|
||||||
|
|
||||||
def connect_slot(self, slot: Callable, topic: str) -> None:
|
def connect_slot(self, slot: Callable, topic: str) -> None:
|
||||||
"""Connect widget's pyqt slot, so that it is called on new pub/sub topic message
|
"""Connect widget's pyqt slot, so that it is called on new pub/sub topic message
|
||||||
|
|
||||||
|
@ -5,10 +5,10 @@ from typing import Any
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pyqtgraph
|
import pyqtgraph
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from PyQt5.QtCore import pyqtSlot
|
|
||||||
from PyQt5.QtWidgets import QTableWidgetItem, QCheckBox
|
|
||||||
|
|
||||||
from bec_lib import BECClient
|
from bec_lib import BECClient
|
||||||
|
from bec_lib.core import MessageEndpoints
|
||||||
|
from PyQt5.QtCore import pyqtSlot
|
||||||
|
from PyQt5.QtWidgets import QCheckBox, QTableWidgetItem
|
||||||
from pyqtgraph import mkBrush, mkColor, mkPen
|
from pyqtgraph import mkBrush, mkColor, mkPen
|
||||||
from pyqtgraph.Qt import QtCore, QtWidgets, uic
|
from pyqtgraph.Qt import QtCore, QtWidgets, uic
|
||||||
from pyqtgraph.Qt.QtCore import pyqtSignal
|
from pyqtgraph.Qt.QtCore import pyqtSignal
|
||||||
@ -54,10 +54,7 @@ class BasicPlot(QtWidgets.QWidget):
|
|||||||
self.plotter_scan_id = None
|
self.plotter_scan_id = None
|
||||||
|
|
||||||
# TODO to be moved to utils function
|
# TODO to be moved to utils function
|
||||||
plotstyles = {
|
plotstyles = {"symbol": "o", "symbolSize": 10}
|
||||||
"symbol": "o",
|
|
||||||
"symbolSize": 10,
|
|
||||||
}
|
|
||||||
color_list = ["#384c6b", "#e28a2b", "#5E3023", "#e41a1c", "#984e83", "#4daf4a"]
|
color_list = ["#384c6b", "#e28a2b", "#5E3023", "#e41a1c", "#984e83", "#4daf4a"]
|
||||||
color_list = BasicPlot.golden_angle_color(colormap="CET-R2", num=len(self.y_value_list))
|
color_list = BasicPlot.golden_angle_color(colormap="CET-R2", num=len(self.y_value_list))
|
||||||
|
|
||||||
@ -336,9 +333,9 @@ class BasicPlot(QtWidgets.QWidget):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import argparse
|
import argparse
|
||||||
from bec_widgets.bec_dispatcher import bec_dispatcher
|
|
||||||
|
|
||||||
from bec_widgets import ctrl_c
|
from bec_widgets import ctrl_c
|
||||||
|
from bec_widgets.bec_dispatcher import bec_dispatcher
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -354,7 +351,7 @@ if __name__ == "__main__":
|
|||||||
app = QtWidgets.QApplication([])
|
app = QtWidgets.QApplication([])
|
||||||
ctrl_c.setup(app)
|
ctrl_c.setup(app)
|
||||||
plot = BasicPlot(y_value_list=value.signals)
|
plot = BasicPlot(y_value_list=value.signals)
|
||||||
bec_dispatcher.connect(plot)
|
bec_dispatcher.connect_slot(plot.on_scan_segment, MessageEndpoints.scan_segment())
|
||||||
plot.show()
|
plot.show()
|
||||||
# client.callbacks.register("scan_segment", plot, sync=False)
|
# client.callbacks.register("scan_segment", plot, sync=False)
|
||||||
app.exec_()
|
app.exec_()
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
from threading import RLock
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
|
from bec_lib.core import MessageEndpoints
|
||||||
from bec_lib.core.logger import bec_logger
|
from bec_lib.core.logger import bec_logger
|
||||||
from PyQt5.QtCore import pyqtProperty, pyqtSlot
|
from PyQt5.QtCore import pyqtProperty, pyqtSlot
|
||||||
|
|
||||||
@ -14,7 +17,10 @@ pg.setConfigOptions(background="w", foreground="k", antialias=True)
|
|||||||
class BECScanPlot2D(pg.GraphicsView):
|
class BECScanPlot2D(pg.GraphicsView):
|
||||||
def __init__(self, parent=None, background="default"):
|
def __init__(self, parent=None, background="default"):
|
||||||
super().__init__(parent, background)
|
super().__init__(parent, background)
|
||||||
bec_dispatcher.connect(self)
|
bec_dispatcher.connect_slot(self.on_scan_segment, MessageEndpoints.scan_segment())
|
||||||
|
|
||||||
|
self._scanID = None
|
||||||
|
self._scanID_lock = RLock()
|
||||||
|
|
||||||
self._x_channel = ""
|
self._x_channel = ""
|
||||||
self._y_channel = ""
|
self._y_channel = ""
|
||||||
@ -33,8 +39,7 @@ class BECScanPlot2D(pg.GraphicsView):
|
|||||||
self.imageItem = pg.ImageItem()
|
self.imageItem = pg.ImageItem()
|
||||||
self.plot_item.addItem(self.imageItem)
|
self.plot_item.addItem(self.imageItem)
|
||||||
|
|
||||||
@pyqtSlot(dict, dict)
|
def reset_plots(self, _scan_segment, metadata):
|
||||||
def on_new_scan(self, _scan_segment, metadata):
|
|
||||||
# TODO: Do we reset in case of a scan type change?
|
# TODO: Do we reset in case of a scan type change?
|
||||||
self.imageItem.clear()
|
self.imageItem.clear()
|
||||||
|
|
||||||
@ -79,6 +84,13 @@ class BECScanPlot2D(pg.GraphicsView):
|
|||||||
|
|
||||||
@pyqtSlot(dict, dict)
|
@pyqtSlot(dict, dict)
|
||||||
def on_scan_segment(self, scan_segment, metadata):
|
def on_scan_segment(self, scan_segment, metadata):
|
||||||
|
# reset plots on scanID change
|
||||||
|
with self._scanID_lock:
|
||||||
|
scan_id = scan_segment["scanID"]
|
||||||
|
if self._scanID != scan_id:
|
||||||
|
self._scanID = scan_id
|
||||||
|
self.reset_plots(scan_segment, metadata)
|
||||||
|
|
||||||
if not self.z_channel or metadata["scan_name"] != "grid_scan":
|
if not self.z_channel or metadata["scan_name"] != "grid_scan":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import itertools
|
import itertools
|
||||||
|
from threading import RLock
|
||||||
|
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from bec_lib.core import MessageEndpoints
|
from bec_lib.core import MessageEndpoints
|
||||||
@ -17,24 +18,33 @@ COLORS = ["#fd7f6f", "#7eb0d5", "#b2e061", "#bd7ebe", "#ffb55a"]
|
|||||||
class BECScanPlot(pg.GraphicsView):
|
class BECScanPlot(pg.GraphicsView):
|
||||||
def __init__(self, parent=None, background="default"):
|
def __init__(self, parent=None, background="default"):
|
||||||
super().__init__(parent, background)
|
super().__init__(parent, background)
|
||||||
bec_dispatcher.connect(self)
|
bec_dispatcher.connect_slot(self.on_scan_segment, MessageEndpoints.scan_segment())
|
||||||
|
|
||||||
self.view = pg.PlotItem()
|
self.view = pg.PlotItem()
|
||||||
self.setCentralItem(self.view)
|
self.setCentralItem(self.view)
|
||||||
|
|
||||||
|
self._scanID = None
|
||||||
|
self._scanID_lock = RLock()
|
||||||
|
|
||||||
self._x_channel = ""
|
self._x_channel = ""
|
||||||
self._y_channel_list = []
|
self._y_channel_list = []
|
||||||
|
|
||||||
self.scan_curves = {}
|
self.scan_curves = {}
|
||||||
self.dap_curves = {}
|
self.dap_curves = {}
|
||||||
|
|
||||||
@pyqtSlot(dict, dict)
|
def reset_plots(self, _scan_segment, _metadata):
|
||||||
def on_new_scan(self, _scan_segment, _metadata):
|
|
||||||
for plot_curve in {**self.scan_curves, **self.dap_curves}.values():
|
for plot_curve in {**self.scan_curves, **self.dap_curves}.values():
|
||||||
plot_curve.setData(x=[], y=[])
|
plot_curve.setData(x=[], y=[])
|
||||||
|
|
||||||
@pyqtSlot(dict, dict)
|
@pyqtSlot(dict, dict)
|
||||||
def on_scan_segment(self, scan_segment, _metadata):
|
def on_scan_segment(self, scan_segment, metadata):
|
||||||
|
# reset plots on scanID change
|
||||||
|
with self._scanID_lock:
|
||||||
|
scan_id = scan_segment["scanID"]
|
||||||
|
if self._scanID != scan_id:
|
||||||
|
self._scanID = scan_id
|
||||||
|
self.reset_plots(scan_segment, metadata)
|
||||||
|
|
||||||
if not self.x_channel:
|
if not self.x_channel:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ def test_scan_plot_clears_data(qtbot):
|
|||||||
},
|
},
|
||||||
{"scanID": "test", "scan_number": 1, "scan_report_devices": ["x"]},
|
{"scanID": "test", "scan_number": 1, "scan_report_devices": ["x"]},
|
||||||
)
|
)
|
||||||
plot.on_new_scan({}, {})
|
plot.reset_plots({}, {})
|
||||||
plot.on_scan_segment(
|
plot.on_scan_segment(
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
|
Reference in New Issue
Block a user