mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
fix(examples): outdated examples removed (mca_plot.py, stream_plot.py, motor_example.py)
This commit is contained in:
@ -2,18 +2,16 @@ import os
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.Qt import QtWidgets
|
import qdarktheme
|
||||||
from qtconsole.inprocess import QtInProcessKernelManager
|
from qtconsole.inprocess import QtInProcessKernelManager
|
||||||
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
||||||
from qtpy.QtCore import QSize
|
from qtpy.QtCore import QSize
|
||||||
from qtpy.QtGui import QIcon
|
from qtpy.QtGui import QIcon
|
||||||
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
|
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
|
||||||
|
|
||||||
from bec_widgets.cli.rpc_register import RPCRegister
|
|
||||||
from bec_widgets.utils import BECDispatcher, UILoader
|
from bec_widgets.utils import BECDispatcher, UILoader
|
||||||
from bec_widgets.widgets import BECFigure
|
from bec_widgets.widgets import BECFigure
|
||||||
from bec_widgets.widgets.dock.dock_area import BECDockArea
|
from bec_widgets.widgets.dock.dock_area import BECDockArea
|
||||||
from bec_widgets.widgets.spiral_progress_bar.spiral_progress_bar import SpiralProgressBar
|
|
||||||
|
|
||||||
|
|
||||||
class JupyterConsoleWidget(RichJupyterWidget): # pragma: no cover:
|
class JupyterConsoleWidget(RichJupyterWidget): # pragma: no cover:
|
||||||
@ -26,7 +24,6 @@ class JupyterConsoleWidget(RichJupyterWidget): # pragma: no cover:
|
|||||||
self.kernel_client.start_channels()
|
self.kernel_client.start_channels()
|
||||||
|
|
||||||
self.kernel_manager.kernel.shell.push({"np": np, "pg": pg})
|
self.kernel_manager.kernel.shell.push({"np": np, "pg": pg})
|
||||||
# self.set_console_font_size(70)
|
|
||||||
|
|
||||||
def shutdown_kernel(self):
|
def shutdown_kernel(self):
|
||||||
self.kernel_client.stop_channels()
|
self.kernel_client.stop_channels()
|
||||||
@ -46,27 +43,22 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|||||||
|
|
||||||
self.ui.splitter.setSizes([200, 100])
|
self.ui.splitter.setSizes([200, 100])
|
||||||
self.safe_close = False
|
self.safe_close = False
|
||||||
# self.figure.clean_signal.connect(self.confirm_close)
|
|
||||||
|
|
||||||
self.register = RPCRegister()
|
|
||||||
self.register.add_rpc(self.figure)
|
|
||||||
|
|
||||||
# console push
|
# console push
|
||||||
self.console.kernel_manager.kernel.shell.push(
|
self.console.kernel_manager.kernel.shell.push(
|
||||||
{
|
{
|
||||||
"fig": self.figure,
|
"fig": self.figure,
|
||||||
"register": self.register,
|
|
||||||
"dock": self.dock,
|
"dock": self.dock,
|
||||||
"w1": self.w1,
|
"w1": self.w1,
|
||||||
"w2": self.w2,
|
"w2": self.w2,
|
||||||
"w3": self.w3,
|
"w3": self.w3,
|
||||||
|
"d0": self.d0,
|
||||||
"d1": self.d1,
|
"d1": self.d1,
|
||||||
"d2": self.d2,
|
"d2": self.d2,
|
||||||
"d3": self.d3,
|
"fig0": self.fig0,
|
||||||
|
"fig1": self.fig1,
|
||||||
|
"fig2": self.fig2,
|
||||||
"bar": self.bar,
|
"bar": self.bar,
|
||||||
"b2a": self.button_2_a,
|
|
||||||
"b2b": self.button_2_b,
|
|
||||||
"b2c": self.button_2_c,
|
|
||||||
"bec": self.figure.client,
|
"bec": self.figure.client,
|
||||||
"scans": self.figure.client.scans,
|
"scans": self.figure.client.scans,
|
||||||
"dev": self.figure.client.device_manager.devices,
|
"dev": self.figure.client.device_manager.devices,
|
||||||
@ -111,25 +103,22 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|||||||
self.c1 = self.w1.get_config()
|
self.c1 = self.w1.get_config()
|
||||||
|
|
||||||
def _init_dock(self):
|
def _init_dock(self):
|
||||||
self.button_1 = QtWidgets.QPushButton("Button 1 ")
|
|
||||||
self.button_2_a = QtWidgets.QPushButton("Button to be added at place 0,0 in d3")
|
|
||||||
self.button_2_b = QtWidgets.QPushButton("button after without postions specified")
|
|
||||||
self.button_2_c = QtWidgets.QPushButton("button super late")
|
|
||||||
self.button_3 = QtWidgets.QPushButton("Button above Figure ")
|
|
||||||
self.bar = SpiralProgressBar()
|
|
||||||
|
|
||||||
self.label_2 = QtWidgets.QLabel("label which is added separately")
|
self.d0 = self.dock.add_dock(name="dock_0")
|
||||||
self.label_3 = QtWidgets.QLabel("Label above figure")
|
self.fig0 = self.d0.add_widget_bec("BECFigure")
|
||||||
|
self.fig0.image("eiger", vrange=(0, 100))
|
||||||
|
|
||||||
self.d1 = self.dock.add_dock(widget=self.button_1, position="left")
|
self.d1 = self.dock.add_dock(name="dock_1", position="right")
|
||||||
self.d1.addWidget(self.label_2)
|
self.fig1 = self.d1.add_widget_bec("BECFigure")
|
||||||
self.d2 = self.dock.add_dock(widget=self.bar, position="right")
|
self.fig1.plot(x_name="samx", y_name="bpm4i")
|
||||||
self.d3 = self.dock.add_dock(name="figure")
|
self.fig1.plot(x_name="samx", y_name="bpm3a")
|
||||||
self.fig_dock3 = BECFigure()
|
|
||||||
self.fig_dock3.plot(x_name="samx", y_name="bpm4d")
|
self.d2 = self.dock.add_dock(name="dock_2", position="bottom")
|
||||||
self.d3.add_widget(self.label_3)
|
self.fig2 = self.d2.add_widget_bec("BECFigure", row=0, col=0)
|
||||||
self.d3.add_widget(self.button_3)
|
self.fig2.motor_map(x_name="samx", y_name="samy")
|
||||||
self.d3.add_widget(self.fig_dock3)
|
self.fig2.plot(x_name="samx", y_name="bpm4i")
|
||||||
|
self.bar = self.d2.add_widget_bec("SpiralProgressBar", row=0, col=1)
|
||||||
|
self.bar.set_diameter(200)
|
||||||
|
|
||||||
self.dock.save_state()
|
self.dock.save_state()
|
||||||
|
|
||||||
@ -155,6 +144,7 @@ if __name__ == "__main__": # pragma: no cover
|
|||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.setApplicationName("Jupyter Console")
|
app.setApplicationName("Jupyter Console")
|
||||||
app.setApplicationDisplayName("Jupyter Console")
|
app.setApplicationDisplayName("Jupyter Console")
|
||||||
|
qdarktheme.setup_theme("auto")
|
||||||
icon = QIcon()
|
icon = QIcon()
|
||||||
icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
|
icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
|
||||||
app.setWindowIcon(icon)
|
app.setWindowIcon(icon)
|
||||||
|
@ -1,159 +0,0 @@
|
|||||||
# import simulation_progress as SP
|
|
||||||
import numpy as np
|
|
||||||
import pyqtgraph as pg
|
|
||||||
from bec_lib import messages
|
|
||||||
from bec_lib.endpoints import MessageEndpoints
|
|
||||||
from qtpy.QtCore import Signal as pyqtSignal
|
|
||||||
from qtpy.QtCore import Slot as pyqtSlot
|
|
||||||
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
|
|
||||||
|
|
||||||
|
|
||||||
class StreamApp(QWidget):
|
|
||||||
update_signal = pyqtSignal()
|
|
||||||
new_scan_id = pyqtSignal(str)
|
|
||||||
|
|
||||||
def __init__(self, device, sub_device):
|
|
||||||
super().__init__()
|
|
||||||
pg.setConfigOptions(background="w", foreground="k")
|
|
||||||
self.init_ui()
|
|
||||||
|
|
||||||
self.setWindowTitle("MCA readout")
|
|
||||||
|
|
||||||
self.data = None
|
|
||||||
self.scan_id = None
|
|
||||||
self.stream_consumer = None
|
|
||||||
|
|
||||||
self.device = device
|
|
||||||
self.sub_device = sub_device
|
|
||||||
|
|
||||||
self.start_device_consumer()
|
|
||||||
|
|
||||||
# self.start_device_consumer(self.device) # for simulation
|
|
||||||
|
|
||||||
self.new_scan_id.connect(self.create_new_stream_consumer)
|
|
||||||
self.update_signal.connect(self.plot_new)
|
|
||||||
|
|
||||||
def init_ui(self):
|
|
||||||
# Create layout and add widgets
|
|
||||||
self.layout = QVBoxLayout()
|
|
||||||
self.setLayout(self.layout)
|
|
||||||
|
|
||||||
# Create plot
|
|
||||||
self.glw = pg.GraphicsLayoutWidget()
|
|
||||||
self.layout.addWidget(self.glw)
|
|
||||||
|
|
||||||
# Create Plot and add ImageItem
|
|
||||||
self.plot_item = pg.PlotItem()
|
|
||||||
self.plot_item.setAspectLocked(False)
|
|
||||||
self.imageItem = pg.ImageItem()
|
|
||||||
# self.plot_item1D = pg.PlotItem()
|
|
||||||
# self.plot_item.addItem(self.imageItem)
|
|
||||||
# self.plot_item.addItem(self.plot_item1D)
|
|
||||||
|
|
||||||
# Setting up histogram
|
|
||||||
# self.hist = pg.HistogramLUTItem()
|
|
||||||
# self.hist.setImageItem(self.imageItem)
|
|
||||||
# self.hist.gradient.loadPreset("magma")
|
|
||||||
# self.update_hist()
|
|
||||||
|
|
||||||
# Adding Items to Graphical Layout
|
|
||||||
self.glw.addItem(self.plot_item)
|
|
||||||
# self.glw.addItem(self.hist)
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
|
||||||
def create_new_stream_consumer(self, scan_id: str):
|
|
||||||
print(f"Creating new stream consumer for scan_id: {scan_id}")
|
|
||||||
|
|
||||||
self.connect_stream_consumer(scan_id, self.device)
|
|
||||||
|
|
||||||
def connect_stream_consumer(self, scan_id, device):
|
|
||||||
if self.stream_consumer is not None:
|
|
||||||
self.stream_consumer.shutdown()
|
|
||||||
|
|
||||||
self.stream_consumer = connector.stream_consumer(
|
|
||||||
topics=MessageEndpoints.device_async_readback(scan_id=scan_id, device=device),
|
|
||||||
cb=self._streamer_cb,
|
|
||||||
parent=self,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.stream_consumer.start()
|
|
||||||
|
|
||||||
def start_device_consumer(self):
|
|
||||||
self.device_consumer = connector.consumer(
|
|
||||||
topics=MessageEndpoints.scan_status(), cb=self._device_cv, parent=self
|
|
||||||
)
|
|
||||||
|
|
||||||
self.device_consumer.start()
|
|
||||||
|
|
||||||
# def start_device_consumer(self, device): #for simulation
|
|
||||||
# self.device_consumer = connector.consumer(
|
|
||||||
# topics=MessageEndpoints.device_status(device), cb=self._device_cv, parent=self
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# self.device_consumer.start()
|
|
||||||
|
|
||||||
def plot_new(self):
|
|
||||||
print(f"Printing data from plot update: {self.data}")
|
|
||||||
self.plot_item.plot(self.data[0])
|
|
||||||
# self.imageItem.setImage(self.data, autoLevels=False)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _streamer_cb(msg, *, parent, **_kwargs) -> None:
|
|
||||||
msgMCS = msg.value
|
|
||||||
print(msgMCS)
|
|
||||||
row = msgMCS.content["signals"][parent.sub_device]
|
|
||||||
metadata = msgMCS.metadata
|
|
||||||
|
|
||||||
# Check if the current number of rows is odd
|
|
||||||
# if parent.data is not None and parent.data.shape[0] % 2 == 1:
|
|
||||||
# row = np.flip(row) # Flip the row
|
|
||||||
print(f"Printing data from callback update: {row}")
|
|
||||||
parent.data = np.array([row])
|
|
||||||
# if parent.data is None:
|
|
||||||
# parent.data = np.array([row])
|
|
||||||
# else:
|
|
||||||
# parent.data = np.vstack((parent.data, row))
|
|
||||||
|
|
||||||
parent.update_signal.emit()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _device_cv(msg, *, parent, **_kwargs) -> None:
|
|
||||||
print("Getting ScanID")
|
|
||||||
|
|
||||||
msgDEV = msg.value
|
|
||||||
|
|
||||||
current_scan_id = msgDEV.content["scan_id"]
|
|
||||||
|
|
||||||
if parent.scan_id is None:
|
|
||||||
parent.scan_id = current_scan_id
|
|
||||||
parent.new_scan_id.emit(current_scan_id)
|
|
||||||
print(f"New scan_id: {current_scan_id}")
|
|
||||||
|
|
||||||
if current_scan_id != parent.scan_id:
|
|
||||||
parent.scan_id = current_scan_id
|
|
||||||
# parent.data = None
|
|
||||||
# parent.imageItem.clear()
|
|
||||||
parent.new_scan_id.emit(current_scan_id)
|
|
||||||
|
|
||||||
print(f"New scan_id: {current_scan_id}")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
from bec_lib.redis_connector import RedisConnector
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Stream App.")
|
|
||||||
parser.add_argument("--port", type=str, default="pc15543:6379", help="Port for RedisConnector")
|
|
||||||
parser.add_argument("--device", type=str, default="mcs", help="Device name")
|
|
||||||
parser.add_argument("--sub_device", type=str, default="mca4", help="Sub-device name")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
connector = RedisConnector(args.port)
|
|
||||||
|
|
||||||
app = QApplication([])
|
|
||||||
streamApp = StreamApp(device=args.device, sub_device=args.sub_device)
|
|
||||||
|
|
||||||
streamApp.show()
|
|
||||||
app.exec()
|
|
@ -1,28 +0,0 @@
|
|||||||
import time
|
|
||||||
|
|
||||||
from bec_lib import messages
|
|
||||||
from bec_lib.endpoints import MessageEndpoints
|
|
||||||
from bec_lib.redis_connector import RedisConnector
|
|
||||||
|
|
||||||
connector = RedisConnector("localhost:6379")
|
|
||||||
metadata = {}
|
|
||||||
|
|
||||||
scan_id = "ScanID1"
|
|
||||||
|
|
||||||
metadata.update(
|
|
||||||
{"scan_id": scan_id, "async_update": "append"} # this will be different for each scan
|
|
||||||
)
|
|
||||||
for ii in range(20):
|
|
||||||
data = {"mca1": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "mca2": [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]}
|
|
||||||
msg = messages.DeviceMessage(signals=data, metadata=metadata).dumps()
|
|
||||||
|
|
||||||
connector.xadd(
|
|
||||||
topic=MessageEndpoints.device_async_readback(
|
|
||||||
scan_id=scan_id, device="mca"
|
|
||||||
), # scan_id will be different for each scan
|
|
||||||
msg={"data": msg}, # TODO should be msg_dict
|
|
||||||
expire=1800,
|
|
||||||
)
|
|
||||||
|
|
||||||
print(f"Sent {ii}")
|
|
||||||
time.sleep(0.5)
|
|
@ -1,17 +0,0 @@
|
|||||||
selected_motors:
|
|
||||||
motor_x: "samx"
|
|
||||||
motor_y: "samy"
|
|
||||||
|
|
||||||
plot_motors:
|
|
||||||
max_points: 1000
|
|
||||||
num_dim_points: 100
|
|
||||||
scatter_size: 5
|
|
||||||
precision: 3
|
|
||||||
mode_lock: False # "Individual" or "Start/Stop". False to unlock
|
|
||||||
extra_columns:
|
|
||||||
- sample name: "sample 1"
|
|
||||||
- step_x [mu]: 25
|
|
||||||
- step_y [mu]: 25
|
|
||||||
- exp_time [s]: 1
|
|
||||||
- start: 1
|
|
||||||
- tilt [deg]: 0
|
|
@ -1,10 +0,0 @@
|
|||||||
redis:
|
|
||||||
host: pc15543
|
|
||||||
port: 6379
|
|
||||||
mongodb:
|
|
||||||
host: localhost
|
|
||||||
port: 27017
|
|
||||||
scibec:
|
|
||||||
host: http://localhost
|
|
||||||
port: 3030
|
|
||||||
beamline: MyBeamline
|
|
@ -1,17 +0,0 @@
|
|||||||
selected_motors:
|
|
||||||
motor_x: "samx"
|
|
||||||
motor_y: "samy"
|
|
||||||
|
|
||||||
plot_motors:
|
|
||||||
max_points: 1000
|
|
||||||
num_dim_points: 100
|
|
||||||
scatter_size: 5
|
|
||||||
precision: 3
|
|
||||||
mode_lock: Start/Stop # "Individual" or "Start/Stop"
|
|
||||||
extra_columns:
|
|
||||||
- sample name: "sample 1"
|
|
||||||
- step_x [mu]: 25
|
|
||||||
- step_y [mu]: 25
|
|
||||||
- exp_time [s]: 1
|
|
||||||
- start: 1
|
|
||||||
- tilt [deg]: 0
|
|
File diff suppressed because it is too large
Load Diff
@ -1,148 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>Form</class>
|
|
||||||
<widget class="QWidget" name="Form">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>845</width>
|
|
||||||
<height>635</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Line Plot</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QSplitter" name="splitter">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<widget class="QSplitter" name="splitter_plot">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>1</horstretch>
|
|
||||||
<verstretch>1</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="glw_plot_placeholder" native="true"/>
|
|
||||||
<widget class="QWidget" name="glw_image_placeholder" native="true"/>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="layoutWidget">
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,1,1,15">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton_generate">
|
|
||||||
<property name="text">
|
|
||||||
<string>Generate 1D and 2D data without stream</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="title">
|
|
||||||
<string>1st angle of azimutal segment (deg)</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>360.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>0.250000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboBox">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>f1amp</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>f2amp</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>f2 phase</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Precision</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QSpinBox" name="spinBox_precision">
|
|
||||||
<property name="value">
|
|
||||||
<number>4</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QTableWidget" name="cursor_table">
|
|
||||||
<property name="textElideMode">
|
|
||||||
<enum>Qt::ElideMiddle</enum>
|
|
||||||
</property>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Display</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>X</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Y</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -1,342 +0,0 @@
|
|||||||
import os
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import pyqtgraph
|
|
||||||
import pyqtgraph as pg
|
|
||||||
from bec_lib import messages
|
|
||||||
from bec_lib.endpoints import MessageEndpoints
|
|
||||||
from bec_lib.redis_connector import RedisConnector
|
|
||||||
from pyqtgraph import mkBrush, mkPen
|
|
||||||
from pyqtgraph.Qt import QtCore, QtWidgets
|
|
||||||
from qtpy.QtCore import Signal, Slot
|
|
||||||
from qtpy.QtWidgets import QTableWidgetItem, QVBoxLayout
|
|
||||||
|
|
||||||
from bec_widgets.utils import Colors, Crosshair, UILoader
|
|
||||||
from bec_widgets.utils.bec_dispatcher import BECDispatcher
|
|
||||||
|
|
||||||
|
|
||||||
class StreamPlot(QtWidgets.QWidget):
|
|
||||||
update_signal = Signal()
|
|
||||||
roi_signal = Signal(tuple)
|
|
||||||
|
|
||||||
def __init__(self, name="", y_value_list=["gauss_bpm"], client=None, parent=None) -> None:
|
|
||||||
"""
|
|
||||||
Basic plot widget for displaying scan data.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name (str, optional): Name of the plot. Defaults to "".
|
|
||||||
y_value_list (list, optional): List of signals to be plotted. Defaults to ["gauss_bpm"].
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Client and device manager from BEC
|
|
||||||
self.client = BECDispatcher().client if client is None else client
|
|
||||||
|
|
||||||
super(StreamPlot, self).__init__()
|
|
||||||
# Set style for pyqtgraph plots
|
|
||||||
pg.setConfigOption("background", "w")
|
|
||||||
pg.setConfigOption("foreground", "k")
|
|
||||||
current_path = os.path.dirname(__file__)
|
|
||||||
self.ui = UILoader().load_ui(os.path.join(current_path, "line_plot.ui"), self)
|
|
||||||
|
|
||||||
self._idle_time = 100
|
|
||||||
self.connector = RedisConnector(["localhost:6379"])
|
|
||||||
|
|
||||||
self.y_value_list = y_value_list
|
|
||||||
self.previous_y_value_list = None
|
|
||||||
self.plotter_data_x = []
|
|
||||||
self.plotter_data_y = []
|
|
||||||
|
|
||||||
self.plotter_scan_id = None
|
|
||||||
|
|
||||||
self._current_proj = None
|
|
||||||
self._current_metadata_ep = "px_stream/projection_{}/metadata"
|
|
||||||
|
|
||||||
self.proxy_update = pg.SignalProxy(self.update_signal, rateLimit=25, slot=self.update)
|
|
||||||
|
|
||||||
self._data_retriever_thread_exit_event = threading.Event()
|
|
||||||
self.data_retriever = threading.Thread(
|
|
||||||
target=self.on_projection, args=(self._data_retriever_thread_exit_event,), daemon=True
|
|
||||||
)
|
|
||||||
self.data_retriever.start()
|
|
||||||
|
|
||||||
##########################
|
|
||||||
# UI
|
|
||||||
##########################
|
|
||||||
self.init_ui()
|
|
||||||
self.init_curves()
|
|
||||||
self.hook_crosshair()
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
super().close()
|
|
||||||
self._data_retriever_thread_exit_event.set()
|
|
||||||
self.data_retriever.join()
|
|
||||||
|
|
||||||
def init_ui(self):
|
|
||||||
"""Setup all ui elements"""
|
|
||||||
##########################
|
|
||||||
# 1D Plot
|
|
||||||
##########################
|
|
||||||
|
|
||||||
# LabelItem for ROI
|
|
||||||
self.label_plot = pg.LabelItem(justify="center")
|
|
||||||
self.glw_plot_layout = QVBoxLayout(self.ui.glw_plot_placeholder)
|
|
||||||
self.glw_plot = pg.GraphicsLayoutWidget()
|
|
||||||
self.glw_plot_layout.addWidget(self.glw_plot)
|
|
||||||
self.glw_plot.addItem(self.label_plot)
|
|
||||||
self.label_plot.setText("ROI region")
|
|
||||||
|
|
||||||
# ROI selector - so far from [-1,1] #TODO update to scale with xrange
|
|
||||||
self.roi_selector = pg.LinearRegionItem([-1, 1])
|
|
||||||
|
|
||||||
self.glw_plot.nextRow() # TODO update of cursor
|
|
||||||
self.label_plot_moved = pg.LabelItem(justify="center")
|
|
||||||
self.glw_plot.addItem(self.label_plot_moved)
|
|
||||||
self.label_plot_moved.setText("Actual coordinates (X, Y)")
|
|
||||||
|
|
||||||
# Label for coordinates clicked
|
|
||||||
self.glw_plot.nextRow()
|
|
||||||
self.label_plot_clicked = pg.LabelItem(justify="center")
|
|
||||||
self.glw_plot.addItem(self.label_plot_clicked)
|
|
||||||
self.label_plot_clicked.setText("Clicked coordinates (X, Y)")
|
|
||||||
|
|
||||||
# 1D PlotItem
|
|
||||||
self.glw_plot.nextRow()
|
|
||||||
self.plot = pg.PlotItem()
|
|
||||||
self.plot.setLogMode(True, True)
|
|
||||||
self.glw_plot.addItem(self.plot)
|
|
||||||
self.plot.addLegend()
|
|
||||||
|
|
||||||
##########################
|
|
||||||
# 2D Plot
|
|
||||||
##########################
|
|
||||||
|
|
||||||
# Label for coordinates moved
|
|
||||||
self.label_image_moved = pg.LabelItem(justify="center")
|
|
||||||
self.glw_image_layout = QVBoxLayout(self.ui.glw_image_placeholder)
|
|
||||||
self.glw_image = pg.GraphicsLayoutWidget()
|
|
||||||
self.glw_plot_layout.addWidget(self.glw_image)
|
|
||||||
self.glw_image.addItem(self.label_image_moved)
|
|
||||||
self.label_image_moved.setText("Actual coordinates (X, Y)")
|
|
||||||
|
|
||||||
# Label for coordinates clicked
|
|
||||||
self.glw_image.nextRow()
|
|
||||||
self.label_image_clicked = pg.LabelItem(justify="center")
|
|
||||||
self.glw_image.addItem(self.label_image_clicked)
|
|
||||||
self.label_image_clicked.setText("Clicked coordinates (X, Y)")
|
|
||||||
|
|
||||||
# TODO try to lock aspect ratio with view
|
|
||||||
|
|
||||||
# # Create a window
|
|
||||||
# win = pg.GraphicsLayoutWidget()
|
|
||||||
# win.show()
|
|
||||||
#
|
|
||||||
# # Create a ViewBox
|
|
||||||
# view = win.addViewBox()
|
|
||||||
#
|
|
||||||
# # Lock the aspect ratio
|
|
||||||
# view.setAspectLocked(True)
|
|
||||||
|
|
||||||
# # Create an ImageItem
|
|
||||||
# image_item = pg.ImageItem(np.random.random((100, 100)))
|
|
||||||
#
|
|
||||||
# # Add the ImageItem to the ViewBox
|
|
||||||
# view.addItem(image_item)
|
|
||||||
|
|
||||||
# 2D ImageItem
|
|
||||||
self.glw_image.nextRow()
|
|
||||||
self.plot_image = pg.PlotItem()
|
|
||||||
self.glw_image.addItem(self.plot_image)
|
|
||||||
|
|
||||||
def init_curves(self):
|
|
||||||
# init of 1D plot
|
|
||||||
self.plot.clear()
|
|
||||||
|
|
||||||
self.curves = []
|
|
||||||
self.pens = []
|
|
||||||
self.brushs = []
|
|
||||||
|
|
||||||
self.color_list = Colors.golden_angle_color(colormap="CET-R2", num=len(self.y_value_list))
|
|
||||||
|
|
||||||
for ii, y_value in enumerate(self.y_value_list):
|
|
||||||
pen = mkPen(color=self.color_list[ii], width=2, style=QtCore.Qt.DashLine)
|
|
||||||
brush = mkBrush(color=self.color_list[ii])
|
|
||||||
curve = pg.PlotDataItem(symbolBrush=brush, pen=pen, skipFiniteCheck=True, name=y_value)
|
|
||||||
self.plot.addItem(curve)
|
|
||||||
self.curves.append(curve)
|
|
||||||
self.pens.append(pen)
|
|
||||||
self.brushs.append(brush)
|
|
||||||
|
|
||||||
# check if roi selector is in the plot
|
|
||||||
if self.roi_selector not in self.plot.items:
|
|
||||||
self.plot.addItem(self.roi_selector)
|
|
||||||
|
|
||||||
# init of 2D plot
|
|
||||||
self.plot_image.clear()
|
|
||||||
|
|
||||||
self.img = pg.ImageItem()
|
|
||||||
self.plot_image.addItem(self.img)
|
|
||||||
|
|
||||||
# hooking signals
|
|
||||||
self.hook_crosshair()
|
|
||||||
self.init_table()
|
|
||||||
|
|
||||||
def splitter_sizes(self): ...
|
|
||||||
|
|
||||||
def hook_crosshair(self):
|
|
||||||
self.crosshair_1d = Crosshair(self.plot, precision=4)
|
|
||||||
|
|
||||||
self.crosshair_1d.coordinatesChanged1D.connect(
|
|
||||||
lambda x, y: self.label_plot_moved.setText(f"Moved : ({x}, {y})")
|
|
||||||
)
|
|
||||||
self.crosshair_1d.coordinatesClicked1D.connect(
|
|
||||||
lambda x, y: self.label_plot_clicked.setText(f"Moved : ({x}, {y})")
|
|
||||||
)
|
|
||||||
|
|
||||||
self.crosshair_1d.coordinatesChanged1D.connect(
|
|
||||||
lambda x, y: self.update_table(table_widget=self.cursor_table, x=x, y_values=y)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.crosshair_2D = Crosshair(self.plot_image)
|
|
||||||
|
|
||||||
self.crosshair_2D.coordinatesChanged2D.connect(
|
|
||||||
lambda x, y: self.label_image_moved.setText(f"Moved : ({x}, {y})")
|
|
||||||
)
|
|
||||||
self.crosshair_2D.coordinatesClicked2D.connect(
|
|
||||||
lambda x, y: self.label_image_clicked.setText(f"Moved : ({x}, {y})")
|
|
||||||
)
|
|
||||||
|
|
||||||
# ROI
|
|
||||||
self.roi_selector.sigRegionChangeFinished.connect(self.get_roi_region)
|
|
||||||
|
|
||||||
def get_roi_region(self):
|
|
||||||
"""For testing purpose now, get roi region and print it to self.label as tuple"""
|
|
||||||
region = self.roi_selector.getRegion()
|
|
||||||
self.label_plot.setText(f"x = {(10 ** region[0]):.4f}, y ={(10 ** region[1]):.4f}")
|
|
||||||
return_dict = {
|
|
||||||
"horiz_roi": [
|
|
||||||
np.where(self.plotter_data_x[0] > 10 ** region[0])[0][0],
|
|
||||||
np.where(self.plotter_data_x[0] < 10 ** region[1])[0][-1],
|
|
||||||
]
|
|
||||||
}
|
|
||||||
msg = messages.DeviceMessage(signals=return_dict).dumps()
|
|
||||||
self.connector.set_and_publish("px_stream/gui_event", msg=msg)
|
|
||||||
self.roi_signal.emit(region)
|
|
||||||
|
|
||||||
def init_table(self):
|
|
||||||
# Init number of rows in table according to n of devices
|
|
||||||
self.ui.cursor_table.setRowCount(len(self.y_value_list))
|
|
||||||
# self.table.setHorizontalHeaderLabels(["(X, Y) - Moved", "(X, Y) - Clicked"]) #TODO can be dynamic
|
|
||||||
self.ui.cursor_table.setVerticalHeaderLabels(self.y_value_list)
|
|
||||||
self.ui.cursor_table.resizeColumnsToContents()
|
|
||||||
|
|
||||||
def update_table(self, table_widget, x, y_values):
|
|
||||||
for i, y in enumerate(y_values):
|
|
||||||
table_widget.setItem(i, 1, QTableWidgetItem(str(x)))
|
|
||||||
table_widget.setItem(i, 2, QTableWidgetItem(str(y)))
|
|
||||||
table_widget.resizeColumnsToContents()
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Update the plot with the new data."""
|
|
||||||
|
|
||||||
# check if QTable was initialised and if list of devices was changed
|
|
||||||
# if self.y_value_list != self.previous_y_value_list:
|
|
||||||
# self.setup_cursor_table()
|
|
||||||
# self.previous_y_value_list = self.y_value_list.copy() if self.y_value_list else None
|
|
||||||
|
|
||||||
self.curves[0].setData(self.plotter_data_x[0], self.plotter_data_y[0])
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def flip_even_rows(arr):
|
|
||||||
arr_copy = np.copy(arr) # Create a writable copy
|
|
||||||
arr_copy[1::2, :] = arr_copy[1::2, ::-1]
|
|
||||||
return arr_copy
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def remove_curve_by_name(plot: pyqtgraph.PlotItem, name: str) -> None:
|
|
||||||
# def remove_curve_by_name(plot: pyqtgraph.PlotItem, checkbox: QtWidgets.QCheckBox, name: str) -> None:
|
|
||||||
"""Removes a curve from the given plot by the specified name.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
plot (pyqtgraph.PlotItem): The plot from which to remove the curve.
|
|
||||||
name (str): The name of the curve to remove.
|
|
||||||
"""
|
|
||||||
# if checkbox.isChecked():
|
|
||||||
for item in plot.items:
|
|
||||||
if isinstance(item, pg.PlotDataItem) and getattr(item, "opts", {}).get("name") == name:
|
|
||||||
plot.removeItem(item)
|
|
||||||
return
|
|
||||||
|
|
||||||
# else:
|
|
||||||
# return
|
|
||||||
|
|
||||||
def on_projection(self, exit_event):
|
|
||||||
while not exit_event.is_set():
|
|
||||||
if self._current_proj is None:
|
|
||||||
time.sleep(0.1)
|
|
||||||
continue
|
|
||||||
endpoint = f"px_stream/projection_{self._current_proj}/data"
|
|
||||||
msgs = self.client.connector.lrange(topic=endpoint, start=-1, end=-1)
|
|
||||||
data = msgs
|
|
||||||
if not data:
|
|
||||||
continue
|
|
||||||
with np.errstate(divide="ignore", invalid="ignore"):
|
|
||||||
self.plotter_data_y = [
|
|
||||||
np.sum(
|
|
||||||
np.sum(data[-1].content["signals"]["data"] * self._current_norm, axis=1)
|
|
||||||
/ np.sum(self._current_norm, axis=0),
|
|
||||||
axis=0,
|
|
||||||
).squeeze()
|
|
||||||
]
|
|
||||||
|
|
||||||
self.update_signal.emit()
|
|
||||||
|
|
||||||
@Slot(dict, dict)
|
|
||||||
def on_dap_update(self, data: dict, metadata: dict):
|
|
||||||
flipped_data = self.flip_even_rows(data["data"]["z"])
|
|
||||||
|
|
||||||
self.img.setImage(flipped_data)
|
|
||||||
|
|
||||||
@Slot(dict, dict)
|
|
||||||
def new_proj(self, content: dict, _metadata: dict):
|
|
||||||
proj_nr = content["signals"]["proj_nr"]
|
|
||||||
endpoint = f"px_stream/projection_{proj_nr}/metadata"
|
|
||||||
msg_raw = self.client.connector.get(topic=endpoint)
|
|
||||||
msg = messages.DeviceMessage.loads(msg_raw)
|
|
||||||
self._current_q = msg.content["signals"]["q"]
|
|
||||||
self._current_norm = msg.content["signals"]["norm_sum"]
|
|
||||||
self._current_metadata = msg.content["signals"]["metadata"]
|
|
||||||
|
|
||||||
self.plotter_data_x = [self._current_q]
|
|
||||||
self._current_proj = proj_nr
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
# from bec_widgets import ctrl_c # TODO uncomment when ctrl_c is ready to be compatible with qtpy
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument(
|
|
||||||
"--signals", help="specify recorded signals", nargs="+", default=["gauss_bpm"]
|
|
||||||
)
|
|
||||||
# default = ["gauss_bpm", "bpm4i", "bpm5i", "bpm6i", "xert"],
|
|
||||||
value = parser.parse_args()
|
|
||||||
print(f"Plotting signals for: {', '.join(value.signals)}")
|
|
||||||
|
|
||||||
# Client from dispatcher
|
|
||||||
bec_dispatcher = BECDispatcher()
|
|
||||||
client = bec_dispatcher.client
|
|
||||||
|
|
||||||
app = QtWidgets.QApplication([])
|
|
||||||
# ctrl_c.setup(app) # TODO uncomment when ctrl_c is ready to be compatible with qtpy
|
|
||||||
plot = StreamPlot(y_value_list=value.signals, client=client)
|
|
||||||
|
|
||||||
bec_dispatcher.connect_slot(plot.new_proj, "px_stream/proj_nr")
|
|
||||||
bec_dispatcher.connect_slot(
|
|
||||||
plot.on_dap_update, MessageEndpoints.processed_data("px_dap_worker")
|
|
||||||
)
|
|
||||||
plot.show()
|
|
||||||
# client.callbacks.register("scan_segment", plot, sync=False)
|
|
||||||
app.exec()
|
|
@ -1,158 +0,0 @@
|
|||||||
# pylint: disable = no-name-in-module,missing-class-docstring, missing-module-docstring
|
|
||||||
import threading
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import pytest
|
|
||||||
from bec_lib import messages
|
|
||||||
from bec_lib.redis_connector import RedisConnector
|
|
||||||
from pytestqt import qtbot
|
|
||||||
|
|
||||||
from bec_widgets.examples.stream_plot.stream_plot import StreamPlot
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
|
||||||
def stream_app(qtbot):
|
|
||||||
"""Helper function to set up the StreamPlot widget."""
|
|
||||||
client = mock.MagicMock()
|
|
||||||
widget = StreamPlot(client=client)
|
|
||||||
qtbot.addWidget(widget)
|
|
||||||
qtbot.waitExposed(widget)
|
|
||||||
yield widget
|
|
||||||
widget.close()
|
|
||||||
|
|
||||||
|
|
||||||
def test_roi_signals_emitted(qtbot, stream_app):
|
|
||||||
region = (0.1, 0.9)
|
|
||||||
with qtbot.waitSignal(stream_app.roi_signal, timeout=1000) as blocker:
|
|
||||||
stream_app.roi_signal.emit(region)
|
|
||||||
assert blocker.signal_triggered
|
|
||||||
assert blocker.args == [region]
|
|
||||||
|
|
||||||
|
|
||||||
def test_update_signals_emitted(qtbot, stream_app):
|
|
||||||
# Mimic data coming from the data stream
|
|
||||||
stream_app.plotter_data_x = [list(range(10))] # Replace with the actual x data
|
|
||||||
stream_app.plotter_data_y = [list(range(10))] # Replace with the actual y data
|
|
||||||
|
|
||||||
# Initialize curves
|
|
||||||
stream_app.init_curves()
|
|
||||||
|
|
||||||
with qtbot.waitSignal(stream_app.update_signal, timeout=1000) as blocker:
|
|
||||||
stream_app.update_signal.emit()
|
|
||||||
assert blocker.signal_triggered
|
|
||||||
|
|
||||||
|
|
||||||
def test_ui_initialization(qtbot, stream_app):
|
|
||||||
"""Checking the UI creation."""
|
|
||||||
|
|
||||||
# Check if UI elements are initialized correctly
|
|
||||||
assert stream_app.label_plot is not None
|
|
||||||
assert stream_app.label_plot_moved is not None
|
|
||||||
assert stream_app.label_plot_clicked is not None
|
|
||||||
assert stream_app.label_image_moved is not None
|
|
||||||
assert stream_app.label_image_clicked is not None
|
|
||||||
|
|
||||||
# Check if plots are initialized correctly
|
|
||||||
assert stream_app.plot is not None
|
|
||||||
assert stream_app.plot_image is not None
|
|
||||||
|
|
||||||
# Check if ROI selector is initialized correctly
|
|
||||||
assert stream_app.roi_selector is not None
|
|
||||||
|
|
||||||
|
|
||||||
def test_1d_plotting_data(qtbot, stream_app):
|
|
||||||
# Set up some mock data
|
|
||||||
x_data = [list(range(10))]
|
|
||||||
y_data = [list(range(10))]
|
|
||||||
|
|
||||||
# Manually set the data attributes
|
|
||||||
stream_app.plotter_data_x = x_data
|
|
||||||
stream_app.plotter_data_y = y_data
|
|
||||||
stream_app.y_value_list = ["Curve 1"]
|
|
||||||
|
|
||||||
# Initialize curves and update the plot
|
|
||||||
stream_app.init_curves()
|
|
||||||
stream_app.update() # This should update the plot with the new data
|
|
||||||
|
|
||||||
# Check the data on the plot
|
|
||||||
for idx, curve in enumerate(stream_app.curves):
|
|
||||||
np.testing.assert_array_equal(curve.xData, x_data[0]) # Access the first list of x_data
|
|
||||||
np.testing.assert_array_equal(
|
|
||||||
curve.yData, y_data[idx]
|
|
||||||
) # Access the list of y_data for each curve without additional indexing
|
|
||||||
|
|
||||||
|
|
||||||
def test_flip_even_rows(qtbot, stream_app):
|
|
||||||
# Create a numpy array with some known data
|
|
||||||
original_array = np.array(
|
|
||||||
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20]]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Call flip_even_rows on the original array
|
|
||||||
flipped_array = stream_app.flip_even_rows(original_array)
|
|
||||||
|
|
||||||
# Expected array flipped along the rows with even indices
|
|
||||||
expected_array = np.array(
|
|
||||||
[[1, 2, 3, 4, 5], [10, 9, 8, 7, 6], [11, 12, 13, 14, 15], [20, 19, 18, 17, 16]]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check that flip_even_rows returned the expected result
|
|
||||||
np.testing.assert_array_equal(flipped_array, expected_array)
|
|
||||||
|
|
||||||
|
|
||||||
def test_on_dap_update(qtbot, stream_app):
|
|
||||||
"""2D image rendering by dap update"""
|
|
||||||
# Create some mock data to be "received" by the slot
|
|
||||||
data_dict = {"data": {"z": np.random.rand(10, 10)}}
|
|
||||||
metadata_dict = {}
|
|
||||||
|
|
||||||
# Trigger the slot
|
|
||||||
stream_app.on_dap_update(data_dict, metadata_dict)
|
|
||||||
|
|
||||||
# Apply the same transformation to the test data
|
|
||||||
expected_data = stream_app.flip_even_rows(data_dict["data"]["z"])
|
|
||||||
|
|
||||||
# Now check the state of the StreamPlot object
|
|
||||||
# For example, check the data of the image plot:
|
|
||||||
np.testing.assert_array_equal(stream_app.img.image, expected_data)
|
|
||||||
|
|
||||||
|
|
||||||
####################
|
|
||||||
# Until Here
|
|
||||||
####################
|
|
||||||
|
|
||||||
# def test_new_proj(qtbot, stream_app): #TODO this test is not working, does it make sense testing even?
|
|
||||||
# # Create some mock content to be "received" by the slot
|
|
||||||
# content_dict = {"signals": {"proj_nr": 1}}
|
|
||||||
# metadata_dict = {}
|
|
||||||
#
|
|
||||||
# # Manually create some mock data that new_proj would work with
|
|
||||||
# # This step may need to be adjusted to fit the actual behavior of new_proj
|
|
||||||
# mock_data = {
|
|
||||||
# "q": np.array([1, 2, 3, 4, 5]),
|
|
||||||
# "norm_sum": np.array([6, 7, 8, 9, 10]),
|
|
||||||
# "metadata": "some_metadata",
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# # Assume the RedisConnector client would return this data when new_proj is called
|
|
||||||
# mock_message = mock.MagicMock(spec=messages.DeviceMessage)
|
|
||||||
# mock_message.__getitem__.side_effect = lambda key: mock_data[key]
|
|
||||||
# stream_app.client.producer.get = mock.MagicMock(return_value=mock_message.dumps())
|
|
||||||
#
|
|
||||||
# # Trigger the slot
|
|
||||||
# stream_app.new_proj(content_dict, metadata_dict)
|
|
||||||
#
|
|
||||||
# # Now check the state of the StreamPlot object
|
|
||||||
# # For example, check that the plotter_data_x attribute was updated correctly:
|
|
||||||
# np.testing.assert_array_equal(stream_app.plotter_data_x, [mock_data["q"]])
|
|
||||||
# assert stream_app._current_proj == 1
|
|
||||||
# assert stream_app._current_q == mock_data["q"]
|
|
||||||
# assert stream_app._current_norm == mock_data["norm_sum"]
|
|
||||||
# assert stream_app._current_metadata == mock_data["metadata"]
|
|
||||||
|
|
||||||
|
|
||||||
# def test_connection_creation(qtbot, stream_app): #TODO maybe test connections in a different way?
|
|
||||||
# assert isinstance(stream_app.producer, RedisConnector)
|
|
||||||
# assert isinstance(stream_app.data_retriever, threading.Thread)
|
|
||||||
# assert stream_app.data_retriever.is_alive()
|
|
Reference in New Issue
Block a user