diff --git a/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py b/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py
index 01a3796..608014b 100644
--- a/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py
+++ b/debye_bec/bec_widgets/widgets/digital_twin/digital_twin.py
@@ -1,18 +1,19 @@
import sys
-import os
import datetime
import numpy as np
from bec_lib import bec_logger
# pylint: disable=E0611
from qtpy.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
- QDoubleSpinBox, QGroupBox, QApplication, QLineEdit, QLayout
+ QApplication, QLayout
)
# pylint: disable=E0611
-from qtpy.QtCore import QTimer, Qt
-from qtpy.QtGui import QColor
+from qtpy.QtCore import Qt
+from qtpy.QtGui import QColor, QFont
import pyqtgraph as pg
+from xrt.backends.raycing.physconsts import CHeVcm, AVOGADRO
+
from bec_widgets.utils.bec_widget import BECWidget
from bec_widgets.utils.error_popups import SafeSlot
@@ -20,7 +21,6 @@ from debye_bec.bec_widgets.widgets.qt_widgets import InputNumberField, ComboBox,
from debye_bec.bec_widgets.widgets.digital_twin.calculate_positions import calc_positions
-from xrt.backends.raycing.physconsts import CHeVcm, AVOGADRO
import debye_bec.bec_widgets.widgets.digital_twin.x01da_parameters as bl
logger = bec_logger.logger
@@ -33,7 +33,6 @@ class DigitalTwin(BECWidget, QWidget):
- A live plot that updates every second
"""
- USER_ACCESS = ["set_a", "set_b"]
PLUGIN = True
ICON_NAME = "lightbulb"
@@ -41,23 +40,20 @@ class DigitalTwin(BECWidget, QWidget):
super().__init__(parent=parent, theme_update=True, *arg, **kwargs)
self.get_bec_shortcuts()
- self._history = [] # stores (sum, product) over time
- self._t = 0 # tick counter
-
central = QWidget()
self.root_layout = QHBoxLayout(central)
- self.plot_widget = PlotWidget(title='Plot title', chart_data = [])
self.input = InputPanel()
+ self.plot_widget = PlotWidget()
self.positions = PositionsPanel()
- self.root_layout.addWidget(self.plot_widget, stretch=3)
- self.root_layout.addWidget(self.input, stretch=1, alignment=Qt.AlignTop)
- self.root_layout.addWidget(self.positions, stretch=1, alignment=Qt.AlignTop)
+ self.root_layout.addWidget(self.input, stretch=1, alignment=Qt.AlignTop) # type: ignore
+ self.root_layout.addWidget(self.plot_widget, stretch=1, alignment=Qt.AlignTop) # type: ignore
+ self.root_layout.addWidget(self.positions, stretch=1, alignment=Qt.AlignTop) # type: ignore
self.setLayout(self.root_layout)
self.setWindowTitle("Digital Twin")
- self.resize(600, 500)
+ # self.resize(1500, 800)
self.input.energy.value_changed_connect(self.calc_bragg_angle)
self.input.sldi_hacc.value_changed_connect(self.calc_positions)
@@ -197,7 +193,7 @@ class InputPanel(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self._layout = QVBoxLayout(self)
- self._layout.setSizeConstraint(QLayout.SetFixedSize)
+ self._layout.setSizeConstraint(QLayout.SetFixedSize) # type: ignore
# Energy
self.energy = InputNumberField('Energy [keV]', init=8979, decimals=0, single_step=100, ll=4000, hl=65000)
@@ -275,7 +271,7 @@ class PositionsPanel(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self._layout = QVBoxLayout(self)
- self._layout.setSizeConstraint(QLayout.SetFixedSize)
+ self._layout.setSizeConstraint(QLayout.SetFixedSize) # type: ignore
# FE Slits
self.sldi_gapx = NumberIndicator('GAPX', 'mm', decimals=3)
@@ -402,25 +398,31 @@ class PositionsPanel(QWidget):
class PlotWidget(QWidget):
"""Plot widget with two curves and legend."""
- def __init__(self, title: str = "Title", chart_data = [], max_points=2000, parent=None):
+ def __init__(self, parent=None):
super().__init__(parent)
- self.chart_data = chart_data
- self.max_points = max_points
-
self._layout = QVBoxLayout(self)
- self._title = QLabel(f"
{title}
")
- self._layout.addWidget(self._title)
+ # self._layout.setSizeConstraint(QLayout.SetFixedSize) # type: ignore
- self.plot_widget = pg.PlotWidget(axisItems={'bottom': TimeAxis(orientation='bottom')})
+ self.plot_widget = pg.PlotWidget()
self.plot_widget.getAxis('bottom').enableAutoSIPrefix(False)
self.plot_widget.addLegend()
self.curves = []
colors = self.golden_angle_color(
- colormap='plasma', num=max(10, len(self.curves) + 1), format="HEX"
+ colormap='plasma',
+ num=2,
+ format="HEX",
)
+ self.color_impenetrable = self.impenetrable_color()
- for idx, element in enumerate(self.chart_data):
+ self.data = {
+ 'assistant': [[0, 1000, 2000], [0, 20, 30]],
+ 'reality': [[0, 1000, 2000], [0, 18, 36]],
+ }
+ self.pipes = []
+ self.walls = []
+
+ for idx, element in enumerate(self.data):
self.curves.append(
self.plot_widget.plot(
[],
@@ -430,10 +432,62 @@ class PlotWidget(QWidget):
)
)
- self._layout.addWidget(self.plot_widget)
+ self.plot_group = Group(
+ 'Side View',
+ [
+ self.plot_widget,
+ ]
+ )
- self.plot_widget.setLabel('left', 'Temperature [°C]')
- self.plot_widget.setLabel('bottom', 'Time')
+ self.plot_widget.setLabel('left', 'Height [mm]')
+ self.plot_widget.setLabel('bottom', 'Distance [mm]')
+ self.plot_widget.setMouseEnabled(x=False, y=False)
+ self.plot_widget.setXRange(0, 25000, padding=0.1)
+ self.plot_widget.setYRange(-20, 120, padding=0.1)
+ self.plot_widget.setMenuEnabled(False)
+ self.plot_widget.hideButtons()
+
+ self._layout.addWidget(self.plot_group)
+ self._layout.addStretch()
+
+ self.plot_vacuum_pipes()
+ self.plot_walls()
+ self.update_curves()
+
+ def plot_vacuum_pipes(self):
+ for i, _ in enumerate(bl.vacuum_pipes.center):
+ top = bl.vacuum_pipes.center[i] + bl.vacuum_pipes.diameter[i]/2 + bl.sourceHeight
+ bottom = bl.vacuum_pipes.center[i] - bl.vacuum_pipes.diameter[i]/2 + bl.sourceHeight
+ self.pipes.append(self.plot_widget.plot(
+ x=np.array([bl.vacuum_pipes.start[i], bl.vacuum_pipes.end[i]]),
+ y=np.array([top, top]),
+ pen=pg.mkPen(color=self.color_impenetrable, width=2),
+ ))
+ self.pipes.append(self.plot_widget.plot(
+ x=np.array([bl.vacuum_pipes.start[i], bl.vacuum_pipes.end[i]]),
+ y=np.array([bottom, bottom]),
+ pen=pg.mkPen(color=self.color_impenetrable, width=2),
+ ))
+
+ def plot_walls(self):
+ for i, _ in enumerate(bl.walls.start):
+ rect = pg.QtWidgets.QGraphicsRectItem( # pylint: disable=E1101
+ bl.walls.start[i],
+ bl.walls.height[i][0],
+ bl.walls.end[i] - bl.walls.start[i],
+ bl.walls.height[i][1] - bl.walls.height[i][0],
+ )
+ rect.setBrush(pg.QtGui.QBrush(pg.QtGui.QColor(*self.color_impenetrable))) # pylint: disable=E1101
+ rect.setPen(pg.mkPen(color=self.color_impenetrable, width=2))
+ self.plot_widget.addItem(rect)
+
+ def impenetrable_color(self):
+ app = QApplication.instance()
+ theme = app.theme.theme # type: ignore
+ if theme == "light":
+ return (30, 30, 30)
+ else:
+ return (220, 220, 220)
def golden_angle_color(
self,
@@ -470,10 +524,10 @@ class PlotWidget(QWidget):
positions = min_pos + positions * (max_pos - min_pos)
# Sample colors from the colormap at the calculated positions
- colors = cmap.map(positions, mode="float")
+ colors = cmap.map(positions, mode="float") # type: ignore
color_list = []
- for color in colors:
+ for color in colors: # type: ignore
if format.upper() == "HEX":
color_list.append(QColor.fromRgbF(*color).name())
elif format.upper() == "RGB":
@@ -505,7 +559,7 @@ class PlotWidget(QWidget):
if theme is None:
app = QApplication.instance()
if hasattr(app, "theme"):
- theme = app.theme.theme
+ theme = app.theme.theme # type: ignore
if theme == "light":
min_pos = 0.0
@@ -516,17 +570,12 @@ class PlotWidget(QWidget):
return min_pos, max_pos
- def update_curves(self, timestamps: list[str], data: list[float]):
- x = timestamps.copy()
- y = data.copy()
- min_len = min([min([len(i) for i in y]), len(x)])
- x_float = [t.timestamp() for t in x]
- for idx, element in enumerate(y):
- self.curves[idx].setData(x=np.array(x_float)[0:min_len], y=np.array(element)[0:min_len])
-
-class TimeAxis(pg.AxisItem):
- def tickStrings(self, values, scale, spacing):
- return [datetime.fromtimestamp(value).strftime("%H:%M:%S") for value in values]
+ def update_curves(self):
+ for idx, element in enumerate(self.data):
+ self.curves[idx].setData(
+ x=np.array(self.data[element][0]),
+ y=np.array(self.data[element][1]),
+ )
# --------------------------------------------------------- Standalone run ---
@@ -537,10 +586,10 @@ if __name__ == "__main__":
from bec_widgets.utils.colors import apply_theme
app = QApplication(sys.argv)
- apply_theme("dark")
+ apply_theme("light")
dispatcher = BECDispatcher(gui_id="digital_twin")
win = DigitalTwin()
- win.resize(1000, 800)
+ # win.resize(1000, 800)
win.show()
sys.exit(app.exec_())
\ No newline at end of file
diff --git a/debye_bec/bec_widgets/widgets/digital_twin/x01da_parameters.py b/debye_bec/bec_widgets/widgets/digital_twin/x01da_parameters.py
index 1ddd98b..cb5db48 100644
--- a/debye_bec/bec_widgets/widgets/digital_twin/x01da_parameters.py
+++ b/debye_bec/bec_widgets/widgets/digital_twin/x01da_parameters.py
@@ -289,3 +289,23 @@ smpl = sample(
smpl2 = sample(
name='EH-SMPL2',
center=[0, 27500, sourceHeight],)
+
+# Vacuum pipes
+# DN40CF ID = 35 mm oder 37 mm
+# DN50CF ID = 47.5 mm
+# DN63CF ID = 60.2 mm oder 66 mm
+# DN100CF ID = 97.4 mm oder 104 mm
+pipe = namedtuple('pipes', ['center', 'diameter', 'start', 'end'])
+vacuum_pipes = pipe(
+ center= [27.5, (37.5+27.5)/2, 37.5, 62.5, 72.5],
+ diameter=[97.4, 97.4, 97.4, 97.4, 97.4],
+ start= [10952.88, 11750+250, mo2.center[1]+250, 14000, fm.center[1]],
+ end= [11750-250, mo2.center[1]-250, 14000, fm.center[1], ehWindow.center[1]],
+)
+
+Walls = namedtuple('walls', ['start', 'end', 'height'])
+walls = Walls(
+ start= [13999.30],
+ end= [13999+75.5+30],
+ height= [[-20, 25]],
+)
diff --git a/debye_bec/bec_widgets/widgets/qt_widgets.py b/debye_bec/bec_widgets/widgets/qt_widgets.py
index 14d0fdd..2ccb69b 100644
--- a/debye_bec/bec_widgets/widgets/qt_widgets.py
+++ b/debye_bec/bec_widgets/widgets/qt_widgets.py
@@ -10,9 +10,9 @@ from qtpy.QtGui import QFont
class Group(QGroupBox):
def __init__(self, label, widgets):
super().__init__(label)
- self.layout = QVBoxLayout(self)
+ self.layout = QVBoxLayout(self) # type: ignore
for widget in widgets:
- self.layout.addWidget(widget)
+ self.layout.addWidget(widget) # type: ignore
# class TextIndicator(QWidget):
# def __init__(self, label, unit=None, highlight=False):
@@ -94,8 +94,8 @@ class InputTextField(QWidget):
def has_focus(self) -> bool:
return self.val.hasFocus()
- def value(self) -> float:
- return self.val.val()
+ def text(self) -> str:
+ return self.val.text()
def set_on_return(self, func):
"""Connect a function to the Enter/Return key press."""