Source code for pyccapt.control.gui.gui_visualization

import multiprocessing
import os
import sys
import time

import numpy as np
import pyqtgraph as pg
import pyqtgraph.exporters
# from numba import njit
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtCore import QTimer

# Local module and scripts
from pyccapt.control.core import runtime, tof2mc_simple
from pyccapt.control.devices import initialize_devices


[docs] class Ui_Visualization(object): def __init__(self, variables, conf, x_plot, y_plot, t_plot, main_v_dc_plot): """ Constructor for the Visualization UI class. Args: variables (object): Global experiment variables. conf (dict): Configuration settings. x_plot (multiprocessing.Array): Array for storing the x-axis values of the mass spectrum. y_plot (multiprocessing.Array): Array for storing the y-axis values of the mass spectrum. t_plot (multiprocessing.Array): Array for storing the time values of the mass spectrum. main_v_dc_plot (multiprocessing.Array): Array for storing the main voltage values of the mass spectrum. """ self.path_meta = None self.num_hit_display = 0 self.bins_detector = (256, 256) detector_diameter = conf["detector_diameter"] detector_diameter = detector_diameter / 2 self.range = [[-detector_diameter, detector_diameter], [-detector_diameter, detector_diameter]] self.hist_fdm, xedges, yedges = np.histogram2d([], [], bins=self.bins_detector, range=self.range) self.index_hist_mc = None self.index_hist_tof = None self.max_tof_val = None self.max_mc_val = None self.last_100_thousand_det_x_heatmap = np.array([]) self.last_100_thousand_det_y_heatmap = np.array([]) self.last_100_thousand_t = np.array([]) self.last_100_thousand_v = np.array([]) self.last_100_thousand_det_x = np.array([]) self.last_100_thousand_det_y = np.array([]) self.length_events = 0 self.styles = None self.num_event_mc_tof = None self.mc_tof_last_events_flag = False self.change_detection_rate_range = False self.start_time_metadata = 0 self.start_main_exp = 0 self.index_plot_start = 0 self.variables = variables self.conf = conf self.x_plot = x_plot self.y_plot = y_plot self.t_plot = t_plot self.main_v_dc_plot = main_v_dc_plot self.counter_source = '' self.index_plot_save = 0 self.index_plot = 0 self.index_wait_on_plot_start = 0 self.index_auto_scale_graph = 0 self.heatmap_fdm_switch_flag = 'heatmap' self.bins_mc = np.arange(0, self.conf["max_mass"] + self.conf['bin_size'], self.conf['bin_size']) self.bins_tof = np.arange(0, self.conf["max_tof"] + self.conf['bin_size'], self.conf['bin_size']) self.hist_mc = np.zeros(len(self.bins_mc) - 1) self.hist_tof = np.zeros(len(self.bins_tof) - 1) self.update_timer = QTimer() # Create a QTimer for updating graphs self.update_timer.timeout.connect(self.update_graphs) # Connect it to the update_graphs slot self.visualization_window = None # Inâ™ itialize the attribute
[docs] def setupUi(self, Visualization): """ Setup the UI for the Visualization window. Args: Visualization (QMainWindow): Visualization window. Return: None """ Visualization.setObjectName("Visualization") Visualization.resize(822, 647) self.gridLayout_6 = QtWidgets.QGridLayout(Visualization) self.gridLayout_6.setObjectName("gridLayout_6") self.gridLayout_5 = QtWidgets.QGridLayout() self.gridLayout_5.setObjectName("gridLayout_5") self.gridLayout_4 = QtWidgets.QGridLayout() self.gridLayout_4.setObjectName("gridLayout_4") self.label_200 = QtWidgets.QLabel(parent=Visualization) font = QtGui.QFont() font.setBold(True) self.label_200.setFont(font) self.label_200.setObjectName("label_200") self.gridLayout_4.addWidget(self.label_200, 0, 0, 1, 1) self.voltage = QtWidgets.QLineEdit(parent=Visualization) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.voltage.sizePolicy().hasHeightForWidth()) self.voltage.setSizePolicy(sizePolicy) self.voltage.setMinimumSize(QtCore.QSize(100, 20)) self.voltage.setStyleSheet("QLineEdit{\n" " background: rgb(223,223,233)\n" " }\n" " ") self.voltage.setObjectName("voltage") self.gridLayout_4.addWidget(self.voltage, 0, 1, 1, 1) spacerItem = QtWidgets.QSpacerItem(26, 17, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.gridLayout_4.addItem(spacerItem, 0, 2, 1, 1) #### # self.vdc_time = QtWidgets.QGraphicsView(parent=Visualization) self.vdc_time = pg.PlotWidget(parent=Visualization) self.vdc_time.setBackground('w') #### sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) sizePolicy.setHeightForWidth(self.vdc_time.sizePolicy().hasHeightForWidth()) self.vdc_time.setSizePolicy(sizePolicy) self.vdc_time.setMinimumSize(QtCore.QSize(250, 250)) self.vdc_time.setStyleSheet("QWidget{\n" " border: 0.5px solid gray;\n" " }\n" " ") self.vdc_time.setObjectName("vdc_time") self.gridLayout_4.addWidget(self.vdc_time, 1, 0, 1, 3) self.dc_hold = QtWidgets.QPushButton(parent=Visualization) self.dc_hold.setMinimumSize(QtCore.QSize(100, 20)) self.dc_hold.setMaximumSize(QtCore.QSize(100, 16777215)) self.dc_hold.setObjectName("dc_hold") self.gridLayout_4.addWidget(self.dc_hold, 2, 0, 1, 2) self.gridLayout_5.addLayout(self.gridLayout_4, 0, 0, 1, 1) self.gridLayout = QtWidgets.QGridLayout() self.gridLayout.setObjectName("gridLayout") self.label_201 = QtWidgets.QLabel(parent=Visualization) font = QtGui.QFont() font.setBold(True) self.label_201.setFont(font) self.label_201.setObjectName("label_201") self.gridLayout.addWidget(self.label_201, 0, 0, 1, 1) self.detection_rate = QtWidgets.QLineEdit(parent=Visualization) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.detection_rate.sizePolicy().hasHeightForWidth()) self.detection_rate.setSizePolicy(sizePolicy) self.detection_rate.setMinimumSize(QtCore.QSize(100, 20)) self.detection_rate.setStyleSheet("QLineEdit{\n" " background: rgb(223,223,233)\n" " }\n" " ") self.detection_rate.setObjectName("detection_rate") self.gridLayout.addWidget(self.detection_rate, 0, 1, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.gridLayout.addItem(spacerItem1, 0, 2, 1, 1) #### # self.detection_rate_viz = QtWidgets.QGraphicsView(parent=Visualization) self.detection_rate_viz = pg.PlotWidget(parent=Visualization) self.detection_rate_viz.setBackground('w') #### sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) sizePolicy.setHeightForWidth(self.detection_rate_viz.sizePolicy().hasHeightForWidth()) self.detection_rate_viz.setSizePolicy(sizePolicy) self.detection_rate_viz.setMinimumSize(QtCore.QSize(250, 250)) self.detection_rate_viz.setStyleSheet("QWidget{\n" " border: 0.5px solid gray;\n" " }\n" " ") self.detection_rate_viz.setObjectName("detection_rate_viz") self.gridLayout.addWidget(self.detection_rate_viz, 1, 0, 1, 3) self.detection_rate_range_switch = QtWidgets.QPushButton(parent=Visualization) self.detection_rate_range_switch.setMinimumSize(QtCore.QSize(0, 20)) self.detection_rate_range_switch.setMaximumSize(QtCore.QSize(100, 16777215)) self.detection_rate_range_switch.setObjectName("detection_rate_range_switch") self.gridLayout.addWidget(self.detection_rate_range_switch, 2, 0, 1, 1) self.gridLayout_5.addLayout(self.gridLayout, 0, 1, 1, 1) self.gridLayout_3 = QtWidgets.QGridLayout() self.gridLayout_3.setObjectName("gridLayout_3") self.label_206 = QtWidgets.QLabel(parent=Visualization) font = QtGui.QFont() font.setBold(True) self.label_206.setFont(font) self.label_206.setObjectName("label_206") self.gridLayout_3.addWidget(self.label_206, 0, 0, 1, 1) self.hitmap_count = QtWidgets.QLineEdit(parent=Visualization) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.hitmap_count.sizePolicy().hasHeightForWidth()) self.hitmap_count.setSizePolicy(sizePolicy) self.hitmap_count.setMinimumSize(QtCore.QSize(100, 20)) self.hitmap_count.setStyleSheet("QLineEdit{\n" " background: rgb(223,223,233)\n" " }\n" " ") self.hitmap_count.setObjectName("hitmap_count") self.gridLayout_3.addWidget(self.hitmap_count, 0, 1, 1, 1) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.gridLayout_3.addItem(spacerItem2, 0, 2, 1, 1) ### # self.detector_heatmap = QtWidgets.QGraphicsView(parent=Visualization) self.detector_heatmap = pg.PlotWidget(parent=Visualization) self.detector_heatmap.setBackground('w') ### sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) sizePolicy.setHeightForWidth(self.detector_heatmap.sizePolicy().hasHeightForWidth()) self.detector_heatmap.setSizePolicy(sizePolicy) self.detector_heatmap.setMinimumSize(QtCore.QSize(250, 250)) self.detector_heatmap.setStyleSheet("QWidget{\n" " border: 0.5px solid gray;\n" " }\n" " ") self.detector_heatmap.setObjectName("detector_heatmap") self.gridLayout_3.addWidget(self.detector_heatmap, 1, 0, 1, 3) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.reset_heatmap_v = QtWidgets.QPushButton(parent=Visualization) self.reset_heatmap_v.setMinimumSize(QtCore.QSize(0, 20)) self.reset_heatmap_v.setMaximumSize(QtCore.QSize(60, 16777215)) self.reset_heatmap_v.setObjectName("reset_heatmap_v") self.horizontalLayout_2.addWidget(self.reset_heatmap_v) self.hitmap_plot_size = QtWidgets.QDoubleSpinBox(parent=Visualization) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.hitmap_plot_size.sizePolicy().hasHeightForWidth()) self.hitmap_plot_size.setSizePolicy(sizePolicy) self.hitmap_plot_size.setMinimumSize(QtCore.QSize(0, 20)) self.hitmap_plot_size.setStyleSheet("QDoubleSpinBox{\n" " background: rgb(223,223,233)\n" " }\n" " ") self.hitmap_plot_size.setObjectName("hitmap_plot_size") self.horizontalLayout_2.addWidget(self.hitmap_plot_size) self.hit_displayed = QtWidgets.QLineEdit(parent=Visualization) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.hit_displayed.sizePolicy().hasHeightForWidth()) self.hit_displayed.setSizePolicy(sizePolicy) self.hit_displayed.setMinimumSize(QtCore.QSize(50, 20)) self.hit_displayed.setStyleSheet("QLineEdit{\n" " background: rgb(223,223,233)\n" " }\n" " ") self.hit_displayed.setObjectName("hit_displayed") self.horizontalLayout_2.addWidget(self.hit_displayed) self.heatmap_fdm_switch = QtWidgets.QPushButton(parent=Visualization) self.heatmap_fdm_switch.setMinimumSize(QtCore.QSize(100, 20)) self.heatmap_fdm_switch.setMaximumSize(QtCore.QSize(60, 16777215)) self.heatmap_fdm_switch.setObjectName("heatmap_fdm_switch") self.horizontalLayout_2.addWidget(self.heatmap_fdm_switch) self.gridLayout_3.addLayout(self.horizontalLayout_2, 2, 0, 1, 3) self.gridLayout_5.addLayout(self.gridLayout_3, 0, 2, 1, 1) self.gridLayout_2 = QtWidgets.QGridLayout() self.gridLayout_2.setObjectName("gridLayout_2") self.label_207 = QtWidgets.QLabel(parent=Visualization) self.label_207.setMinimumSize(QtCore.QSize(0, 25)) font = QtGui.QFont() font.setBold(True) self.label_207.setFont(font) self.label_207.setObjectName("label_207") self.gridLayout_2.addWidget(self.label_207, 0, 0, 1, 1) #### # self.histogram = QtWidgets.QGraphicsView(parent=Visualization) self.histogram = pg.PlotWidget(parent=Visualization) self.histogram.setBackground('w') #### sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) sizePolicy.setHeightForWidth(self.histogram.sizePolicy().hasHeightForWidth()) self.histogram.setSizePolicy(sizePolicy) self.histogram.setMinimumSize(QtCore.QSize(750, 150)) self.histogram.setStyleSheet("QWidget{\n" " border: 0.5px solid gray;\n" " }\n" " ") self.histogram.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) self.histogram.setObjectName("histogram") self.gridLayout_2.addWidget(self.histogram, 1, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.spectrum_switch = QtWidgets.QPushButton(parent=Visualization) self.spectrum_switch.setMinimumSize(QtCore.QSize(0, 20)) self.spectrum_switch.setMaximumSize(QtCore.QSize(60, 16777215)) self.spectrum_switch.setObjectName("spectrum_switch") self.horizontalLayout.addWidget(self.spectrum_switch) self.spectrum_last_events_switch = QtWidgets.QPushButton(parent=Visualization) self.spectrum_last_events_switch.setMinimumSize(QtCore.QSize(0, 20)) self.spectrum_last_events_switch.setMaximumSize(QtCore.QSize(100, 16777215)) self.spectrum_last_events_switch.setObjectName("spectrum_last_events_switch") self.horizontalLayout.addWidget(self.spectrum_last_events_switch) self.num_last_events = QtWidgets.QLineEdit(parent=Visualization) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.num_last_events.sizePolicy().hasHeightForWidth()) self.num_last_events.setSizePolicy(sizePolicy) self.num_last_events.setMinimumSize(QtCore.QSize(100, 20)) self.num_last_events.setStyleSheet("QLineEdit{\n" " background: rgb(223,223,233)\n" " }\n" " ") self.num_last_events.setObjectName("num_last_events") self.horizontalLayout.addWidget(self.num_last_events) self.label_208 = QtWidgets.QLabel(parent=Visualization) self.label_208.setMinimumSize(QtCore.QSize(0, 25)) font = QtGui.QFont() font.setBold(True) self.label_208.setFont(font) self.label_208.setObjectName("label_208") self.horizontalLayout.addWidget(self.label_208) self.max_mc = QtWidgets.QLineEdit(parent=Visualization) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.max_mc.sizePolicy().hasHeightForWidth()) self.max_mc.setSizePolicy(sizePolicy) self.max_mc.setMinimumSize(QtCore.QSize(100, 20)) self.max_mc.setStyleSheet("QLineEdit{\n" " background: rgb(223,223,233)\n" " }\n" " ") self.max_mc.setObjectName("max_mc") self.horizontalLayout.addWidget(self.max_mc) self.label_209 = QtWidgets.QLabel(parent=Visualization) self.label_209.setMinimumSize(QtCore.QSize(0, 25)) font = QtGui.QFont() font.setBold(True) self.label_209.setFont(font) self.label_209.setObjectName("label_209") self.horizontalLayout.addWidget(self.label_209) self.max_tof = QtWidgets.QLineEdit(parent=Visualization) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.max_tof.sizePolicy().hasHeightForWidth()) self.max_tof.setSizePolicy(sizePolicy) self.max_tof.setMinimumSize(QtCore.QSize(100, 20)) self.max_tof.setStyleSheet("QLineEdit{\n" " background: rgb(223,223,233)\n" " }\n" " ") self.max_tof.setObjectName("max_tof") self.horizontalLayout.addWidget(self.max_tof) spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem3) self.gridLayout_2.addLayout(self.horizontalLayout, 2, 0, 1, 1) self.Error = QtWidgets.QLabel(parent=Visualization) self.Error.setMinimumSize(QtCore.QSize(800, 30)) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setStrikeOut(False) self.Error.setFont(font) self.Error.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.Error.setWordWrap(True) self.Error.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse) self.Error.setObjectName("Error") self.gridLayout_2.addWidget(self.Error, 3, 0, 1, 1) self.gridLayout_5.addLayout(self.gridLayout_2, 1, 0, 1, 3) self.gridLayout_6.addLayout(self.gridLayout_5, 0, 0, 1, 1) self.retranslateUi(Visualization) QtCore.QMetaObject.connectSlotsByName(Visualization) Visualization.setTabOrder(self.voltage, self.detection_rate) Visualization.setTabOrder(self.detection_rate, self.hitmap_count) Visualization.setTabOrder(self.hitmap_count, self.dc_hold) Visualization.setTabOrder(self.dc_hold, self.detection_rate_range_switch) Visualization.setTabOrder(self.detection_rate_range_switch, self.reset_heatmap_v) Visualization.setTabOrder(self.reset_heatmap_v, self.hitmap_plot_size) Visualization.setTabOrder(self.hitmap_plot_size, self.hit_displayed) Visualization.setTabOrder(self.hit_displayed, self.heatmap_fdm_switch) Visualization.setTabOrder(self.heatmap_fdm_switch, self.spectrum_switch) Visualization.setTabOrder(self.spectrum_switch, self.spectrum_last_events_switch) Visualization.setTabOrder(self.spectrum_last_events_switch, self.num_last_events) Visualization.setTabOrder(self.num_last_events, self.max_mc) Visualization.setTabOrder(self.max_mc, self.max_tof) Visualization.setTabOrder(self.max_tof, self.vdc_time) Visualization.setTabOrder(self.vdc_time, self.detection_rate_viz) Visualization.setTabOrder(self.detection_rate_viz, self.detector_heatmap) Visualization.setTabOrder(self.detector_heatmap, self.histogram) ### # Start the update timer with a 500 ms interval (2 times per second) self.update_timer.start(500) # High Voltage visualization ################ self.x_vdc = [i * 0.5 for i in range(200)] # 100 time points self.y_vdc = [0.0] * 200 # 200 data points, all initialized to 0.0 self.y_vdc[:] = [np.nan] * len(self.y_vdc) pen_vdc = pg.mkPen(color=(255, 0, 0), width=3) self.data_line_vdc = self.vdc_time.plot(self.x_vdc, self.y_vdc, pen=pen_vdc) self.vdc_time.plotItem.setMouseEnabled(x=False) # Only allow zoom in Y-axis # Add Axis Labels self.styles = {"color": "#f00", "font-size": "12px"} self.vdc_time.setLabel("left", "High Voltage", units='V', **self.styles) self.vdc_time.setLabel("bottom", "Time (s)", **self.styles) # Add grid self.vdc_time.showGrid(x=True, y=True) # Add Range self.vdc_time.setXRange(0, 100) self.vdc_time.setYRange(0, 15000) # Detection Visualization ######################### self.x_dtec = [i * 0.5 for i in range(200)] # 100 time points self.y_dtec = [0.0] * 200 # 200 data points, all initialized to 0.0 self.y_dtec[:] = [np.nan] * len(self.y_vdc) pen_dtec = pg.mkPen(color=(255, 0, 0), width=3) self.data_line_dtec = self.detection_rate_viz.plot(self.x_dtec, self.y_dtec, pen=pen_dtec) # Add Axis Labels self.detection_rate_viz.setLabel("left", "Detection rate (%)", **self.styles) self.detection_rate_viz.setLabel("bottom", "Time (s)", **self.styles) # Add grid self.detection_rate_viz.showGrid(x=True, y=True) self.detection_rate_viz.plotItem.setMouseEnabled(x=False) # Only allow zoom in Y-axis # Add Range self.detection_rate_viz.setXRange(0, 100) self.detection_rate_viz.setYRange(0, 100) # detector heatmep ##################### self.scatter = pg.ScatterPlotItem( size=self.hitmap_plot_size.value(), brush='black') self.detector_circle = QtWidgets.QGraphicsEllipseItem(-40, -40, 80, 80) # x, y, width, height self.detector_circle.setPen(pg.mkPen(color=(255, 0, 0), width=2)) self.detector_heatmap.addItem(self.detector_circle) self.detector_heatmap.setLabel("left", "X_det", units='mm', **self.styles) self.detector_heatmap.setLabel("bottom", "Y_det", units='mm', **self.styles) # Histogram ######################### # Add Axis Labels self.histogram.plotItem.setMouseEnabled(y=False) # Only allow zoom in X-axis self.histogram.setLabel("left", "Event Counts", **self.styles) self.histogram.setLogMode(y=True) if self.conf["visualization"] == "tof": self.histogram.setLabel("bottom", "Time", units='ns', **self.styles) elif self.conf["visualization"] == "mc": self.histogram.setLabel("bottom", "m/c", units='Da', **self.styles) self.visualization_window = Visualization # Assign the attribute when setting up the UI self.reset_heatmap_v.clicked.connect(self.reset_heatmap) self.histogram.addLegend(offset=(-10, 10)) self.original_button_style = self.detection_rate_range_switch.styleSheet() self.detection_rate_range_switch.clicked.connect(self.detection_rate_range) self.spectrum_switch.clicked.connect(self.spectrum_switch_mc_tof) self.spectrum_last_events_switch.clicked.connect(self.spectrum_last_events) self.num_last_events.editingFinished.connect(self.parameters_changes) self.max_mc.editingFinished.connect(self.parameters_changes) self.max_tof.editingFinished.connect(self.parameters_changes) self.num_event_mc_tof = int(self.num_last_events.text()) self.heatmap_fdm_switch.clicked.connect(self.heatmap_fdm_switch_change) self.num_event_mc_tof = int(self.num_last_events.text()) self.max_mc_val = int(self.max_mc.text()) self.max_tof_val = int(self.max_tof.text()) self.index_hist_tof = np.where(self.bins_tof == self.max_tof_val)[0][0] self.index_hist_mc = np.where(self.bins_mc == self.max_mc_val)[0][0] self.dc_hold.clicked.connect(self.dc_hold_clicked) self.hitmap_count.setReadOnly(True) self.voltage.setReadOnly(True) self.detection_rate.setReadOnly(True) self.hit_displayed.editingFinished.connect(self.parameters_changes) # Create a QTimer to hide the warning message after 8 seconds self.timer = QtCore.QTimer() self.timer.timeout.connect(self.hideMessage) self.hitmap_plot_size.setValue(1.0) self.hitmap_plot_size.setSingleStep(0.1) self.hitmap_plot_size.setDecimals(1)
[docs] def retranslateUi(self, Visualization): """ Set the text of the widgets Args: Visualization: The main window Return: None """ _translate = QtCore.QCoreApplication.translate ### # Visualization.setWindowTitle(_translate("Visualization", "Form")) Visualization.setWindowTitle(_translate("Visualization", "PyCCAPT Visualization")) Visualization.setWindowIcon(QtGui.QIcon('./files/logo.png')) ### self.label_200.setText(_translate("Visualization", "Voltage")) self.voltage.setText(_translate("Visualization", "0")) self.dc_hold.setText(_translate("Visualization", "Hold DC Voltage")) self.label_201.setText(_translate("Visualization", "Detection Rate")) self.detection_rate.setText(_translate("Visualization", "0")) self.detection_rate_range_switch.setText(_translate("Visualization", "Short Range")) self.label_206.setText(_translate("Visualization", "Detector")) self.hitmap_count.setText(_translate("Visualization", "0")) self.reset_heatmap_v.setText(_translate("Visualization", "Reset")) self.hit_displayed.setText(_translate("Visualization", "2000")) self.heatmap_fdm_switch.setText(_translate("Visualization", "Hitmap/FDM")) self.label_207.setText(_translate("Visualization", "Spectrum")) self.spectrum_switch.setText(_translate("Visualization", "mc/tof")) self.spectrum_last_events_switch.setText(_translate("Visualization", "Last Events")) self.num_last_events.setText(_translate("Visualization", "10000")) self.label_208.setText(_translate("Visualization", "Max mc (Da)")) self.max_mc.setText(_translate("Visualization", "400")) self.label_209.setText(_translate("Visualization", "Max tof (ns)")) self.max_tof.setText(_translate("Visualization", "5000")) self.Error.setText(_translate("Visualization", "<html><head/><body><p><br/></p></body></html>"))
[docs] def dc_hold_clicked(self): """ Hold the DC voltage Args: None Return: None """ if self.variables.start_flag or self.variables.last_screen_shot: if not self.variables.vdc_hold: self.variables.vdc_hold = True self.dc_hold.setStyleSheet("QPushButton{\n" "background: rgb(0, 255, 26)\n" "}") elif self.variables.vdc_hold: self.variables.vdc_hold = False self.dc_hold.setStyleSheet(self.original_button_style)
[docs] def heatmap_fdm_switch_change(self): """ Change the heatmap type Args: None Return: None """ if self.heatmap_fdm_switch_flag == 'heatmap': self.heatmap_fdm_switch_flag = 'fdm' elif self.heatmap_fdm_switch_flag == 'fdm': self.heatmap_fdm_switch_flag = 'heatmap'
[docs] def reset_heatmap(self): """ Reset the heatmap Args: None Return: None """ # with self.variables.lock_setup_parameters: if not self.variables.reset_heatmap: self.variables.reset_heatmap = True
[docs] def detection_rate_range(self): """ Change the time range of the detection rate Args: None Return: None """ self.change_detection_rate_range = not self.change_detection_rate_range if self.change_detection_rate_range: self.detection_rate_range_switch.setStyleSheet("QPushButton{\n" "background: rgb(0, 255, 26)\n" "}") else: self.detection_rate_range_switch.setStyleSheet(self.original_button_style)
[docs] def update_graphs_helper(self, ): """ Update the graphs Args: None Return: None """ if self.index_plot_start == 0: self.num_hit_display = int(float(self.hit_displayed.text())) self.start_main_exp = time.time() self.start_time = time.time() self.start_time_metadata = time.time() self.index_plot_start += 1 self.hitmap_count.setText(str(0)) self.variables.elapsed_time = time.time() - self.start_time # with self.variables.lock_statistics: if self.index_wait_on_plot_start <= 16: if self.index_wait_on_plot_start == 0: self.counter_source = self.variables.counter_source self.index_wait_on_plot_start += 1 # V_dc and V_p current_voltage = self.variables.specimen_voltage_plot if self.index_plot < len(self.y_vdc): self.y_vdc[self.index_plot] = int(current_voltage) # Add a new value. else: x_vdc_last = self.x_vdc[-1] self.x_vdc.append(x_vdc_last + 0.5) # Add a new value 1 higher than the last. self.y_vdc.append(int(current_voltage)) # set the value of the voltage with two decimal places self.voltage.setText(str("{:.2f}".format(current_voltage))) # Set the maximum number of data points to display max_display_points = 200 # Downsample the data if needed if len(self.x_vdc) > max_display_points: step = len(self.x_vdc) // max_display_points x_vdc_downsampled = self.x_vdc[::step] y_vdc_downsampled = self.y_vdc[::step] self.data_line_vdc.setData(x_vdc_downsampled, y_vdc_downsampled) else: self.data_line_vdc.setData(self.x_vdc, self.y_vdc) # Detection Rate Visualization # with self.variables.lock_statistics: current_detection_rate = self.variables.detection_rate_current_plot if self.index_plot < len(self.y_dtec): self.y_dtec[self.index_plot] = current_detection_rate # Add a new value. else: # self.x_dtec = self.x_dtec[1:] # Remove the first element. x_dtec_last = self.x_dtec[-1] self.x_dtec.append(x_dtec_last + 0.5) # Add a new value 1 higher than the last. self.y_dtec.append(current_detection_rate) self.detection_rate.setText(str("{:.2f}".format(current_detection_rate))) # self.data_line_dtec.setData(self.x_dtec, self.y_dtec) # Set the maximum number of data points to display max_display_points = 200 # Downsample the data if needed if len(self.x_dtec) > max_display_points and not self.change_detection_rate_range: step = len(self.x_dtec) // max_display_points x_dtec_downsampled = self.x_dtec[::step] y_dtec_downsampled = self.y_dtec[::step] self.data_line_dtec.setData(x_dtec_downsampled, y_dtec_downsampled) elif len(self.x_dtec) > max_display_points and self.change_detection_rate_range: x_dtec_downsampled = self.x_dtec[-max_display_points:] y_dtec_downsampled = self.y_dtec[-max_display_points:] self.data_line_dtec.setData(x_dtec_downsampled, y_dtec_downsampled) else: self.data_line_dtec.setData(self.x_dtec, self.y_dtec) # Increase the index # with self.variables.lock_statistics: self.index_plot += 1 # mass spectrum if self.counter_source == 'TDC' and self.variables.total_ions > 0 and \ self.index_wait_on_plot_start > 16: xx = np.array([]) yy = np.array([]) tt = np.array([]) main_v_dc_dld = np.array([]) while not self.x_plot.empty() and not self.y_plot.empty() and not self.t_plot.empty() and \ not self.main_v_dc_plot.empty(): data = self.x_plot.get() xx = np.append(xx, data) data = self.y_plot.get() yy = np.append(yy, data) data = self.t_plot.get() tt = np.append(tt, data) data = self.main_v_dc_plot.get() main_v_dc_dld = np.append(main_v_dc_dld, data) # self.length_events += len(self.tt) self.length_events += len(tt) if len(self.last_100_thousand_v) == 0: self.last_100_thousand_det_x_heatmap = xx self.last_100_thousand_det_y_heatmap = yy mask_t = tt < self.conf["max_tof"] self.last_100_thousand_v = main_v_dc_dld[mask_t] self.last_100_thousand_det_x = xx[mask_t] self.last_100_thousand_det_y = yy[mask_t] self.last_100_thousand_t = tt[mask_t] else: self.last_100_thousand_det_x_heatmap = np.concatenate((self.last_100_thousand_det_x_heatmap, xx)) self.last_100_thousand_det_y_heatmap = np.concatenate((self.last_100_thousand_det_y_heatmap, yy)) mask_t = tt < self.conf["max_tof"] self.last_100_thousand_v = np.concatenate((self.last_100_thousand_v, main_v_dc_dld[mask_t])) self.last_100_thousand_det_x = np.concatenate((self.last_100_thousand_det_x, xx[mask_t])) self.last_100_thousand_det_y = np.concatenate((self.last_100_thousand_det_y, yy[mask_t])) self.last_100_thousand_t = np.concatenate((self.last_100_thousand_t, tt[mask_t])) if len(self.last_100_thousand_v) > 100000: self.last_100_thousand_v = self.last_100_thousand_v[-100000:] self.last_100_thousand_det_x = self.last_100_thousand_det_x[-100000:] self.last_100_thousand_det_x_heatmap = self.last_100_thousand_det_x_heatmap[-100000:] self.last_100_thousand_det_y = self.last_100_thousand_det_y[-100000:] self.last_100_thousand_det_y_heatmap = self.last_100_thousand_det_y_heatmap[-100000:] self.last_100_thousand_t = self.last_100_thousand_t[-100000:] try: if self.variables.pulse_mode == 'Voltage': t_0 = self.conf["t_0_voltage"] elif self.variables.pulse_mode == 'Laser' or self.variables.pulse_mode == 'VoltageLaser': t_0 = self.conf["t_0_laser"] if self.mc_tof_last_events_flag and self.conf["visualization"] == "tof": tt_last_events = self.last_100_thousand_t[-self.num_event_mc_tof:] hist_tof_last_events, _ = np.histogram(tt_last_events, bins=self.bins_tof) elif self.mc_tof_last_events_flag and self.conf["visualization"] == "mc": t_last_events = self.last_100_thousand_t[-self.num_event_mc_tof:] main_v_dc_dld_last_events = self.last_100_thousand_v[-self.num_event_mc_tof:] x_last_events = self.last_100_thousand_det_x[-self.num_event_mc_tof:] y_last_events = self.last_100_thousand_det_y[-self.num_event_mc_tof:] mc_last_events = tof2mc_simple.tof_2_mc(t_last_events, t_0, main_v_dc_dld_last_events, x_last_events, y_last_events, flightPathLength=self.conf["flight_path_length"]) hist_mc_last_events, _ = np.histogram(mc_last_events, bins=self.bins_mc) # hist_tof, _ = np.histogram(tt_max_lenght, bins=self.bins_tof) # self.hist_tof = hist_tof hist_tof, _ = np.histogram(tt[mask_t], bins=self.bins_tof) self.hist_tof += hist_tof # mc = tof2mc_simple.tof_2_mc(self.last_100_thousand_t, self.conf["t_0"], # self.last_100_thousand_v, # self.last_100_thousand_det_x, # self.last_100_thousand_det_y, # flightPathLength=self.conf["flight_path_length"]) # hist_mc, _ = np.histogram(mc, bins=self.bins_mc) # self.hist_mc = hist_mc mc = tof2mc_simple.tof_2_mc(tt[mask_t], t_0, main_v_dc_dld[mask_t], xx[mask_t], yy[mask_t], flightPathLength=self.conf["flight_path_length"]) hist_mc, _ = np.histogram(mc, bins=self.bins_mc) self.hist_mc += hist_mc self.histogram.clear() if self.conf["visualization"] == "tof" and not self.mc_tof_last_events_flag: hist = np.copy(self.hist_tof[:self.index_hist_tof]) hist[hist == 0] = 1 # Avoid log(0) error bins = self.bins_tof[:self.index_hist_tof + 1] self.histogram.plot(bins, hist, stepMode="center", fillLevel=0, fillOutline=True, brush='black', name="num events: %s" % self.length_events) elif self.conf["visualization"] == "mc" and not self.mc_tof_last_events_flag: hist = np.copy(self.hist_mc[:self.index_hist_mc]) hist[hist == 0] = 1 # Avoid log(0) error bins = self.bins_mc[:self.index_hist_mc + 1] self.histogram.plot(bins, hist, stepMode="center", fillLevel=0, fillOutline=True, brush='black', name="num events: %s" % self.length_events) elif self.conf["visualization"] == "tof" and self.mc_tof_last_events_flag: # remobe the bins bigger than the max_tof hist = np.copy(hist_tof_last_events[:self.index_hist_tof]) hist[hist == 0] = 1 # Avoid log(0) error bins = self.bins_tof[:self.index_hist_tof + 1] self.histogram.plot(bins, hist, stepMode="center", fillLevel=0, fillOutline=True, brush='black', name="num events: %s" % self.length_events) elif self.conf["visualization"] == "mc" and self.mc_tof_last_events_flag: # remobe the bins bigger than the max_mc hist = np.copy(hist_mc_last_events[:self.index_hist_mc]) hist[hist == 0] = 1 # Avoid log(0) error bins = self.bins_mc[:self.index_hist_mc + 1] self.histogram.plot(bins, hist, stepMode="center", fillLevel=0, fillOutline=True, brush='black', name="num events: %s" % self.length_events) except Exception as e: print( f"{initialize_devices.bcolors.FAIL}Error: Cannot plot Histogram correctly{initialize_devices.bcolors.ENDC}") print(e) # Visualization # try: # calculate the fdm for the current data hist, xedges, yedges = np.histogram2d(xx * 10, yy * 10, bins=self.bins_detector, range=self.range) self.hist_fdm += np.log10(hist + 1) # Avoid log(0) error # self.hist_fdm += hist if self.heatmap_fdm_switch_flag == 'heatmap': if self.variables.reset_heatmap: self.variables.reset_heatmap = False self.last_100_thousand_det_x_heatmap = np.array([]) self.last_100_thousand_det_y_heatmap = np.array([]) x_last_events = self.last_100_thousand_det_x_heatmap[:] y_last_events = self.last_100_thousand_det_y_heatmap[:] # adding points to the scatter plot self.scatter.setSize(self.hitmap_plot_size.value()) x = x_last_events * 10 y = y_last_events * 10 x = x[-self.num_hit_display:] y = y[-self.num_hit_display:] self.hitmap_count.setText(str(len(x))) # number of points displayed self.scatter.clear() self.scatter.setData(x=x, y=y) # add item to plot window # adding scatter plot item to the plot window self.detector_heatmap.clear() self.detector_heatmap.addItem(self.scatter) self.detector_heatmap.addItem(self.detector_circle) elif self.heatmap_fdm_switch_flag == 'fdm': # plot fdm which is 2d hsogram of det_x and det_y # Create a 2D histogram if self.mc_tof_last_events_flag: x_last_events = self.last_100_thousand_det_x_heatmap[-self.num_event_mc_tof:] y_last_events = self.last_100_thousand_det_y_heatmap[-self.num_event_mc_tof:] hist_fdm_last_events, xedges, yedges = np.histogram2d(x_last_events * 10, y_last_events * 10, bins=self.bins_detector, range=self.range) hist_fdm_last_events = np.log10(hist_fdm_last_events + 1) if self.mc_tof_last_events_flag: hist_fdm_tmp = np.copy(hist_fdm_last_events) else: hist_fdm_tmp = np.copy(self.hist_fdm) img = pg.ImageItem() img.setImage(hist_fdm_tmp) # Transpose if needed because pg.ImageItem assumes (row, col) format # set the length of histogram self.hitmap_count.setText(str(self.length_events)) # number of points displayed img.setRect(QtCore.QRectF(xedges[0], yedges[0], xedges[-1] - xedges[0], yedges[-1] - yedges[0])) # Apply a color map to the histogram # Load a preset color map (e.g., 'grey', 'thermal', 'flame', viridis, etc.) lut = pg.colormap.get('viridis').getLookupTable(start=0.0, stop=1.0, nPts=256) img.setLookupTable(lut) # add item to plot window # adding scatter plot item to the plot window self.detector_heatmap.clear() self.detector_heatmap.addItem(img) # Adjust the aspect ratio to match the data aspect ratio self.detector_heatmap.getViewBox().setAspectLocked(True)
[docs] def update_graphs(self, ): """ Update the graphs Args: None Return: None """ if self.variables.plot_clear_flag: self.x_vdc = [i * 0.5 for i in range(200)] # 100 time points self.y_vdc = [0.0] * 200 # 200 data points, all initialized to 0.0 self.y_vdc[:] = [np.nan] * len(self.y_vdc) self.vdc_time.clear() pen_vdc = pg.mkPen(color=(255, 0, 0), width=3) self.data_line_vdc = self.vdc_time.plot(self.x_vdc, self.y_vdc, pen=pen_vdc) self.x_dtec = [i * 0.5 for i in range(200)] # 100 time points self.y_dtec = [0.0] * 200 # 200 data points, all initialized to 0.0 self.y_dtec[:] = [np.nan] * len(self.y_vdc) self.detection_rate_viz.clear() pen_dtec = pg.mkPen(color=(255, 0, 0), width=3) self.data_line_dtec = self.detection_rate_viz.plot(self.x_dtec, self.y_dtec, pen=pen_dtec) self.histogram.clear() self.detector_heatmap.clear() self.detector_heatmap.addItem(self.detector_circle) self.variables.plot_clear_flag = False self.index_plot = 0 self.index_plot_start = 0 self.index_plot_save = 0 self.start_time_metadata = 0 self.variables.detection_rate_current_plot = 0 self.last_100_thousand_det_x_heatmap = np.array([]) self.last_100_thousand_det_x = np.array([]) self.last_100_thousand_det_y_heatmap = np.array([]) self.last_100_thousand_det_y = np.array([]) self.last_100_thousand_t = np.array([]) self.last_100_thousand_v = np.array([]) self.length_events = 0 self.hist_fdm, xedges, yedges = np.histogram2d([], [], bins=self.bins_detector, range=self.range) self.hist_mc = np.zeros(len(self.bins_mc) - 1) self.hist_tof = np.zeros(len(self.bins_tof) - 1) if self.index_auto_scale_graph == 30: self.vdc_time.enableAutoRange(axis='x') self.histogram.enableAutoRange(axis='y') self.detection_rate_viz.enableAutoRange(axis='x') self.detection_rate_viz.enableAutoRange(axis='y') self.detector_heatmap.enableAutoRange(axis='x') self.detector_heatmap.enableAutoRange(axis='y') self.index_auto_scale_graph = 0 # with self.variables.lock_statistics and self.variables.lock_setup_parameters: if self.variables.start_flag and self.variables.flag_visualization_start: self.index_auto_scale_graph += 1 self.update_graphs_helper() # save plots to the file if time.time() - self.start_time_metadata >= self.variables.save_meta_interval_visualization: self.path_meta = self.variables.path_meta exporter = pg.exporters.ImageExporter(self.vdc_time.plotItem) exporter.params['width'] = 1000 # Set the width of the image exporter.params['height'] = 800 # Set the height of the image exporter.export(self.variables.path_meta + '/visualization_v_dc_p_%s.png' % self.index_plot_save) exporter = pg.exporters.ImageExporter(self.detection_rate_viz.plotItem) exporter.params['width'] = 1000 # Set the width of the image exporter.params['height'] = 800 # Set the height of the image exporter.export(self.path_meta + '/visualization_detection_rate_%s.png' % self.index_plot_save) exporter = pg.exporters.ImageExporter(self.detector_heatmap.plotItem) exporter.params['width'] = 1000 # Set the width of the image exporter.params['height'] = 800 # Set the height of the image exporter.export(self.path_meta + '/visualization_detector_%s.png' % self.index_plot_save) exporter = pg.exporters.ImageExporter(self.histogram.plotItem) exporter.params['width'] = 1000 # Set the width of the image exporter.params['height'] = 800 # Set the height of the image exporter.export(self.path_meta + '/visualization_mc_tof_%s.png' % self.index_plot_save) screenshot = QtWidgets.QApplication.primaryScreen().grabWindow(self.visualization_window.winId()) screenshot.save(self.path_meta + '/visualization_screenshot_%s.png' % self.index_plot_save, 'png') self.start_time_metadata = time.time() # Increase the index self.index_plot_save += 1 elif self.variables.last_screen_shot: self.path_meta = self.variables.path_meta if self.variables.vdc_hold: self.dc_hold.click() if self.heatmap_fdm_switch_flag == 'heatmap': self.heatmap_fdm_switch.click() if self.mc_tof_last_events_flag: self.spectrum_last_events_switch.click() if self.change_detection_rate_range: self.detection_rate_range_switch.click() if self.conf["visualization"] == "tof": self.spectrum_switch.click() self.update_graphs_helper() exporter = pg.exporters.ImageExporter(self.vdc_time.plotItem) exporter.params['width'] = 1000 # Set the width of the image exporter.params['height'] = 800 # Set the height of the image exporter.export(self.path_meta + '/visualization_v_dc_p_final.png') exporter = pg.exporters.ImageExporter(self.detection_rate_viz.plotItem) exporter.params['width'] = 1000 # Set the width of the image exporter.params['height'] = 800 # Set the height of the image exporter.export(self.path_meta + '/visualization_detection_rate_final.png') exporter = pg.exporters.ImageExporter(self.detector_heatmap.plotItem) exporter.params['width'] = 1000 # Set the width of the image exporter.params['height'] = 800 # Set the height of the image exporter.export(self.path_meta + '/visualization_detector_final.png') exporter = pg.exporters.ImageExporter(self.histogram.plotItem) exporter.params['width'] = 1000 # Set the width of the image exporter.params['height'] = 800 # Set the height of the image exporter.export(self.path_meta + '/visualization_mc_tof_final.png') screenshot = QtWidgets.QApplication.primaryScreen().grabWindow(self.visualization_window.winId()) screenshot.save(self.path_meta + '/visualization_screenshot_final.png', 'png') self.variables.last_screen_shot = False
[docs] def spectrum_switch_mc_tof(self): """ Switch between mass spectrum and time of flight spectrum Args: None Return: None """ if self.conf["visualization"] == "tof": self.conf["visualization"] = "mc" self.histogram.setLabel("bottom", "m/c", units='Da', **self.styles) elif self.conf["visualization"] == "mc": self.conf["visualization"] = "tof" self.histogram.setLabel("bottom", "Time", units='ns', **self.styles)
[docs] def spectrum_last_events(self): """ Display the last events in the mass spectrum Args: None Return: None """ self.mc_tof_last_events_flag = not self.mc_tof_last_events_flag if self.mc_tof_last_events_flag: self.spectrum_last_events_switch.setStyleSheet("QPushButton{\n" "background: rgb(0, 255, 26)\n" "}") else: self.spectrum_last_events_switch.setStyleSheet(self.original_button_style)
[docs] def parameters_changes(self): """ Change the parameters for the mass spectrum Args: None Return: None """ if self.num_last_events.text().isdigit(): num_last_event_tmp = int(self.num_last_events.text()) if num_last_event_tmp > 100000: self.num_last_events_val = 100000 self.num_last_events.setText("100000") else: self.num_event_mc_tof = num_last_event_tmp if self.max_mc.text().isdigit(): max_mc_tmp = int(self.max_mc.text()) if max_mc_tmp > self.conf["max_mass"]: self.max_mc_val = self.conf["max_mass"] self.max_mc.setText(str(self.conf["max_mass"])) self.index_hist_mc = np.where(self.bins_mc == self.max_mc_val)[0][0] else: self.max_mc_val = max_mc_tmp self.index_hist_mc = np.where(self.bins_mc == self.max_mc_val)[0][0] if self.max_tof.text().isdigit(): max_tof_tmp = int(self.max_tof.text()) if max_tof_tmp > self.conf["max_tof"]: self.max_tof_val = self.conf["max_tof"] self.max_tof.setText(str(self.conf["max_tof"])) self.index_hist_tof = np.where(self.bins_tof == self.max_tof_val)[0][0] else: self.max_tof_val = max_tof_tmp self.index_hist_tof = np.where(self.bins_tof == self.max_tof_val)[0][0] if self.hit_displayed.text().isdigit(): if int(float(self.hit_displayed.text())) > 100000: self.error_message("Maximum possible number is 100000") _translate = QtCore.QCoreApplication.translate self.hit_displayed.setText(_translate("PyCCAPT", "100000")) else: self.num_hit_display = int(float(self.hit_displayed.text()))
[docs] def error_message(self, message): """ Display an error message and start a timer to hide it after 8 seconds Args: message (str): Error message to display Return: None """ _translate = QtCore.QCoreApplication.translate self.Error.setText(_translate("OXCART", "<html><head/><body><p><span style=\" color:#ff0000;\">" + message + "</span></p></body></html>")) self.timer.start(8000)
[docs] def hideMessage(self, ): """ Hide the message and stop the timer Args: None Return: None """ # Hide the message and stop the timer _translate = QtCore.QCoreApplication.translate self.Error.setText(_translate("OXCART", "<html><head/><body><p><span style=\" " "color:#ff0000;\"></span></p></body></html>")) self.timer.stop()
[docs] def stop(self): """ Stop any background activity Args: None Return: None """ # Add any additional cleanup code here pass
[docs] def efficient_histogram(viz, bin_size): bins = np.arange(np.min(viz), np.max(viz) + bin_size, bin_size) hist, edges = np.histogram(viz, bins=bins) hist[hist == 0] = 1 # Avoid log(0) return hist, edges
[docs] class VisualizationWindow(QtWidgets.QWidget): """ Widget for the Visualization window. """ closed = QtCore.pyqtSignal() # Define a custom closed signal def __init__(self, variables, gui_visualization, visualization_close_event, visualization_win_front, *args, **kwargs): """ Constructor for the VisualizationWindow class. Args: variables: Shared variables. gui_visualization: Instance of the Visualization. visualization_close_event: Event for the Visualization window closed. visualization_win_front: Event for the Visualization window front. *args: Additional positional arguments. **kwargs: Additional keyword arguments. Return: None """ super().__init__(*args, **kwargs) self.gui_visualization = gui_visualization self.variables = variables self.visualization_win_front = visualization_win_front self.visualization_close_event = visualization_close_event self.show() self.showMinimized() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.check_if_should) self.timer.start(500) # Check every 1000 milliseconds (1 second)
[docs] def closeEvent(self, event): """ Close event for the window. Args: event: Close event. Return: None """ event.ignore() self.showMinimized() self.visualization_close_event.set()
[docs] def check_if_should(self): """ Check if the window should be shown. Args: None Return: None """ if self.visualization_win_front.is_set(): self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowType.WindowStaysOnTopHint) self.show() self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowType.WindowStaysOnTopHint) self.visualization_win_front.clear() # Reset the flag if self.variables.flag_visualization_win_show: self.show() self.variables.flag_visualization_win_show = False
[docs] def setWindowStyleFusion(self): # Set the Fusion style QtWidgets.QApplication.setStyle("Fusion")
[docs] def run_visualization_window(variables, conf, visualization_closed_event, visualization_win_front, x_plot, y_plot, t_plot, main_v_dc_plot): """ Run the Cameras window in a separate process. Args: variables: Shared variables. conf: Configuration dictionary. visualization_closed_event: Event for the Visualization window closed. visualization_win_front: Event for the Visualization window front. x_plot: x plot y_plot: y plot t_plot: t plot main_v_dc_plot: main v dc plot Return: None """ app = QtWidgets.QApplication(sys.argv) # <-- Create a new QApplication instance app.setStyle('Fusion') gui_visualization = Ui_Visualization(variables, conf, x_plot, y_plot, t_plot, main_v_dc_plot) Cameras_alignment = VisualizationWindow(variables, gui_visualization, visualization_closed_event, visualization_win_front, flags=QtCore.Qt.WindowType.Tool) gui_visualization.setupUi(Cameras_alignment) sys.exit(app.exec()) # <-- Start the event loop for this QApplication instance
if __name__ == "__main__": try: conf, _ = runtime.load_project_config() except Exception as exc: print('Can not load the configuration file') print(exc) sys.exit() shared = runtime.create_shared_context(conf) app = QtWidgets.QApplication(sys.argv) app.setStyle('Fusion') Visualization = QtWidgets.QWidget() ui = Ui_Visualization( shared.variables, conf, shared.x_plot, shared.y_plot, shared.t_plot, shared.main_v_dc_plot, ) ui.setupUi(Visualization) Visualization.show() sys.exit(app.exec())