From 1e04ab5b152dfd7172e08e64d136e3849c09c482 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Fri, 17 May 2024 05:28:25 -0700 Subject: [PATCH 01/23] Made a bar chart that works with a single pv --- backend.py | 10 ++- bar_chart_test.py | 166 ++++++++++++++++++++++++++++++++++++++++++++++ display_linac.py | 25 ++++--- fault.py | 41 +++++++----- testBarChart.ui | 28 ++++++++ utils.py | 2 +- 6 files changed, 244 insertions(+), 28 deletions(-) create mode 100644 bar_chart_test.py create mode 100644 testBarChart.ui diff --git a/backend.py b/backend.py index c0373cc..5c0596f 100644 --- a/backend.py +++ b/backend.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timedelta from time import sleep from display_linac import DISPLAY_MACHINE, DisplayCryomodule @@ -14,7 +14,13 @@ for cryomoduleName in ALL_CRYOMODULES: cryomodule: DisplayCryomodule = DISPLAY_MACHINE.cryomodules[cryomoduleName] for cavity in cryomodule.cavities.values(): - cavity.run_through_faults() + # EX: cavity = L0B CM01 Cavity 2 + # EX: cryomodule.cavities.values() = dict of 8 display_linac.DisplayCavity object + ########### cavity.run_through_faults() ####PUT THIS BACK IN + if (cavity.pv_prefix == "ACCL:L1B:H220:"): + print(cavity.pv_prefix) + cavity.get_fault_counts(datetime.now() - timedelta(minutes=1), datetime.now()) + # print("Start: ", datetime.now() - timedelta(minutes=1), "End: ", datetime.now()) if DEBUG: delta = (datetime.now() - start).total_seconds() sleep(BACKEND_SLEEP_TIME - delta if delta < BACKEND_SLEEP_TIME else 0) diff --git a/bar_chart_test.py b/bar_chart_test.py new file mode 100644 index 0000000..cbe8ed3 --- /dev/null +++ b/bar_chart_test.py @@ -0,0 +1,166 @@ +# from PyQt5.QtWidgets import QApplication, QMainWindow +# import sys +# from PyQt.QtChart import QChart +import pyqtgraph as pg +from PyQt5.QtWidgets import QVBoxLayout +from datetime import datetime +from pydm import Display + +from lcls_tools.common.data_analysis.archiver import ( + get_values_over_time_range, +) + +# from lcls_tools.superconducting.sc_linac_utils import ALL_CRYOMODULES + +''' +print(ALL_CRYOMODULES) +for cm in ALL_CRYOMODULES: + print("cm: ", cm) + cm_obj: DisplayCryomodule = DISPLAY_CRYOMODULES[cm] + for cav in cm_obj.cavities.values(): + initialTime = datetime.now() + fault_count_dict = cav.get_fault_counts(starttime=datetime.now() - + timedelta(minutes=1), + endtime=datetime.now()) + print(cav, datetime.now() - initialTime) +''' + + +class BarChart(Display): + def __init__(self, parent=None, args=None): + super(BarChart, self).__init__(parent=parent, args=args, + ui_filename="testBarChart.ui") + + vertLayout_Form = self.ui.findChild(QVBoxLayout) + + # Read in archive data + # pv_strings = ["PPS:SYSW:1:BeamReadyA", "ACCL:L3B:1910:PZT:FBSTATSUM", + # "ACCL:L2B:1310:SSA_LTCH", "ACCL:L2B:1310:CRYO_LTCH"] + + pv_string = "ACCL:L3B:1910:PZT:FBSTATSUM" + pv_list = [pv_string] + + start = datetime(2024, 5, 17, 4, 29, 35, 24214) + end = datetime(2024, 5, 17, 4, 30, 35, 24214) + + # get_values_over_time_range(...) -> Dict[str, ArchiveDataHandler] + result = get_values_over_time_range(pv_list, start_time=start, + end_time=end) + + data_handler: ArchiveDataHandler = result[pv_string] + + fault_count = 0 + for archiver_value in data_handler.value_list: \ + # Per spreadsheet, PZT:FBSTATSUM faulted if value equal to 1 + if archiver_value.val == 1: + fault_count += 1 + print(pv_string, "\tTotal fault counts: ", fault_count) + + # Hard coding interpretting the archive data result + yaxis_fault = [] + yaxis_fault.append(fault_count) + + # Make plot window and it to the vert layout + plot_window = pg.plot() + vertLayout_Form.addWidget(plot_window) + + # Create list for horizontal and vertical axis + xlabel = ['PZO'] + xval = [0] + # y1 = [5, 10, 1, 0] + + # Create list of list of tuples for tick marks in the form of + # [[(0,'HWI'), (1,'AOT'), ...]] + ticks = [] + for i, xlabel_string in enumerate(xlabel): + ticks.append((xval[i], xlabel_string)) + ticks = [ticks] + + # Create pyqt5graph bar graph item with green bars + bargraph = pg.BarGraphItem(x=xval, height=yaxis_fault, width=0.6, brush='g') + + ax = plot_window.getAxis('bottom') + ax.setTicks(ticks) + plot_window.showGrid(x=False, y=True, alpha=0.6) + + # Add bargraph to plot window + plot_window.addItem(bargraph) + + ''' + # Hard coding interpretting the archive data result + yaxis_fault = [] + for pv_string, value_list in archive_values_dict.items(): + if pv_string == "PPS:SYSW:1:BeamReadyA": + # fault status isOkay if value = 1 + fault_counter = 0 + for value in value_list: + if value != 1: + fault_counter += 1 + yaxis_fault.append(fault_counter) + print(pv_string, value_list, fault_counter) + + elif pv_string == "ACCL:L3B:1910:PZT:FBSTATSUM": + # fault status isOkay if value = 1 + fault_counter = 0 + for value in value_list: + if value != 1: + fault_counter += 1 + yaxis_fault.append(fault_counter) + print(pv_string, value_list, fault_counter) + + elif pv_string == "ACCL:L2B:1310:SSA_LTCH": + # fault status isOkay if value = 0 + fault_counter = 0 + for value in value_list: + if value != 0: + fault_counter += 1 + yaxis_fault.append(fault_counter) + print(pv_string, value_list, fault_counter) + + elif pv_string == "ACCL:L2B:1310:CRYO_LTCH": + # fault status isOkay if value = 0 + fault_counter = 0 + for value in value_list: + if value != 0: + fault_counter += 1 + yaxis_fault.append(fault_counter) + print(pv_string, value_list, fault_counter) + + print(yaxis_fault) + + # Make plot window and it to the vert layout + plot_window = pg.plot() + vertLayout_Form.addWidget(plot_window) + + # Create list for horizontal and vertical axis + xlabel = ['PPS', 'PZT', 'SSP', 'CSI'] + xval = [0, 1, 2, 3] + # y1 = [5, 10, 1, 0] + + # Create list of list of tuples for tick marks in the form of + # [[(0,'HWI'), (1,'AOT'), ...]] + ticks = [] + for i, xlabel_string in enumerate(xlabel): + ticks.append((xval[i], xlabel_string)) + ticks = [ticks] + + # Create pyqt5graph bar graph item with green bars + bargraph = pg.BarGraphItem(x=xval, height=yaxis_fault, width=0.6, brush='g') + + ax = plot_window.getAxis('bottom') + ax.setTicks(ticks) + plot_window.showGrid(x=False, y=True, alpha=0.6) + + # Add bargraph to plot window + plot_window.addItem(bargraph) + + ''' + ''' + pv_list = Tester().pvList # ["BEND:LTUH:220:BDES", "BEND:LTUH:280:BDES"] + start_time = datetime(2020, 10, 1, 10, 7, 28, 958256) # 220 + end_time = datetime(2020, 10, 14, 9, 57, 57, 230327) # 220 + result = Archiver('lcls').getValuesOverTimeRange(pvList=pv_list, + startTime=start_time, + endTime=end_time) + print(result) + ''' diff --git a/display_linac.py b/display_linac.py index 22b98e0..2d66f85 100644 --- a/display_linac.py +++ b/display_linac.py @@ -1,8 +1,8 @@ from collections import OrderedDict -from datetime import datetime -from typing import Dict +from datetime import datetime from epics import caput +from typing import Dict from fault import Fault, FaultCounter, PVInvalidError from lcls_tools.superconducting.sc_linac import Cavity, Cryomodule, Machine, SSA @@ -29,9 +29,9 @@ def __init__(self, message): class DisplayCryomodule(Cryomodule): def __init__( - self, - cryo_name, - linac_object, + self, + cryo_name, + linac_object, ): super().__init__( cryo_name=cryo_name, @@ -54,9 +54,9 @@ def pydm_macros(self): class DisplayCavity(Cavity): def __init__( - self, - cavity_num, - rack_object, + self, + cavity_num, + rack_object, ): super(DisplayCavity, self).__init__( cavity_num=cavity_num, rack_object=rack_object @@ -110,7 +110,7 @@ def create_faults(self): ) if (cm_type == "1.3" and self.cryomodule.is_harmonic_linearizer) or ( - cm_type == "3.9" and not self.cryomodule.is_harmonic_linearizer + cm_type == "3.9" and not self.cryomodule.is_harmonic_linearizer ): continue pv = prefix + suffix @@ -154,15 +154,20 @@ def create_faults(self): ) def get_fault_counts( - self, start_time: datetime, end_time: datetime + self, start_time: datetime, end_time: datetime ) -> Dict[str, FaultCounter]: result: Dict[str, FaultCounter] = {} + print("get_fault_counts in display_linac.py") for fault in self.faults.values(): result[fault.pv.pvname] = fault.get_fault_count_over_time_range( start_time=start_time, end_time=end_time ) + # result is a dictionary with key=fault pv string, value=FaultCounter(fault_count=0, ok_count=1, invalid_count=0) + # for faultPv in result: + # print(faultPv, "\t", result[faultPv]) + return result def run_through_faults(self): diff --git a/fault.py b/fault.py index 8f297c2..7b0c0d2 100644 --- a/fault.py +++ b/fault.py @@ -34,20 +34,20 @@ def __init__(self, message): class Fault: def __init__( - self, - tlc, - severity, - pv, - ok_value, - fault_value, - long_description, - short_description, - button_level, - button_command, - macros, - button_text, - button_macro, - action, + self, + tlc, + severity, + pv, + ok_value, + fault_value, + long_description, + short_description, + button_level, + button_command, + macros, + button_text, + button_macro, + action, ): self.tlc = tlc self.severity = int(severity) @@ -65,6 +65,7 @@ def __init__( self.pv: PV = PV(pv, connection_timeout=PV_TIMEOUT) def is_currently_faulted(self): + # returns "FALSE" if not faulted. aka Are you faulted? FALSE! All good here return self.is_faulted(self.pv) def is_faulted(self, obj: Union[PV, ArchiverValue]): @@ -80,10 +81,18 @@ class AlarmSeverity(DefaultIntEnum): raise PVInvalidError(self.pv.pvname) if self.ok_value is not None: + # "is not None" means it has a value. It is not a blank, no value + # ok_value = value stated in spreadsheet + # obj.value = actual reading value from pv return obj.val != self.ok_value + # Does the actual value NOT match the spreadsheet value? + # If they don't match, return TRUE + # return "FALSE" means is_okay, not faulted elif self.fault_value is not None: return obj.val == self.fault_value + # return "FALSE" means not faulted + # return "TRUE" means faulted else: print(self) @@ -99,7 +108,7 @@ def was_faulted(self, time: datetime): return self.is_faulted(archiver_value) def get_fault_count_over_time_range( - self, start_time: datetime, end_time: datetime + self, start_time: datetime, end_time: datetime ) -> FaultCounter: result = get_values_over_time_range( pv_list=[self.pv.pvname], start_time=start_time, end_time=end_time @@ -118,4 +127,6 @@ def get_fault_count_over_time_range( except PVInvalidError: counter.invalid_count += 1 + print("PV: ", self.pv.pvname, "\tCounter:", counter, counter.fault_count, counter.ok_count, + counter.invalid_count) return counter diff --git a/testBarChart.ui b/testBarChart.ui new file mode 100644 index 0000000..c23f68e --- /dev/null +++ b/testBarChart.ui @@ -0,0 +1,28 @@ + + + Form + + + + 0 + 0 + 400 + 300 + + + + Fault Counter + + + + + + Fault Counter + + + + + + + + diff --git a/utils.py b/utils.py index 0c35744..025bc1e 100644 --- a/utils.py +++ b/utils.py @@ -7,7 +7,7 @@ DESCRIPTION_SUFFIX = "CUDDESC" RF_STATUS_SUFFIX = "RFSTATE" -DEBUG = False +DEBUG = True BACKEND_SLEEP_TIME = 10 CSV_FAULTS: List[Dict] = [] From a98f495a25836945003f94c96e6e42914bacd8e0 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Fri, 17 May 2024 07:42:22 -0700 Subject: [PATCH 02/23] Can make a bar chart with more than one pv --- bar_chart_test.py | 124 +++++++++------------------------------------- 1 file changed, 24 insertions(+), 100 deletions(-) diff --git a/bar_chart_test.py b/bar_chart_test.py index cbe8ed3..f952c99 100644 --- a/bar_chart_test.py +++ b/bar_chart_test.py @@ -1,6 +1,6 @@ # from PyQt5.QtWidgets import QApplication, QMainWindow # import sys -# from PyQt.QtChart import QChart +# from PyQt.QtChart import import pyqtgraph as pg from PyQt5.QtWidgets import QVBoxLayout from datetime import datetime @@ -10,21 +10,6 @@ get_values_over_time_range, ) -# from lcls_tools.superconducting.sc_linac_utils import ALL_CRYOMODULES - -''' -print(ALL_CRYOMODULES) -for cm in ALL_CRYOMODULES: - print("cm: ", cm) - cm_obj: DisplayCryomodule = DISPLAY_CRYOMODULES[cm] - for cav in cm_obj.cavities.values(): - initialTime = datetime.now() - fault_count_dict = cav.get_fault_counts(starttime=datetime.now() - - timedelta(minutes=1), - endtime=datetime.now()) - print(cav, datetime.now() - initialTime) -''' - class BarChart(Display): def __init__(self, parent=None, args=None): @@ -37,8 +22,9 @@ def __init__(self, parent=None, args=None): # pv_strings = ["PPS:SYSW:1:BeamReadyA", "ACCL:L3B:1910:PZT:FBSTATSUM", # "ACCL:L2B:1310:SSA_LTCH", "ACCL:L2B:1310:CRYO_LTCH"] - pv_string = "ACCL:L3B:1910:PZT:FBSTATSUM" - pv_list = [pv_string] + pv_string1 = "ACCL:L3B:1910:PZT:FBSTATSUM" # PZO fault + pv_string2 = "XCOR:L3B:1685:STATMSG" # MGT fault + pv_list = [pv_string1, pv_string2] start = datetime(2024, 5, 17, 4, 29, 35, 24214) end = datetime(2024, 5, 17, 4, 30, 35, 24214) @@ -47,95 +33,34 @@ def __init__(self, parent=None, args=None): result = get_values_over_time_range(pv_list, start_time=start, end_time=end) - data_handler: ArchiveDataHandler = result[pv_string] - - fault_count = 0 - for archiver_value in data_handler.value_list: \ - # Per spreadsheet, PZT:FBSTATSUM faulted if value equal to 1 - if archiver_value.val == 1: - fault_count += 1 - print(pv_string, "\tTotal fault counts: ", fault_count) - - # Hard coding interpretting the archive data result - yaxis_fault = [] - yaxis_fault.append(fault_count) - - # Make plot window and it to the vert layout - plot_window = pg.plot() - vertLayout_Form.addWidget(plot_window) - - # Create list for horizontal and vertical axis - xlabel = ['PZO'] - xval = [0] - # y1 = [5, 10, 1, 0] - - # Create list of list of tuples for tick marks in the form of - # [[(0,'HWI'), (1,'AOT'), ...]] - ticks = [] - for i, xlabel_string in enumerate(xlabel): - ticks.append((xval[i], xlabel_string)) - ticks = [ticks] - - # Create pyqt5graph bar graph item with green bars - bargraph = pg.BarGraphItem(x=xval, height=yaxis_fault, width=0.6, brush='g') - - ax = plot_window.getAxis('bottom') - ax.setTicks(ticks) - plot_window.showGrid(x=False, y=True, alpha=0.6) - - # Add bargraph to plot window - plot_window.addItem(bargraph) - - ''' # Hard coding interpretting the archive data result yaxis_fault = [] - for pv_string, value_list in archive_values_dict.items(): - if pv_string == "PPS:SYSW:1:BeamReadyA": - # fault status isOkay if value = 1 - fault_counter = 0 - for value in value_list: - if value != 1: - fault_counter += 1 - yaxis_fault.append(fault_counter) - print(pv_string, value_list, fault_counter) - - elif pv_string == "ACCL:L3B:1910:PZT:FBSTATSUM": - # fault status isOkay if value = 1 - fault_counter = 0 - for value in value_list: - if value != 1: - fault_counter += 1 - yaxis_fault.append(fault_counter) - print(pv_string, value_list, fault_counter) - - elif pv_string == "ACCL:L2B:1310:SSA_LTCH": - # fault status isOkay if value = 0 - fault_counter = 0 - for value in value_list: - if value != 0: - fault_counter += 1 - yaxis_fault.append(fault_counter) - print(pv_string, value_list, fault_counter) - - elif pv_string == "ACCL:L2B:1310:CRYO_LTCH": - # fault status isOkay if value = 0 - fault_counter = 0 - for value in value_list: - if value != 0: - fault_counter += 1 - yaxis_fault.append(fault_counter) - print(pv_string, value_list, fault_counter) - - print(yaxis_fault) + for key, value in result.items(): + data_handler: ArchiveDataHandler = result[key] + + if key == pv_string1: + fault_count = 0 + for archiver_value in data_handler.value_list: + if archiver_value.val == 1: + fault_count += 1 + yaxis_fault.append(fault_count) + print(key, "\tTotal fault counts: ", fault_count) + + elif key == pv_string2: + fault_count = 0 + for archiver_value in data_handler.value_list: + if archiver_value.val == 8: + fault_count += 1 + yaxis_fault.append(fault_count) + print(key, "\tTotal fault counts: ", fault_count) # Make plot window and it to the vert layout plot_window = pg.plot() vertLayout_Form.addWidget(plot_window) # Create list for horizontal and vertical axis - xlabel = ['PPS', 'PZT', 'SSP', 'CSI'] - xval = [0, 1, 2, 3] - # y1 = [5, 10, 1, 0] + xlabel = ['PZO', 'MGT'] + xval = [0, 1] # Create list of list of tuples for tick marks in the form of # [[(0,'HWI'), (1,'AOT'), ...]] @@ -154,7 +79,6 @@ def __init__(self, parent=None, args=None): # Add bargraph to plot window plot_window.addItem(bargraph) - ''' ''' pv_list = Tester().pvList # ["BEND:LTUH:220:BDES", "BEND:LTUH:280:BDES"] start_time = datetime(2020, 10, 1, 10, 7, 28, 958256) # 220 From 0439dea75a01513df56fd106aa5ac21fb105013c Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Mon, 20 May 2024 11:23:25 -0700 Subject: [PATCH 03/23] Pushing just to be safe --- backend.py | 4 ++-- display_linac.py | 10 +++++++--- fault.py | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/backend.py b/backend.py index 5c0596f..a879414 100644 --- a/backend.py +++ b/backend.py @@ -16,9 +16,9 @@ for cavity in cryomodule.cavities.values(): # EX: cavity = L0B CM01 Cavity 2 # EX: cryomodule.cavities.values() = dict of 8 display_linac.DisplayCavity object - ########### cavity.run_through_faults() ####PUT THIS BACK IN + # TODO + ########### cavity.run_through_faults() ####PUT THIS BACK IN if (cavity.pv_prefix == "ACCL:L1B:H220:"): - print(cavity.pv_prefix) cavity.get_fault_counts(datetime.now() - timedelta(minutes=1), datetime.now()) # print("Start: ", datetime.now() - timedelta(minutes=1), "End: ", datetime.now()) if DEBUG: diff --git a/display_linac.py b/display_linac.py index 2d66f85..558d66e 100644 --- a/display_linac.py +++ b/display_linac.py @@ -4,6 +4,7 @@ from epics import caput from typing import Dict +from bar_chart_test import BarChart from fault import Fault, FaultCounter, PVInvalidError from lcls_tools.superconducting.sc_linac import Cavity, Cryomodule, Machine, SSA from utils import ( @@ -158,15 +159,18 @@ def get_fault_counts( ) -> Dict[str, FaultCounter]: result: Dict[str, FaultCounter] = {} - print("get_fault_counts in display_linac.py") for fault in self.faults.values(): result[fault.pv.pvname] = fault.get_fault_count_over_time_range( start_time=start_time, end_time=end_time ) # result is a dictionary with key=fault pv string, value=FaultCounter(fault_count=0, ok_count=1, invalid_count=0) - # for faultPv in result: - # print(faultPv, "\t", result[faultPv]) + for faultPv in result: + print(faultPv, "\t", result[faultPv], + result[faultPv].fault_count, + result[faultPv].ok_count, + result[faultPv].invalid_count) + BarChart # --------------------------------------------- return result diff --git a/fault.py b/fault.py index 7b0c0d2..728058c 100644 --- a/fault.py +++ b/fault.py @@ -127,6 +127,6 @@ def get_fault_count_over_time_range( except PVInvalidError: counter.invalid_count += 1 - print("PV: ", self.pv.pvname, "\tCounter:", counter, counter.fault_count, counter.ok_count, - counter.invalid_count) + # print("PV: ", self.pv.pvname, "\tCounter:", counter, counter.fault_count, counter.ok_count, + # counter.invalid_count) return counter From c9babba161b5bbd48d09ef39ad45aa06b142720e Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Mon, 20 May 2024 12:24:12 -0700 Subject: [PATCH 04/23] oops, front end isn't working --- bar_chart_test.py | 6 +----- display.py | 10 +++------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/bar_chart_test.py b/bar_chart_test.py index f952c99..9ee0e81 100644 --- a/bar_chart_test.py +++ b/bar_chart_test.py @@ -18,10 +18,6 @@ def __init__(self, parent=None, args=None): vertLayout_Form = self.ui.findChild(QVBoxLayout) - # Read in archive data - # pv_strings = ["PPS:SYSW:1:BeamReadyA", "ACCL:L3B:1910:PZT:FBSTATSUM", - # "ACCL:L2B:1310:SSA_LTCH", "ACCL:L2B:1310:CRYO_LTCH"] - pv_string1 = "ACCL:L3B:1910:PZT:FBSTATSUM" # PZO fault pv_string2 = "XCOR:L3B:1685:STATMSG" # MGT fault pv_list = [pv_string1, pv_string2] @@ -54,7 +50,7 @@ def __init__(self, parent=None, args=None): yaxis_fault.append(fault_count) print(key, "\tTotal fault counts: ", fault_count) - # Make plot window and it to the vert layout + # Make plot window and add it to the vert layout plot_window = pg.plot() vertLayout_Form.addWidget(plot_window) diff --git a/display.py b/display.py index fe61217..8b465de 100644 --- a/display.py +++ b/display.py @@ -1,17 +1,13 @@ import json -import sys -from typing import List - from PyQt5.QtWidgets import QHBoxLayout, QLabel from pydm import Display from pydm.widgets import PyDMByteIndicator, PyDMEmbeddedDisplay, PyDMTemplateRepeater +from typing import List +from frontend.cavity_widget import CavityWidget from lcls_tools.superconducting.sc_linac import Cavity, MACHINE from utils import DESCRIPTION_SUFFIX, SEVERITY_SUFFIX, STATUS_SUFFIX -sys.path.insert(0, "./frontend") -from cavityWidget import CavityWidget - class CavityDisplayGUI(Display): def __init__(self, parent=None, args=None): @@ -61,7 +57,7 @@ def __init__(self, parent=None, args=None): ssa_status_bar_list.append(statusBar) for cavity_widget, rf_status_bar, ssa_status_bar in zip( - cavity_widget_list, rf_status_bar_list, ssa_status_bar_list + cavity_widget_list, rf_status_bar_list, ssa_status_bar_list ): cavity_object: Cavity = cryomodule_object.cavities[ int(cavity_widget.cavityText) From bbb65e86d3be1f800536c387798b7c3581dcb934 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Fri, 19 Jul 2024 08:56:19 -0700 Subject: [PATCH 05/23] Can launch bar chart without .ui file now --- backend/runner.py | 28 +++++++++++++++------------- bar_chart_test.py | 23 ++++++++++++++--------- testBarChart.ui | 28 ---------------------------- 3 files changed, 29 insertions(+), 50 deletions(-) delete mode 100644 testBarChart.ui diff --git a/backend/runner.py b/backend/runner.py index db52e12..d48eba9 100644 --- a/backend/runner.py +++ b/backend/runner.py @@ -2,6 +2,7 @@ from time import sleep from backend.backend_cavity import BackendCavity +# from bar_chart_test import BarChart from lcls_tools.common.controls.pyepics.utils import PV from lcls_tools.superconducting.sc_linac import Machine, Cryomodule from lcls_tools.superconducting.sc_linac_utils import ALL_CRYOMODULES @@ -18,17 +19,18 @@ cryomodule: Cryomodule = DISPLAY_MACHINE.cryomodules[cryomoduleName] for cavity in cryomodule.cavities.values(): # EX: cavity = L0B CM01 Cavity 2 - # EX: cryomodule.cavities.values() = dict of 8 display_linac.DisplayCavity object - # TODO - cavity.run_through_faults() ####PUT THIS BACK IN - # if (cavity.pv_prefix == "ACCL:L1B:H220:"): - # cavity.get_fault_counts(datetime.now() - timedelta(minutes=1), datetime.now()) - # print("Start: ", datetime.now() - timedelta(minutes=1), "End: ", datetime.now()) - if DEBUG: - delta = (datetime.now() - start).total_seconds() - sleep(BACKEND_SLEEP_TIME - delta if delta < BACKEND_SLEEP_TIME else 0) + # EX: cryomodule.cavities.values() = dict of 8 backend.backend_cavity.BackendCavity objects + # cavity.run_through_faults() ####TODO PUT THIS BACK IN + if (cavity.pv_prefix == "ACCL:L1B:H220:"): + # BarChart() + print("I am here") + cavity.get_fault_counts(datetime.now() - timedelta(minutes=1), datetime.now()) + print("Start: ", datetime.now() - timedelta(minutes=1), "End: ", datetime.now()) + if DEBUG: + delta = (datetime.now() - start).total_seconds() + sleep(BACKEND_SLEEP_TIME - delta if delta < BACKEND_SLEEP_TIME else 0) - try: - WATCHER_PV.put(WATCHER_PV.get() + 1) - except TypeError as e: - print(f"Write to watcher PV failed with error: {e}") + try: + WATCHER_PV.put(WATCHER_PV.get() + 1) + except TypeError as e: + print(f"Write to watcher PV failed with error: {e}") diff --git a/bar_chart_test.py b/bar_chart_test.py index 9ee0e81..7d48cde 100644 --- a/bar_chart_test.py +++ b/bar_chart_test.py @@ -13,10 +13,9 @@ class BarChart(Display): def __init__(self, parent=None, args=None): - super(BarChart, self).__init__(parent=parent, args=args, - ui_filename="testBarChart.ui") - - vertLayout_Form = self.ui.findChild(QVBoxLayout) + super().__init__(parent, args) + # super(BarChart, self).__init__(parent=parent, args=args, + # ui_filename="testBarChart.ui") pv_string1 = "ACCL:L3B:1910:PZT:FBSTATSUM" # PZO fault pv_string2 = "XCOR:L3B:1685:STATMSG" # MGT fault @@ -50,9 +49,15 @@ def __init__(self, parent=None, args=None): yaxis_fault.append(fault_count) print(key, "\tTotal fault counts: ", fault_count) + self.setWindowTitle("Bar Chart") + vertLayout_Form = QVBoxLayout() + # vertLayout_Form = self.ui.findChild(QVBoxLayout) + # Make plot window and add it to the vert layout - plot_window = pg.plot() - vertLayout_Form.addWidget(plot_window) + self.plot_window = pg.plot() + vertLayout_Form.addWidget(self.plot_window) + + self.setLayout(vertLayout_Form) # Create list for horizontal and vertical axis xlabel = ['PZO', 'MGT'] @@ -68,12 +73,12 @@ def __init__(self, parent=None, args=None): # Create pyqt5graph bar graph item with green bars bargraph = pg.BarGraphItem(x=xval, height=yaxis_fault, width=0.6, brush='g') - ax = plot_window.getAxis('bottom') + ax = self.plot_window.getAxis('bottom') ax.setTicks(ticks) - plot_window.showGrid(x=False, y=True, alpha=0.6) + self.plot_window.showGrid(x=False, y=True, alpha=0.6) # Add bargraph to plot window - plot_window.addItem(bargraph) + self.plot_window.addItem(bargraph) ''' pv_list = Tester().pvList # ["BEND:LTUH:220:BDES", "BEND:LTUH:280:BDES"] diff --git a/testBarChart.ui b/testBarChart.ui deleted file mode 100644 index c23f68e..0000000 --- a/testBarChart.ui +++ /dev/null @@ -1,28 +0,0 @@ - - - Form - - - - 0 - 0 - 400 - 300 - - - - Fault Counter - - - - - - Fault Counter - - - - - - - - From de71ce52563d6e46d1b18476916c94a44f5b9eab Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Mon, 22 Jul 2024 13:48:18 -0700 Subject: [PATCH 06/23] Got archive_data.py to launch bar chart GUI from another file --- backend/archive_data.py | 38 +++++++++++++++++++++++ backend/backend_cavity.py | 16 +++++----- backend/runner.py | 11 ++----- bar_chart_test.py => bar_chart_display.py | 25 +++++++-------- 4 files changed, 60 insertions(+), 30 deletions(-) create mode 100644 backend/archive_data.py rename bar_chart_test.py => bar_chart_display.py (78%) diff --git a/backend/archive_data.py b/backend/archive_data.py new file mode 100644 index 0000000..9904f02 --- /dev/null +++ b/backend/archive_data.py @@ -0,0 +1,38 @@ +from backend.backend_cavity import BackendCavity +from bar_chart_display import BarChart +from lcls_tools.superconducting.sc_linac import Machine, Cryomodule +from lcls_tools.superconducting.sc_linac_utils import ALL_CRYOMODULES + +DISPLAY_MACHINE = Machine(cavity_class=BackendCavity) + +for cryomoduleName in ALL_CRYOMODULES: + cryomodule: Cryomodule = DISPLAY_MACHINE.cryomodules[cryomoduleName] + for cavity in cryomodule.cavities.values(): + if (cavity.pv_prefix == "ACCL:L1B:H220:"): + print("CM H2, cavity 2") + BarChart() + +''' +while True: + start = datetime.now() + for cryomoduleName in ALL_CRYOMODULES: + cryomodule: Cryomodule = DISPLAY_MACHINE.cryomodules[cryomoduleName] + for cavity in cryomodule.cavities.values(): + # EX: cavity = L0B CM01 Cavity 2 + # EX: cryomodule.cavities.values() = dict of 8 backend.backend_cavity.BackendCavity objects + if (cavity.pv_prefix == "ACCL:L1B:H220:"): + BarChart() + print("I am here") + + result = cavity.get_fault_counts(datetime.now() - timedelta(minutes=1), datetime.now()) + for faultPv in result: + print(faultPv, "\t", result[faultPv], + result[faultPv].fault_count, + result[faultPv].ok_count, + result[faultPv].invalid_count) + print("Start: ", datetime.now() - timedelta(minutes=1), "End: ", datetime.now()) + + if DEBUG: + delta = (datetime.now() - start).total_seconds() + sleep(BACKEND_SLEEP_TIME - delta if delta < BACKEND_SLEEP_TIME else 0) +''' diff --git a/backend/backend_cavity.py b/backend/backend_cavity.py index c91f8dc..44a6e76 100644 --- a/backend/backend_cavity.py +++ b/backend/backend_cavity.py @@ -1,11 +1,11 @@ from collections import OrderedDict -from datetime import datetime -from typing import Dict +from datetime import datetime from epics import caput +from typing import Dict -from bar_chart_test import BarChart from backend.fault import Fault, FaultCounter, PVInvalidError +from bar_chart_display import BarChart from lcls_tools.superconducting.sc_linac import Cavity from utils.utils import ( STATUS_SUFFIX, @@ -19,9 +19,9 @@ class BackendCavity(Cavity): def __init__( - self, - cavity_num, - rack_object, + self, + cavity_num, + rack_object, ): super(BackendCavity, self).__init__( cavity_num=cavity_num, rack_object=rack_object @@ -76,7 +76,7 @@ def create_faults(self): ) if (cm_type == "1.3" and self.cryomodule.is_harmonic_linearizer) or ( - cm_type == "3.9" and not self.cryomodule.is_harmonic_linearizer + cm_type == "3.9" and not self.cryomodule.is_harmonic_linearizer ): continue pv = prefix + suffix @@ -120,7 +120,7 @@ def create_faults(self): ) def get_fault_counts( - self, start_time: datetime, end_time: datetime + self, start_time: datetime, end_time: datetime ) -> Dict[str, FaultCounter]: result: Dict[str, FaultCounter] = {} diff --git a/backend/runner.py b/backend/runner.py index d48eba9..5107065 100644 --- a/backend/runner.py +++ b/backend/runner.py @@ -2,7 +2,6 @@ from time import sleep from backend.backend_cavity import BackendCavity -# from bar_chart_test import BarChart from lcls_tools.common.controls.pyepics.utils import PV from lcls_tools.superconducting.sc_linac import Machine, Cryomodule from lcls_tools.superconducting.sc_linac_utils import ALL_CRYOMODULES @@ -18,14 +17,8 @@ for cryomoduleName in ALL_CRYOMODULES: cryomodule: Cryomodule = DISPLAY_MACHINE.cryomodules[cryomoduleName] for cavity in cryomodule.cavities.values(): - # EX: cavity = L0B CM01 Cavity 2 - # EX: cryomodule.cavities.values() = dict of 8 backend.backend_cavity.BackendCavity objects - # cavity.run_through_faults() ####TODO PUT THIS BACK IN - if (cavity.pv_prefix == "ACCL:L1B:H220:"): - # BarChart() - print("I am here") - cavity.get_fault_counts(datetime.now() - timedelta(minutes=1), datetime.now()) - print("Start: ", datetime.now() - timedelta(minutes=1), "End: ", datetime.now()) + cavity.run_through_faults() + if DEBUG: delta = (datetime.now() - start).total_seconds() sleep(BACKEND_SLEEP_TIME - delta if delta < BACKEND_SLEEP_TIME else 0) diff --git a/bar_chart_test.py b/bar_chart_display.py similarity index 78% rename from bar_chart_test.py rename to bar_chart_display.py index 7d48cde..4baeeb5 100644 --- a/bar_chart_test.py +++ b/bar_chart_display.py @@ -2,7 +2,7 @@ # import sys # from PyQt.QtChart import import pyqtgraph as pg -from PyQt5.QtWidgets import QVBoxLayout +from PyQt5.QtWidgets import QVBoxLayout, QApplication from datetime import datetime from pydm import Display @@ -14,8 +14,8 @@ class BarChart(Display): def __init__(self, parent=None, args=None): super().__init__(parent, args) - # super(BarChart, self).__init__(parent=parent, args=args, - # ui_filename="testBarChart.ui") + + print("TEST: this is bar_chart_display.py") pv_string1 = "ACCL:L3B:1910:PZT:FBSTATSUM" # PZO fault pv_string2 = "XCOR:L3B:1685:STATMSG" # MGT fault @@ -51,7 +51,6 @@ def __init__(self, parent=None, args=None): self.setWindowTitle("Bar Chart") vertLayout_Form = QVBoxLayout() - # vertLayout_Form = self.ui.findChild(QVBoxLayout) # Make plot window and add it to the vert layout self.plot_window = pg.plot() @@ -80,12 +79,12 @@ def __init__(self, parent=None, args=None): # Add bargraph to plot window self.plot_window.addItem(bargraph) - ''' - pv_list = Tester().pvList # ["BEND:LTUH:220:BDES", "BEND:LTUH:280:BDES"] - start_time = datetime(2020, 10, 1, 10, 7, 28, 958256) # 220 - end_time = datetime(2020, 10, 14, 9, 57, 57, 230327) # 220 - result = Archiver('lcls').getValuesOverTimeRange(pvList=pv_list, - startTime=start_time, - endTime=end_time) - print(result) - ''' + +def main(): + app = QApplication(sys.argv) + chart = BarChart() + sys.exit(app.exec_()) + + +if __name__ == "__main__": + main() From 467f294c023378aab3a549ab0049691289669756 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Tue, 23 Jul 2024 12:28:04 -0700 Subject: [PATCH 07/23] Troubleshooting BarChart failing to launch --- backend/archive_data.py | 59 ++++++++++++++---------------- backend/backend_cavity.py | 17 ++------- backend/fault.py | 10 +++++ backend/runner.py | 3 +- bar_chart_display.py | 77 +++++++-------------------------------- utils/utils.py | 1 - 6 files changed, 56 insertions(+), 111 deletions(-) diff --git a/backend/archive_data.py b/backend/archive_data.py index 9904f02..2452139 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -1,38 +1,33 @@ +from datetime import datetime, timedelta +from typing import Dict + +print("Actual start of archive_data.py before import statements++++++++++++++++++") from backend.backend_cavity import BackendCavity +from backend.fault import FaultCounter from bar_chart_display import BarChart -from lcls_tools.superconducting.sc_linac import Machine, Cryomodule -from lcls_tools.superconducting.sc_linac_utils import ALL_CRYOMODULES +from lcls_tools.superconducting.sc_linac import Machine DISPLAY_MACHINE = Machine(cavity_class=BackendCavity) -for cryomoduleName in ALL_CRYOMODULES: - cryomodule: Cryomodule = DISPLAY_MACHINE.cryomodules[cryomoduleName] - for cavity in cryomodule.cavities.values(): - if (cavity.pv_prefix == "ACCL:L1B:H220:"): - print("CM H2, cavity 2") - BarChart() +print("Start of archive_data.py file +++++++++++++++++++++++++++++++++++++++++++") +cavity = DISPLAY_MACHINE.cryomodules["H2"].cavities[2] + +tlc_list = [] +fault_count_list = [] + +# Ex. result is a dictionary with key=fault pv string, value=FaultCounter(fault_count=0, ok_count=1, invalid_count=0) +result: Dict[str, FaultCounter] = cavity.get_fault_counts(datetime.now() - timedelta(minutes=1), + datetime.now()) +for tlc, counter_obj in result.items(): + tlc_list.append(tlc) # x axis + fault_count_list.append(counter_obj.sum_fault_count) # y axis -''' -while True: - start = datetime.now() - for cryomoduleName in ALL_CRYOMODULES: - cryomodule: Cryomodule = DISPLAY_MACHINE.cryomodules[cryomoduleName] - for cavity in cryomodule.cavities.values(): - # EX: cavity = L0B CM01 Cavity 2 - # EX: cryomodule.cavities.values() = dict of 8 backend.backend_cavity.BackendCavity objects - if (cavity.pv_prefix == "ACCL:L1B:H220:"): - BarChart() - print("I am here") - - result = cavity.get_fault_counts(datetime.now() - timedelta(minutes=1), datetime.now()) - for faultPv in result: - print(faultPv, "\t", result[faultPv], - result[faultPv].fault_count, - result[faultPv].ok_count, - result[faultPv].invalid_count) - print("Start: ", datetime.now() - timedelta(minutes=1), "End: ", datetime.now()) - - if DEBUG: - delta = (datetime.now() - start).total_seconds() - sleep(BACKEND_SLEEP_TIME - delta if delta < BACKEND_SLEEP_TIME else 0) -''' + ''' + print(tlc, "\t", counter_obj, + counter_obj.fault_count, + counter_obj.ok_count, + counter_obj.invalid_count) + ''' +print("right before BarChart call in archive_data.py++++++++++++") +BarChart(x_vals=tlc_list, y_vals=fault_count_list) +print("End of archive_data.py++++++++++++++++++++++++++++++++++") diff --git a/backend/backend_cavity.py b/backend/backend_cavity.py index 44a6e76..9daa0d9 100644 --- a/backend/backend_cavity.py +++ b/backend/backend_cavity.py @@ -1,11 +1,10 @@ -from collections import OrderedDict +from collections import OrderedDict, defaultdict from datetime import datetime from epics import caput from typing import Dict from backend.fault import Fault, FaultCounter, PVInvalidError -from bar_chart_display import BarChart from lcls_tools.superconducting.sc_linac import Cavity from utils.utils import ( STATUS_SUFFIX, @@ -122,20 +121,12 @@ def create_faults(self): def get_fault_counts( self, start_time: datetime, end_time: datetime ) -> Dict[str, FaultCounter]: - result: Dict[str, FaultCounter] = {} + result: Dict[str, FaultCounter] = defaultdict(FaultCounter) for fault in self.faults.values(): - result[fault.pv.pvname] = fault.get_fault_count_over_time_range( + result[fault.tlc] = max(result[fault.tlc], fault.get_fault_count_over_time_range( start_time=start_time, end_time=end_time - ) - - # result is a dictionary with key=fault pv string, value=FaultCounter(fault_count=0, ok_count=1, invalid_count=0) - for faultPv in result: - print(faultPv, "\t", result[faultPv], - result[faultPv].fault_count, - result[faultPv].ok_count, - result[faultPv].invalid_count) - BarChart # --------------------------------------------- + )) return result diff --git a/backend/fault.py b/backend/fault.py index fe1feec..074f715 100644 --- a/backend/fault.py +++ b/backend/fault.py @@ -19,6 +19,10 @@ class FaultCounter: ok_count: int = 0 invalid_count: int = 0 + @property + def sum_fault_count(self): + return self.fault_count + self.invalid_count + @property def ratio_ok(self): try: @@ -26,6 +30,12 @@ def ratio_ok(self): except ZeroDivisionError: return 1 + def __gt__(self, other): + return self.sum_fault_count > other.sum_fault_count + + def __eq__(self, other): + return self.sum_fault_count == other.sum_fault_count + class PVInvalidError(Exception): def __init__(self, message): diff --git a/backend/runner.py b/backend/runner.py index 5107065..1e6151e 100644 --- a/backend/runner.py +++ b/backend/runner.py @@ -3,7 +3,7 @@ from backend.backend_cavity import BackendCavity from lcls_tools.common.controls.pyepics.utils import PV -from lcls_tools.superconducting.sc_linac import Machine, Cryomodule +from lcls_tools.superconducting.sc_linac import Cryomodule, Machine from lcls_tools.superconducting.sc_linac_utils import ALL_CRYOMODULES from utils.utils import DEBUG, BACKEND_SLEEP_TIME @@ -11,7 +11,6 @@ WATCHER_PV.put(0) DISPLAY_MACHINE = Machine(cavity_class=BackendCavity) - while True: start = datetime.now() for cryomoduleName in ALL_CRYOMODULES: diff --git a/bar_chart_display.py b/bar_chart_display.py index 4baeeb5..2498bd6 100644 --- a/bar_chart_display.py +++ b/bar_chart_display.py @@ -1,54 +1,15 @@ -# from PyQt5.QtWidgets import QApplication, QMainWindow -# import sys -# from PyQt.QtChart import import pyqtgraph as pg -from PyQt5.QtWidgets import QVBoxLayout, QApplication -from datetime import datetime +from PyQt5.QtWidgets import QVBoxLayout from pydm import Display +from typing import List -from lcls_tools.common.data_analysis.archiver import ( - get_values_over_time_range, -) +print("Start of bar_chart_display.py-----------------------------------------") class BarChart(Display): - def __init__(self, parent=None, args=None): + def __init__(self, x_vals: List[str], y_vals: List[int], parent=None, args=None): super().__init__(parent, args) - print("TEST: this is bar_chart_display.py") - - pv_string1 = "ACCL:L3B:1910:PZT:FBSTATSUM" # PZO fault - pv_string2 = "XCOR:L3B:1685:STATMSG" # MGT fault - pv_list = [pv_string1, pv_string2] - - start = datetime(2024, 5, 17, 4, 29, 35, 24214) - end = datetime(2024, 5, 17, 4, 30, 35, 24214) - - # get_values_over_time_range(...) -> Dict[str, ArchiveDataHandler] - result = get_values_over_time_range(pv_list, start_time=start, - end_time=end) - - # Hard coding interpretting the archive data result - yaxis_fault = [] - for key, value in result.items(): - data_handler: ArchiveDataHandler = result[key] - - if key == pv_string1: - fault_count = 0 - for archiver_value in data_handler.value_list: - if archiver_value.val == 1: - fault_count += 1 - yaxis_fault.append(fault_count) - print(key, "\tTotal fault counts: ", fault_count) - - elif key == pv_string2: - fault_count = 0 - for archiver_value in data_handler.value_list: - if archiver_value.val == 8: - fault_count += 1 - yaxis_fault.append(fault_count) - print(key, "\tTotal fault counts: ", fault_count) - self.setWindowTitle("Bar Chart") vertLayout_Form = QVBoxLayout() @@ -58,33 +19,23 @@ def __init__(self, parent=None, args=None): self.setLayout(vertLayout_Form) - # Create list for horizontal and vertical axis - xlabel = ['PZO', 'MGT'] - xval = [0, 1] + # TODO Remove these hardcoded x_vals and y_vals + # x_vals = ['OFF', 'PZO', 'MGT'] + # y_vals = [1, 6, 2] + x_vals_ints = [] - # Create list of list of tuples for tick marks in the form of - # [[(0,'HWI'), (1,'AOT'), ...]] ticks = [] - for i, xlabel_string in enumerate(xlabel): - ticks.append((xval[i], xlabel_string)) - ticks = [ticks] + for idx, x_val in enumerate(x_vals): + ticks.append((idx, x_val)) + x_vals_ints.append(idx) # Create pyqt5graph bar graph item with green bars - bargraph = pg.BarGraphItem(x=xval, height=yaxis_fault, width=0.6, brush='g') + bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals, width=0.6, brush='g') ax = self.plot_window.getAxis('bottom') - ax.setTicks(ticks) + ax.setTicks([ticks]) self.plot_window.showGrid(x=False, y=True, alpha=0.6) # Add bargraph to plot window self.plot_window.addItem(bargraph) - - -def main(): - app = QApplication(sys.argv) - chart = BarChart() - sys.exit(app.exec_()) - - -if __name__ == "__main__": - main() + print("End of bar_chart_display.py----------------------------------------") diff --git a/utils/utils.py b/utils/utils.py index f4c8fba..df84c3b 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,6 +1,5 @@ import os from csv import DictReader - from typing import Dict, List DEBUG = True From e25d16b08ed0f0718cfa44f4f6618d4153066992 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Tue, 23 Jul 2024 14:21:51 -0700 Subject: [PATCH 08/23] It works! Made new GUI to select cm and cav to make bar chart --- backend/archive_data.py | 115 +++++++++++++++++++++++++++++++--------- bar_chart_display.py | 4 +- 2 files changed, 94 insertions(+), 25 deletions(-) diff --git a/backend/archive_data.py b/backend/archive_data.py index 2452139..80eb98f 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -1,33 +1,100 @@ -from datetime import datetime, timedelta +import pyqtgraph as pg +from PyQt5.QtCore import QDateTime +from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QComboBox, QDateTimeEdit, QPushButton +from pydm import Display from typing import Dict -print("Actual start of archive_data.py before import statements++++++++++++++++++") from backend.backend_cavity import BackendCavity -from backend.fault import FaultCounter -from bar_chart_display import BarChart from lcls_tools.superconducting.sc_linac import Machine +from lcls_tools.superconducting.sc_linac_utils import ALL_CRYOMODULES DISPLAY_MACHINE = Machine(cavity_class=BackendCavity) -print("Start of archive_data.py file +++++++++++++++++++++++++++++++++++++++++++") cavity = DISPLAY_MACHINE.cryomodules["H2"].cavities[2] -tlc_list = [] -fault_count_list = [] - -# Ex. result is a dictionary with key=fault pv string, value=FaultCounter(fault_count=0, ok_count=1, invalid_count=0) -result: Dict[str, FaultCounter] = cavity.get_fault_counts(datetime.now() - timedelta(minutes=1), - datetime.now()) -for tlc, counter_obj in result.items(): - tlc_list.append(tlc) # x axis - fault_count_list.append(counter_obj.sum_fault_count) # y axis - - ''' - print(tlc, "\t", counter_obj, - counter_obj.fault_count, - counter_obj.ok_count, - counter_obj.invalid_count) - ''' -print("right before BarChart call in archive_data.py++++++++++++") -BarChart(x_vals=tlc_list, y_vals=fault_count_list) -print("End of archive_data.py++++++++++++++++++++++++++++++++++") + +class FaultCounter(Display): + def __init__(self): + super().__init__() + main_v_layout = QVBoxLayout() + input_h_layout = QHBoxLayout() + + self.plot_window = pg.plot() + main_v_layout.addLayout(input_h_layout) + main_v_layout.addWidget(self.plot_window) + self.setLayout(main_v_layout) + + self.cm_combo_box = QComboBox() + self.cav_combo_box = QComboBox() + + min_date_time = QDateTime(2022, 1, 1, 0, 0) + self.start_selector = QDateTimeEdit() + self.end_selector = QDateTimeEdit() + + self.start_selector.setMinimumDateTime(min_date_time) + self.end_selector.setMinimumDateTime(min_date_time) + + self.plot_button = QPushButton() + + input_h_layout.addWidget(self.cm_combo_box) + input_h_layout.addWidget(self.cav_combo_box) + input_h_layout.addWidget(self.start_selector) + input_h_layout.addWidget(self.end_selector) + input_h_layout.addWidget(self.plot_button) + + self.cm_combo_box.addItems(ALL_CRYOMODULES) + self.cav_combo_box.addItems([str(i) for i in range(1, 9)]) + + self.x_data = None + self.y_data = None + + self.plot_button.clicked.connect(self.update_plot) + + def get_data(self): + cavity: BackendCavity = DISPLAY_MACHINE.cryomodules[self.cm_combo_box.currentText()].cavities[ + int(self.cav_combo_box.currentText())] + + self.x_data = [] + self.y_data = [] + + start = self.start_selector.dateTime().toPyDateTime() + end = self.end_selector.dateTime().toPyDateTime() + + # Ex. result is a dictionary with key=fault pv string, value=FaultCounter(fault_count=0, ok_count=1, invalid_count=0) + result: Dict[str, FaultCounter] = cavity.get_fault_counts( + start, end + ) + for tlc, counter_obj in result.items(): + self.x_data.append(tlc) # x axis + self.y_data.append(counter_obj.sum_fault_count) # y axis + + def update_plot(self): + self.get_data() + + ticks = [] + x_vals_ints = [] + for idx, x_val in enumerate(self.x_data): + ticks.append((idx, x_val)) + x_vals_ints.append(idx) + + # Create pyqt5graph bar graph item with green bars + bargraph = pg.BarGraphItem(x=x_vals_ints, height=self.y_data, width=0.6, brush="g") + + ax = self.plot_window.getAxis("bottom") + ax.setTicks([ticks]) + self.plot_window.showGrid(x=False, y=True, alpha=0.6) + self.plot_window.addItem(bargraph) + + +''' + + +chart_display = Display() +chart_display.setWindowTitle("Bar Chart") +vert_layout = QVBoxLayout() +plot_window = pg.plot() +vert_layout.addWidget(plot_window) +chart_display.setLayout(vert_layout) + +showDisplay(chart_display) +''' diff --git a/bar_chart_display.py b/bar_chart_display.py index 2498bd6..15c5262 100644 --- a/bar_chart_display.py +++ b/bar_chart_display.py @@ -38,4 +38,6 @@ def __init__(self, x_vals: List[str], y_vals: List[int], parent=None, args=None) # Add bargraph to plot window self.plot_window.addItem(bargraph) - print("End of bar_chart_display.py----------------------------------------") + + +print("End of bar_chart_display.py----------------------------------------") From 97fc10ed6e2477b5a75e88be782da4a9b01ba646 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Wed, 24 Jul 2024 16:58:03 -0700 Subject: [PATCH 09/23] Added labels for user readability --- backend/archive_data.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/backend/archive_data.py b/backend/archive_data.py index 80eb98f..aedab86 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -1,6 +1,6 @@ import pyqtgraph as pg from PyQt5.QtCore import QDateTime -from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QComboBox, QDateTimeEdit, QPushButton +from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QComboBox, QDateTimeEdit, QPushButton, QLabel from pydm import Display from typing import Dict @@ -24,21 +24,32 @@ def __init__(self): main_v_layout.addWidget(self.plot_window) self.setLayout(main_v_layout) + cm_text = QLabel("CM:") self.cm_combo_box = QComboBox() + cav_text = QLabel("Cav:") self.cav_combo_box = QComboBox() - min_date_time = QDateTime(2022, 1, 1, 0, 0) + end_date_time = QDateTime.currentDateTime() + min_date_time = QDateTime.addSecs(end_date_time, 10 * -60) + + start_text = QLabel("Start:") self.start_selector = QDateTimeEdit() + end_text = QLabel("End:") self.end_selector = QDateTimeEdit() self.start_selector.setMinimumDateTime(min_date_time) - self.end_selector.setMinimumDateTime(min_date_time) + self.end_selector.setMinimumDateTime(end_date_time) self.plot_button = QPushButton() + self.plot_button.setText("Update Bar Chart") + input_h_layout.addWidget(cm_text) input_h_layout.addWidget(self.cm_combo_box) + input_h_layout.addWidget(cav_text) input_h_layout.addWidget(self.cav_combo_box) + input_h_layout.addWidget(start_text) input_h_layout.addWidget(self.start_selector) + input_h_layout.addWidget(end_text) input_h_layout.addWidget(self.end_selector) input_h_layout.addWidget(self.plot_button) From 57e22a9f6b1f7cc8a9c8734b23761113de173289 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Mon, 12 Aug 2024 12:07:35 -0700 Subject: [PATCH 10/23] Removed attempt at scroll bar --- backend/archive_data.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/archive_data.py b/backend/archive_data.py index aedab86..0934c24 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -10,7 +10,8 @@ DISPLAY_MACHINE = Machine(cavity_class=BackendCavity) -cavity = DISPLAY_MACHINE.cryomodules["H2"].cavities[2] + +# cavity = DISPLAY_MACHINE.cryomodules["H2"].cavities[2] class FaultCounter(Display): @@ -20,6 +21,7 @@ def __init__(self): input_h_layout = QHBoxLayout() self.plot_window = pg.plot() + main_v_layout.addLayout(input_h_layout) main_v_layout.addWidget(self.plot_window) self.setLayout(main_v_layout) @@ -30,7 +32,7 @@ def __init__(self): self.cav_combo_box = QComboBox() end_date_time = QDateTime.currentDateTime() - min_date_time = QDateTime.addSecs(end_date_time, 10 * -60) + min_date_time = QDateTime.addSecs(end_date_time, 30 * -60) start_text = QLabel("Start:") self.start_selector = QDateTimeEdit() @@ -92,6 +94,7 @@ def update_plot(self): bargraph = pg.BarGraphItem(x=x_vals_ints, height=self.y_data, width=0.6, brush="g") ax = self.plot_window.getAxis("bottom") + print(type(ax)) ax.setTicks([ticks]) self.plot_window.showGrid(x=False, y=True, alpha=0.6) self.plot_window.addItem(bargraph) From 22715f87aa70ee0a7604a0c9f48dc6d902a64587 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Tue, 13 Aug 2024 07:40:52 -0700 Subject: [PATCH 11/23] Made bar chart horizontal --- backend/archive_data.py | 29 ++++++----------------------- bar_chart_display.py | 22 +++++++++------------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/backend/archive_data.py b/backend/archive_data.py index 0934c24..d90f31a 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -11,9 +11,6 @@ DISPLAY_MACHINE = Machine(cavity_class=BackendCavity) -# cavity = DISPLAY_MACHINE.cryomodules["H2"].cavities[2] - - class FaultCounter(Display): def __init__(self): super().__init__() @@ -87,28 +84,14 @@ def update_plot(self): ticks = [] x_vals_ints = [] for idx, x_val in enumerate(self.x_data): - ticks.append((idx, x_val)) - x_vals_ints.append(idx) + ticks.append((idx + 1, x_val)) + x_vals_ints.append(idx + 1) # Create pyqt5graph bar graph item with green bars - bargraph = pg.BarGraphItem(x=x_vals_ints, height=self.y_data, width=0.6, brush="g") + # bargraph = pg.BarGraphItem(x=x_vals_ints, height=self.y_data, width=0.6, brush="g") + bargraph = pg.BarGraphItem(x0=0, y=x_vals_ints, height=0.6, width=self.y_data, brush='b') - ax = self.plot_window.getAxis("bottom") - print(type(ax)) + ax = self.plot_window.getAxis("left") ax.setTicks([ticks]) - self.plot_window.showGrid(x=False, y=True, alpha=0.6) + self.plot_window.showGrid(x=True, y=False, alpha=0.6) self.plot_window.addItem(bargraph) - - -''' - - -chart_display = Display() -chart_display.setWindowTitle("Bar Chart") -vert_layout = QVBoxLayout() -plot_window = pg.plot() -vert_layout.addWidget(plot_window) -chart_display.setLayout(vert_layout) - -showDisplay(chart_display) -''' diff --git a/bar_chart_display.py b/bar_chart_display.py index 15c5262..3871331 100644 --- a/bar_chart_display.py +++ b/bar_chart_display.py @@ -1,13 +1,10 @@ import pyqtgraph as pg from PyQt5.QtWidgets import QVBoxLayout from pydm import Display -from typing import List - -print("Start of bar_chart_display.py-----------------------------------------") class BarChart(Display): - def __init__(self, x_vals: List[str], y_vals: List[int], parent=None, args=None): + def __init__(self, parent=None, args=None): super().__init__(parent, args) self.setWindowTitle("Bar Chart") @@ -20,24 +17,23 @@ def __init__(self, x_vals: List[str], y_vals: List[int], parent=None, args=None) self.setLayout(vertLayout_Form) # TODO Remove these hardcoded x_vals and y_vals - # x_vals = ['OFF', 'PZO', 'MGT'] - # y_vals = [1, 6, 2] + x_vals = ['OFF', 'PZO', 'MGT'] + y_vals = [1, 6, 2] x_vals_ints = [] ticks = [] for idx, x_val in enumerate(x_vals): - ticks.append((idx, x_val)) - x_vals_ints.append(idx) + ticks.append((idx + 1, x_val)) + x_vals_ints.append(idx + 1) + print(x_vals_ints) # Create pyqt5graph bar graph item with green bars - bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals, width=0.6, brush='g') + # bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals, width=0.6, brush='g') + bargraph = pg.BarGraphItem(x0=0, y=x_vals_ints, height=0.6, width=y_vals, brush='b') - ax = self.plot_window.getAxis('bottom') + ax = self.plot_window.getAxis('left') ax.setTicks([ticks]) self.plot_window.showGrid(x=False, y=True, alpha=0.6) # Add bargraph to plot window self.plot_window.addItem(bargraph) - - -print("End of bar_chart_display.py----------------------------------------") From 9a9f9cbae799519444a74f9c557e658e947092f5 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Tue, 13 Aug 2024 15:02:53 -0700 Subject: [PATCH 12/23] Made a stacked bar chart example (i.e. in an effort to get invalid and fault counts on the same bar graph) --- backend/archive_data.py | 1 + bar_chart_display.py | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/backend/archive_data.py b/backend/archive_data.py index d90f31a..9a678e1 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -92,6 +92,7 @@ def update_plot(self): bargraph = pg.BarGraphItem(x0=0, y=x_vals_ints, height=0.6, width=self.y_data, brush='b') ax = self.plot_window.getAxis("left") + self.plot_window.setWindowTitle("title") ax.setTicks([ticks]) self.plot_window.showGrid(x=True, y=False, alpha=0.6) self.plot_window.addItem(bargraph) diff --git a/bar_chart_display.py b/bar_chart_display.py index 3871331..65dcaec 100644 --- a/bar_chart_display.py +++ b/bar_chart_display.py @@ -1,5 +1,6 @@ import pyqtgraph as pg from PyQt5.QtWidgets import QVBoxLayout +# from PyQt5.QtChart import QChart, QChartView, QBarSet, QPercentBarSeries, QBarCategoryAxis from pydm import Display @@ -17,23 +18,33 @@ def __init__(self, parent=None, args=None): self.setLayout(vertLayout_Form) # TODO Remove these hardcoded x_vals and y_vals - x_vals = ['OFF', 'PZO', 'MGT'] - y_vals = [1, 6, 2] + x_vals = ['OFF', 'PZO', 'MGT', 'AOT'] + y_vals_faults = [1, 6, 2, 1] + y_vals_invalid = [10, 11, 12, 1] x_vals_ints = [] ticks = [] for idx, x_val in enumerate(x_vals): - ticks.append((idx + 1, x_val)) - x_vals_ints.append(idx + 1) + ticks.append((idx, x_val)) + x_vals_ints.append(idx) - print(x_vals_ints) + # Attempting to stack bar chart + bottom = [0, 0, 0, 0] + bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals_faults, width=0.6, brush='g') + self.plot_window.addItem(bargraph) + bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals_invalid, y0=y_vals_faults, width=0.6, brush='b') + self.plot_window.addItem(bargraph) + + ''' # Create pyqt5graph bar graph item with green bars - # bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals, width=0.6, brush='g') - bargraph = pg.BarGraphItem(x0=0, y=x_vals_ints, height=0.6, width=y_vals, brush='b') + bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals_faults, width=0.6, brush='g') + # bargraph = pg.BarGraphItem(x0=0, y=x_vals_ints, height=0.6, width=y_vals, brush='b') - ax = self.plot_window.getAxis('left') + # ax = self.plot_window.getAxis('left') + ax = self.plot_window.getAxis('bottom') ax.setTicks([ticks]) self.plot_window.showGrid(x=False, y=True, alpha=0.6) # Add bargraph to plot window self.plot_window.addItem(bargraph) + ''' From bd5aed828a2236ffb3f1f0722c074120d60a71b8 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Wed, 14 Aug 2024 13:16:36 -0700 Subject: [PATCH 13/23] Set minimum start time to 3 yrs, default 30 min --- backend/archive_data.py | 22 ++++++++++++++++------ bar_chart_display.py | 6 ++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/backend/archive_data.py b/backend/archive_data.py index 9a678e1..b8badd5 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -5,6 +5,7 @@ from typing import Dict from backend.backend_cavity import BackendCavity +from frontend.cavity_widget import RED_FILL_COLOR, PURPLE_FILL_COLOR, DARK_GRAY_COLOR from lcls_tools.superconducting.sc_linac import Machine from lcls_tools.superconducting.sc_linac_utils import ALL_CRYOMODULES @@ -18,6 +19,7 @@ def __init__(self): input_h_layout = QHBoxLayout() self.plot_window = pg.plot() + self.plot_window.setBackground(DARK_GRAY_COLOR) main_v_layout.addLayout(input_h_layout) main_v_layout.addWidget(self.plot_window) @@ -29,7 +31,8 @@ def __init__(self): self.cav_combo_box = QComboBox() end_date_time = QDateTime.currentDateTime() - min_date_time = QDateTime.addSecs(end_date_time, 30 * -60) + intermediate_time = QDateTime.addSecs(end_date_time, -30 * 60) # 30 min + min_date_time = QDateTime.addYears(end_date_time, -3) # 3 years start_text = QLabel("Start:") self.start_selector = QDateTimeEdit() @@ -37,7 +40,8 @@ def __init__(self): self.end_selector = QDateTimeEdit() self.start_selector.setMinimumDateTime(min_date_time) - self.end_selector.setMinimumDateTime(end_date_time) + self.start_selector.setDateTime(intermediate_time) + self.end_selector.setDateTime(end_date_time) self.plot_button = QPushButton() self.plot_button.setText("Update Bar Chart") @@ -66,6 +70,8 @@ def get_data(self): self.x_data = [] self.y_data = [] + self.num_of_faults = [] + self.num_of_invalids = [] start = self.start_selector.dateTime().toPyDateTime() end = self.end_selector.dateTime().toPyDateTime() @@ -77,6 +83,9 @@ def get_data(self): for tlc, counter_obj in result.items(): self.x_data.append(tlc) # x axis self.y_data.append(counter_obj.sum_fault_count) # y axis + self.num_of_faults.append(counter_obj.fault_count) + self.num_of_invalids.append(counter_obj.invalid_count) + print(tlc, counter_obj.fault_count, counter_obj.invalid_count) def update_plot(self): self.get_data() @@ -87,12 +96,13 @@ def update_plot(self): ticks.append((idx + 1, x_val)) x_vals_ints.append(idx + 1) - # Create pyqt5graph bar graph item with green bars - # bargraph = pg.BarGraphItem(x=x_vals_ints, height=self.y_data, width=0.6, brush="g") - bargraph = pg.BarGraphItem(x0=0, y=x_vals_ints, height=0.6, width=self.y_data, brush='b') + # Create pyqt5graph bar graph for faults, then stack invalid faults on same bars + bargraph = pg.BarGraphItem(x0=0, y=x_vals_ints, height=0.6, width=self.num_of_faults, brush=RED_FILL_COLOR) + self.plot_window.addItem(bargraph) + bargraph = pg.BarGraphItem(x0=self.num_of_faults, y=x_vals_ints, height=0.6, width=self.num_of_invalids, + brush=PURPLE_FILL_COLOR) ax = self.plot_window.getAxis("left") - self.plot_window.setWindowTitle("title") ax.setTicks([ticks]) self.plot_window.showGrid(x=True, y=False, alpha=0.6) self.plot_window.addItem(bargraph) diff --git a/bar_chart_display.py b/bar_chart_display.py index 65dcaec..7b480ee 100644 --- a/bar_chart_display.py +++ b/bar_chart_display.py @@ -3,6 +3,8 @@ # from PyQt5.QtChart import QChart, QChartView, QBarSet, QPercentBarSeries, QBarCategoryAxis from pydm import Display +from frontend.cavity_widget import GREEN_FILL_COLOR + class BarChart(Display): def __init__(self, parent=None, args=None): @@ -29,8 +31,8 @@ def __init__(self, parent=None, args=None): x_vals_ints.append(idx) # Attempting to stack bar chart - bottom = [0, 0, 0, 0] - bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals_faults, width=0.6, brush='g') + print(type(GREEN_FILL_COLOR)) + bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals_faults, width=0.6, brush=GREEN_FILL_COLOR) self.plot_window.addItem(bargraph) bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals_invalid, y0=y_vals_faults, width=0.6, brush='b') self.plot_window.addItem(bargraph) From 31b4d8972ac9947a946163056497b8dd1a80c7e6 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Wed, 14 Aug 2024 15:07:01 -0700 Subject: [PATCH 14/23] Found a bug where previous bar chart is not being erased --- backend/archive_data.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/archive_data.py b/backend/archive_data.py index b8badd5..2e8aff0 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -76,6 +76,8 @@ def get_data(self): start = self.start_selector.dateTime().toPyDateTime() end = self.end_selector.dateTime().toPyDateTime() + print(start, end) + # Ex. result is a dictionary with key=fault pv string, value=FaultCounter(fault_count=0, ok_count=1, invalid_count=0) result: Dict[str, FaultCounter] = cavity.get_fault_counts( start, end From ee9f36ac4899f3fa82a805a92c291329a25943d3 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Mon, 19 Aug 2024 14:52:19 -0700 Subject: [PATCH 15/23] Added calendar to start and end dates --- backend/archive_data.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/archive_data.py b/backend/archive_data.py index 2e8aff0..0d142da 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -36,8 +36,11 @@ def __init__(self): start_text = QLabel("Start:") self.start_selector = QDateTimeEdit() + self.start_selector.setCalendarPopup(True) + end_text = QLabel("End:") self.end_selector = QDateTimeEdit() + self.end_selector.setCalendarPopup(True) self.start_selector.setMinimumDateTime(min_date_time) self.start_selector.setDateTime(intermediate_time) @@ -90,6 +93,7 @@ def get_data(self): print(tlc, counter_obj.fault_count, counter_obj.invalid_count) def update_plot(self): + self.plot_window.clear() self.get_data() ticks = [] From d4dd14774c4ff4f3dc80f89084b776f626a80f0a Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Tue, 3 Sep 2024 14:19:16 -0700 Subject: [PATCH 16/23] Made a checkbox and removed POT, but these are not interconnected tasks yet --- backend/archive_data.py | 52 ++++++++++++++++++++++++++++------------- bar_chart_display.py | 34 ++++++++++----------------- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/backend/archive_data.py b/backend/archive_data.py index 0d142da..84097dd 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -1,6 +1,6 @@ import pyqtgraph as pg from PyQt5.QtCore import QDateTime -from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QComboBox, QDateTimeEdit, QPushButton, QLabel +from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QComboBox, QDateTimeEdit, QPushButton, QLabel, QCheckBox from pydm import Display from typing import Dict @@ -15,6 +15,8 @@ class FaultCounter(Display): def __init__(self): super().__init__() + self.setWindowTitle("Fault Counter") + main_v_layout = QVBoxLayout() input_h_layout = QHBoxLayout() @@ -46,6 +48,10 @@ def __init__(self): self.start_selector.setDateTime(intermediate_time) self.end_selector.setDateTime(end_date_time) + REMOVE_POT = False + self.pot_checkbox = QCheckBox(text="Check to remove POT fault counts from plot") + self.pot_checkbox.stateChanged.connect(self.removePOT, REMOVE_POT) + self.plot_button = QPushButton() self.plot_button.setText("Update Bar Chart") @@ -58,11 +64,13 @@ def __init__(self): input_h_layout.addWidget(end_text) input_h_layout.addWidget(self.end_selector) input_h_layout.addWidget(self.plot_button) + main_v_layout.addWidget(self.pot_checkbox) self.cm_combo_box.addItems(ALL_CRYOMODULES) self.cav_combo_box.addItems([str(i) for i in range(1, 9)]) - self.x_data = None + self.num_of_faults = [] + self.num_of_invalids = [] self.y_data = None self.plot_button.clicked.connect(self.update_plot) @@ -71,25 +79,25 @@ def get_data(self): cavity: BackendCavity = DISPLAY_MACHINE.cryomodules[self.cm_combo_box.currentText()].cavities[ int(self.cav_combo_box.currentText())] - self.x_data = [] - self.y_data = [] self.num_of_faults = [] self.num_of_invalids = [] + self.y_data = [] start = self.start_selector.dateTime().toPyDateTime() end = self.end_selector.dateTime().toPyDateTime() - print(start, end) - # Ex. result is a dictionary with key=fault pv string, value=FaultCounter(fault_count=0, ok_count=1, invalid_count=0) result: Dict[str, FaultCounter] = cavity.get_fault_counts( start, end ) + for tlc, counter_obj in result.items(): - self.x_data.append(tlc) # x axis - self.y_data.append(counter_obj.sum_fault_count) # y axis - self.num_of_faults.append(counter_obj.fault_count) - self.num_of_invalids.append(counter_obj.invalid_count) + if REMOVE_POT == True and tlc == 'POT': + continue + else: + self.y_data.append(tlc) + self.num_of_faults.append(counter_obj.fault_count) + self.num_of_invalids.append(counter_obj.invalid_count) print(tlc, counter_obj.fault_count, counter_obj.invalid_count) def update_plot(self): @@ -97,18 +105,30 @@ def update_plot(self): self.get_data() ticks = [] - x_vals_ints = [] - for idx, x_val in enumerate(self.x_data): - ticks.append((idx + 1, x_val)) - x_vals_ints.append(idx + 1) + y_vals_ints = [] + for idy, y_val in enumerate(self.y_data): + ticks.append((idy, y_val)) + y_vals_ints.append(idy) # Create pyqt5graph bar graph for faults, then stack invalid faults on same bars - bargraph = pg.BarGraphItem(x0=0, y=x_vals_ints, height=0.6, width=self.num_of_faults, brush=RED_FILL_COLOR) + bargraph = pg.BarGraphItem(x0=0, y=y_vals_ints, height=0.6, width=self.num_of_faults, brush=RED_FILL_COLOR) self.plot_window.addItem(bargraph) - bargraph = pg.BarGraphItem(x0=self.num_of_faults, y=x_vals_ints, height=0.6, width=self.num_of_invalids, + bargraph = pg.BarGraphItem(x0=self.num_of_faults, y=y_vals_ints, height=0.6, width=self.num_of_invalids, brush=PURPLE_FILL_COLOR) ax = self.plot_window.getAxis("left") ax.setTicks([ticks]) self.plot_window.showGrid(x=True, y=False, alpha=0.6) self.plot_window.addItem(bargraph) + + def removePOT(self, REMOVE_POT_FLAG): + if self.pot_checkbox.isChecked(): + REMOVE_POT_FLAG = True + print("Remove POT faults") + self.pot_checkbox.setText("POT faults removed, uncheck to include them again") + return (REMOVE_POT_FLAG) + else: + REMOVE_POT_FLAG = False + print("Not checked") + self.pot_checkbox.setText("Check to remove POT fault counts from plot") + return (REMOVE_POT_FLAG) diff --git a/bar_chart_display.py b/bar_chart_display.py index 7b480ee..7a467a8 100644 --- a/bar_chart_display.py +++ b/bar_chart_display.py @@ -19,34 +19,24 @@ def __init__(self, parent=None, args=None): self.setLayout(vertLayout_Form) - # TODO Remove these hardcoded x_vals and y_vals - x_vals = ['OFF', 'PZO', 'MGT', 'AOT'] - y_vals_faults = [1, 6, 2, 1] - y_vals_invalid = [10, 11, 12, 1] - x_vals_ints = [] + # TODO Remove these hardcoded x_vals and y_data + x_vals_faults = [2, 4, 6, 8] + x_vals_invalid = [10, 12, 14, 16] + + y_data = ['OFF', 'PZO', 'MGT', 'AOT'] ticks = [] - for idx, x_val in enumerate(x_vals): - ticks.append((idx, x_val)) - x_vals_ints.append(idx) + y_vals_ints = [] + for idy, y_val in enumerate(y_data): + ticks.append((idy, y_val)) + y_vals_ints.append(idy) # Attempting to stack bar chart - print(type(GREEN_FILL_COLOR)) - bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals_faults, width=0.6, brush=GREEN_FILL_COLOR) + bargraph = pg.BarGraphItem(x0=0, y=y_vals_ints, height=0.6, width=x_vals_faults, brush=GREEN_FILL_COLOR) self.plot_window.addItem(bargraph) - bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals_invalid, y0=y_vals_faults, width=0.6, brush='b') + bargraph = pg.BarGraphItem(x0=x_vals_faults, y=y_vals_ints, height=0.6, width=x_vals_invalid, brush='b') self.plot_window.addItem(bargraph) - ''' - # Create pyqt5graph bar graph item with green bars - bargraph = pg.BarGraphItem(x=x_vals_ints, height=y_vals_faults, width=0.6, brush='g') - # bargraph = pg.BarGraphItem(x0=0, y=x_vals_ints, height=0.6, width=y_vals, brush='b') - - # ax = self.plot_window.getAxis('left') - ax = self.plot_window.getAxis('bottom') + ax = self.plot_window.getAxis('left') ax.setTicks([ticks]) self.plot_window.showGrid(x=False, y=True, alpha=0.6) - - # Add bargraph to plot window - self.plot_window.addItem(bargraph) - ''' From b398b35a7d84799efad98fb6de18e26d97d2a2b9 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Tue, 3 Sep 2024 16:47:39 -0700 Subject: [PATCH 17/23] Can use checkbox to remove POT fault counts from bar chart --- backend/archive_data.py | 31 +++++++++------------ backend/check_box.py | 60 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 backend/check_box.py diff --git a/backend/archive_data.py b/backend/archive_data.py index 84097dd..80f21e2 100644 --- a/backend/archive_data.py +++ b/backend/archive_data.py @@ -1,6 +1,14 @@ import pyqtgraph as pg from PyQt5.QtCore import QDateTime -from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QComboBox, QDateTimeEdit, QPushButton, QLabel, QCheckBox +from PyQt5.QtWidgets import ( + QVBoxLayout, + QHBoxLayout, + QComboBox, + QDateTimeEdit, + QPushButton, + QLabel, + QCheckBox +) from pydm import Display from typing import Dict @@ -48,9 +56,7 @@ def __init__(self): self.start_selector.setDateTime(intermediate_time) self.end_selector.setDateTime(end_date_time) - REMOVE_POT = False self.pot_checkbox = QCheckBox(text="Check to remove POT fault counts from plot") - self.pot_checkbox.stateChanged.connect(self.removePOT, REMOVE_POT) self.plot_button = QPushButton() self.plot_button.setText("Update Bar Chart") @@ -86,19 +92,20 @@ def get_data(self): start = self.start_selector.dateTime().toPyDateTime() end = self.end_selector.dateTime().toPyDateTime() - # Ex. result is a dictionary with key=fault pv string, value=FaultCounter(fault_count=0, ok_count=1, invalid_count=0) + # Ex. result is a dictionary with: + # Ex. key = fault pv string + # Ex. value = FaultCounter(fault_count=0, ok_count=1, invalid_count=0) result: Dict[str, FaultCounter] = cavity.get_fault_counts( start, end ) for tlc, counter_obj in result.items(): - if REMOVE_POT == True and tlc == 'POT': + if self.pot_checkbox.isChecked() and tlc == 'POT': continue else: self.y_data.append(tlc) self.num_of_faults.append(counter_obj.fault_count) self.num_of_invalids.append(counter_obj.invalid_count) - print(tlc, counter_obj.fault_count, counter_obj.invalid_count) def update_plot(self): self.plot_window.clear() @@ -120,15 +127,3 @@ def update_plot(self): ax.setTicks([ticks]) self.plot_window.showGrid(x=True, y=False, alpha=0.6) self.plot_window.addItem(bargraph) - - def removePOT(self, REMOVE_POT_FLAG): - if self.pot_checkbox.isChecked(): - REMOVE_POT_FLAG = True - print("Remove POT faults") - self.pot_checkbox.setText("POT faults removed, uncheck to include them again") - return (REMOVE_POT_FLAG) - else: - REMOVE_POT_FLAG = False - print("Not checked") - self.pot_checkbox.setText("Check to remove POT fault counts from plot") - return (REMOVE_POT_FLAG) diff --git a/backend/check_box.py b/backend/check_box.py new file mode 100644 index 0000000..9f2b739 --- /dev/null +++ b/backend/check_box.py @@ -0,0 +1,60 @@ +import pyqtgraph as pg +from PyQt5.QtWidgets import QVBoxLayout, QCheckBox, QPushButton +from pydm import Display + + +class MakeGui(Display): + def __init__(self): + super().__init__() + + main_v_layout = QVBoxLayout() + self.setLayout(main_v_layout) + + self.pot_checkbox = QCheckBox(text="Check to remove POT fault counts from plot") + # self.pot_checkbox.stateChanged.connect(self.removePOT) + + self.update_button = QPushButton() + self.update_button.setText("Update plot") + + self.plot_window = pg.plot() + + main_v_layout.addWidget(self.pot_checkbox) + main_v_layout.addWidget(self.update_button) + main_v_layout.addWidget(self.plot_window) + + self.update_button.clicked.connect(self.update_plot) + + def update_plot(self): + self.plot_window.clear() + + fault_count = [2, 15, 4, 3] + + y_data = ['OFF', 'POT', 'MGT', 'AOT'] + + if self.pot_checkbox.isChecked(): + y_data.remove('POT') + fault_count.remove(15) + + ticks = [] + y_vals_ints = [] + for idy, y_val in enumerate(y_data): + ticks.append((idy, y_val)) + y_vals_ints.append(idy) + + bargraph = pg.BarGraphItem(x0=0, y=y_vals_ints, height=0.6, width=fault_count, brush='b') + self.plot_window.addItem(bargraph) + + ax = self.plot_window.getAxis('left') + ax.setTicks([ticks]) + self.plot_window.showGrid(x=False, y=True, alpha=0.6) + + ''' + def removePOT(self): + if self.pot_checkbox.isChecked(): + print("Remove POT faults") + self.pot_checkbox.setText("POT faults removed, uncheck to include them again") + else: + print("Not checked") + self.pot_checkbox.setText("Check to remove POT fault counts from plot") + + ''' From 7c99fe5751f021f52f8a8e91240283d3169dc303 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Tue, 3 Sep 2024 17:11:20 -0700 Subject: [PATCH 18/23] Removed extraneous files --- backend/check_box.py | 60 -------------------------------------------- bar_chart_display.py | 42 ------------------------------- 2 files changed, 102 deletions(-) delete mode 100644 backend/check_box.py delete mode 100644 bar_chart_display.py diff --git a/backend/check_box.py b/backend/check_box.py deleted file mode 100644 index 9f2b739..0000000 --- a/backend/check_box.py +++ /dev/null @@ -1,60 +0,0 @@ -import pyqtgraph as pg -from PyQt5.QtWidgets import QVBoxLayout, QCheckBox, QPushButton -from pydm import Display - - -class MakeGui(Display): - def __init__(self): - super().__init__() - - main_v_layout = QVBoxLayout() - self.setLayout(main_v_layout) - - self.pot_checkbox = QCheckBox(text="Check to remove POT fault counts from plot") - # self.pot_checkbox.stateChanged.connect(self.removePOT) - - self.update_button = QPushButton() - self.update_button.setText("Update plot") - - self.plot_window = pg.plot() - - main_v_layout.addWidget(self.pot_checkbox) - main_v_layout.addWidget(self.update_button) - main_v_layout.addWidget(self.plot_window) - - self.update_button.clicked.connect(self.update_plot) - - def update_plot(self): - self.plot_window.clear() - - fault_count = [2, 15, 4, 3] - - y_data = ['OFF', 'POT', 'MGT', 'AOT'] - - if self.pot_checkbox.isChecked(): - y_data.remove('POT') - fault_count.remove(15) - - ticks = [] - y_vals_ints = [] - for idy, y_val in enumerate(y_data): - ticks.append((idy, y_val)) - y_vals_ints.append(idy) - - bargraph = pg.BarGraphItem(x0=0, y=y_vals_ints, height=0.6, width=fault_count, brush='b') - self.plot_window.addItem(bargraph) - - ax = self.plot_window.getAxis('left') - ax.setTicks([ticks]) - self.plot_window.showGrid(x=False, y=True, alpha=0.6) - - ''' - def removePOT(self): - if self.pot_checkbox.isChecked(): - print("Remove POT faults") - self.pot_checkbox.setText("POT faults removed, uncheck to include them again") - else: - print("Not checked") - self.pot_checkbox.setText("Check to remove POT fault counts from plot") - - ''' diff --git a/bar_chart_display.py b/bar_chart_display.py deleted file mode 100644 index 7a467a8..0000000 --- a/bar_chart_display.py +++ /dev/null @@ -1,42 +0,0 @@ -import pyqtgraph as pg -from PyQt5.QtWidgets import QVBoxLayout -# from PyQt5.QtChart import QChart, QChartView, QBarSet, QPercentBarSeries, QBarCategoryAxis -from pydm import Display - -from frontend.cavity_widget import GREEN_FILL_COLOR - - -class BarChart(Display): - def __init__(self, parent=None, args=None): - super().__init__(parent, args) - - self.setWindowTitle("Bar Chart") - vertLayout_Form = QVBoxLayout() - - # Make plot window and add it to the vert layout - self.plot_window = pg.plot() - vertLayout_Form.addWidget(self.plot_window) - - self.setLayout(vertLayout_Form) - - # TODO Remove these hardcoded x_vals and y_data - x_vals_faults = [2, 4, 6, 8] - x_vals_invalid = [10, 12, 14, 16] - - y_data = ['OFF', 'PZO', 'MGT', 'AOT'] - - ticks = [] - y_vals_ints = [] - for idy, y_val in enumerate(y_data): - ticks.append((idy, y_val)) - y_vals_ints.append(idy) - - # Attempting to stack bar chart - bargraph = pg.BarGraphItem(x0=0, y=y_vals_ints, height=0.6, width=x_vals_faults, brush=GREEN_FILL_COLOR) - self.plot_window.addItem(bargraph) - bargraph = pg.BarGraphItem(x0=x_vals_faults, y=y_vals_ints, height=0.6, width=x_vals_invalid, brush='b') - self.plot_window.addItem(bargraph) - - ax = self.plot_window.getAxis('left') - ax.setTicks([ticks]) - self.plot_window.showGrid(x=False, y=True, alpha=0.6) From 5e0f2ca15085b36fcda8a7054c48c774e203f28d Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Wed, 4 Sep 2024 10:09:32 -0700 Subject: [PATCH 19/23] Renamed fault count display file --- backend/{archive_data.py => fault_count_display.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename backend/{archive_data.py => fault_count_display.py} (98%) diff --git a/backend/archive_data.py b/backend/fault_count_display.py similarity index 98% rename from backend/archive_data.py rename to backend/fault_count_display.py index 80f21e2..7508b7d 100644 --- a/backend/archive_data.py +++ b/backend/fault_count_display.py @@ -20,10 +20,10 @@ DISPLAY_MACHINE = Machine(cavity_class=BackendCavity) -class FaultCounter(Display): +class FaultCountDisplay(Display): def __init__(self): super().__init__() - self.setWindowTitle("Fault Counter") + self.setWindowTitle("Fault Count Display") main_v_layout = QVBoxLayout() input_h_layout = QHBoxLayout() From c71c6599af5467a223b515f7eb110a72f39117d1 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Wed, 4 Sep 2024 11:42:23 -0700 Subject: [PATCH 20/23] Addressed comments in PR --- backend/backend_cavity.py | 4 ++++ backend/fault.py | 10 ++++------ display.py | 0 utils/utils.py | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) delete mode 100644 display.py diff --git a/backend/backend_cavity.py b/backend/backend_cavity.py index 9daa0d9..497344e 100644 --- a/backend/backend_cavity.py +++ b/backend/backend_cavity.py @@ -123,6 +123,10 @@ def get_fault_counts( ) -> Dict[str, FaultCounter]: result: Dict[str, FaultCounter] = defaultdict(FaultCounter) + # Using max function to get the maximum fault or invalid count for duplicate TLCs + # i.e. MGT tlc has three PVs associated with it (X, Y, and Q) but we + # only want the fault and invalid count for whichever PV had the + # greatest number of faults for fault in self.faults.values(): result[fault.tlc] = max(result[fault.tlc], fault.get_fault_count_over_time_range( start_time=start_time, end_time=end_time diff --git a/backend/fault.py b/backend/fault.py index 074f715..da30f40 100644 --- a/backend/fault.py +++ b/backend/fault.py @@ -90,19 +90,19 @@ class AlarmSeverity(DefaultIntEnum): if obj.severity == 3 or obj.status is None: raise PVInvalidError(self.pv.pvname) + # "is not None" means it has a value. + # self.ok_value = value stated in spreadsheet if self.ok_value is not None: - # "is not None" means it has a value. It is not a blank, no value - # ok_value = value stated in spreadsheet # obj.value = actual reading value from pv - return obj.val != self.ok_value # Does the actual value NOT match the spreadsheet value? # If they don't match, return TRUE # return "FALSE" means is_okay, not faulted + return obj.val != self.ok_value elif self.fault_value is not None: - return obj.val == self.fault_value # return "FALSE" means not faulted # return "TRUE" means faulted + return obj.val == self.fault_value else: print(self) @@ -137,6 +137,4 @@ def get_fault_count_over_time_range( except PVInvalidError: counter.invalid_count += 1 - # print("PV: ", self.pv.pvname, "\tCounter:", counter, counter.fault_count, counter.ok_count, - # counter.invalid_count) return counter diff --git a/display.py b/display.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils/utils.py b/utils/utils.py index df84c3b..11b5ce3 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -2,7 +2,7 @@ from csv import DictReader from typing import Dict, List -DEBUG = True +DEBUG = False BACKEND_SLEEP_TIME = 10 STATUS_SUFFIX = "CUDSTATUS" From 1d05d381d07e9d1e1f78c5b1181663dac1704685 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Thu, 5 Sep 2024 13:27:14 -0700 Subject: [PATCH 21/23] Cleaned up comments --- backend/fault.py | 13 ++++++------- backend/fault_count_display.py | 8 +++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/backend/fault.py b/backend/fault.py index da30f40..62421ad 100644 --- a/backend/fault.py +++ b/backend/fault.py @@ -75,7 +75,8 @@ def __init__( self.pv: PV = PV(pv, connection_timeout=PV_TIMEOUT) def is_currently_faulted(self): - # returns "FALSE" if not faulted. aka Are you faulted? FALSE! All good here + # returns "TRUE" if faulted + # returns "FALSE" if not faulted return self.is_faulted(self.pv) def is_faulted(self, obj: Union[PV, ArchiverValue]): @@ -90,18 +91,16 @@ class AlarmSeverity(DefaultIntEnum): if obj.severity == 3 or obj.status is None: raise PVInvalidError(self.pv.pvname) - # "is not None" means it has a value. - # self.ok_value = value stated in spreadsheet + # self.ok_value is the value stated in spreadsheet + # obj.value is the actual reading value from pv if self.ok_value is not None: - # obj.value = actual reading value from pv - # Does the actual value NOT match the spreadsheet value? - # If they don't match, return TRUE + # return "TRUE" means they do NOT match # return "FALSE" means is_okay, not faulted return obj.val != self.ok_value elif self.fault_value is not None: - # return "FALSE" means not faulted # return "TRUE" means faulted + # return "FALSE" means not faulted return obj.val == self.fault_value else: diff --git a/backend/fault_count_display.py b/backend/fault_count_display.py index 7508b7d..68ce790 100644 --- a/backend/fault_count_display.py +++ b/backend/fault_count_display.py @@ -92,9 +92,11 @@ def get_data(self): start = self.start_selector.dateTime().toPyDateTime() end = self.end_selector.dateTime().toPyDateTime() - # Ex. result is a dictionary with: - # Ex. key = fault pv string - # Ex. value = FaultCounter(fault_count=0, ok_count=1, invalid_count=0) + """ + result is a dictionary with: + key = fault pv string + value = FaultCounter(fault_count=0, ok_count=1, invalid_count=0) <-- Example + """ result: Dict[str, FaultCounter] = cavity.get_fault_counts( start, end ) From a0ffd1fc994597b7d6dbc95f84c799fea6702150 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Thu, 5 Sep 2024 13:34:12 -0700 Subject: [PATCH 22/23] Moved fault_count_display.py in to frontend directory --- {backend => frontend}/fault_count_display.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {backend => frontend}/fault_count_display.py (100%) diff --git a/backend/fault_count_display.py b/frontend/fault_count_display.py similarity index 100% rename from backend/fault_count_display.py rename to frontend/fault_count_display.py From 0b4bddea0c22dffaad90e368aa3d35129299a514 Mon Sep 17 00:00:00 2001 From: Derikka Bisi Date: Mon, 16 Sep 2024 13:50:14 -0700 Subject: [PATCH 23/23] Copied changes from cavityDisplay repo to sc_linac_physics repo; Added Corrective Action column to TLC decoder --- backend/backend_cavity.py | 10 +++++--- frontend/decoder.py | 54 +++++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/backend/backend_cavity.py b/backend/backend_cavity.py index 497344e..f25e101 100644 --- a/backend/backend_cavity.py +++ b/backend/backend_cavity.py @@ -123,10 +123,12 @@ def get_fault_counts( ) -> Dict[str, FaultCounter]: result: Dict[str, FaultCounter] = defaultdict(FaultCounter) - # Using max function to get the maximum fault or invalid count for duplicate TLCs - # i.e. MGT tlc has three PVs associated with it (X, Y, and Q) but we - # only want the fault and invalid count for whichever PV had the - # greatest number of faults + """ + Using max function to get the maximum fault or invalid count for duplicate TLCs + i.e. MGT tlc has three PVs associated with it (X, Y, and Q) but we + only want the fault and invalid count for whichever PV had the + greatest number of faults + """ for fault in self.faults.values(): result[fault.tlc] = max(result[fault.tlc], fault.get_fault_count_over_time_range( start_time=start_time, end_time=end_time diff --git a/frontend/decoder.py b/frontend/decoder.py index 076212a..b6a6b8a 100644 --- a/frontend/decoder.py +++ b/frontend/decoder.py @@ -1,7 +1,6 @@ -import sys from collections import OrderedDict -from dataclasses import dataclass +import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import ( QHBoxLayout, @@ -13,6 +12,7 @@ QApplication, QAbstractScrollArea, ) +from dataclasses import dataclass from pydm import Display from utils.utils import parse_csv @@ -23,8 +23,9 @@ @dataclass class Row: tlc: str - longDesc: str - genShortDesc: str + long_desc: str + gen_short_desc: str + corrective_action: str class DecoderDisplay(Display): @@ -35,8 +36,9 @@ def __init__(self, parent=None, args=None, macros=None): tlc = faultRowDict["Three Letter Code"] rows[tlc] = Row( tlc=tlc, - longDesc=faultRowDict["Long Description"], - genShortDesc=faultRowDict["Generic Short Description for Decoder"], + long_desc=faultRowDict["Long Description"], + gen_short_desc=faultRowDict["Generic Short Description for Decoder"], + corrective_action=faultRowDict["Recommended Corrective Actions"] ) sorted_fault_rows = OrderedDict( @@ -62,52 +64,66 @@ def __init__(self, parent=None, args=None, macros=None): # Long description header header_layout = QHBoxLayout() description_header_label = QLabel("Description") - description_header_label.setMinimumSize(200, 30) + description_header_label.setMinimumSize(100, 30) + description_header_label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred) description_header_label.setStyleSheet("text-decoration: underline") # Name (aka short description) header name_header_label = QLabel("Name") - name_header_label.setMinimumSize(200, 30) - name_header_label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) + name_header_label.setMinimumSize(100, 30) + name_header_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) name_header_label.setStyleSheet("text-decoration: underline") # Three-Letter Code header code_header_label = QLabel("Code") code_header_label.setMinimumSize(30, 30) - code_header_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) + code_header_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) code_header_label.setStyleSheet("text-decoration: underline") + # Corrective Action header + action_header_label = QLabel("Corrective Action") + action_header_label.setMinimumSize(100, 30) + action_header_label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred) + action_header_label.setStyleSheet("text-decoration: underline") + header_layout.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) header_layout.addWidget(code_header_label) header_layout.addWidget(name_header_label) - header_layout.addWidget(description_header_label) + header_layout.addWidget(description_header_label, 2) + header_layout.addWidget(action_header_label, 2) header_layout.setSpacing(50) scroll_area_layout.addLayout(header_layout) for row in sorted_fault_rows.values(): horizontal_layout = QHBoxLayout() - description_label = QLabel(row.longDesc) - description_label.setMinimumSize(300, 50) + description_label = QLabel(row.long_desc) + description_label.setMinimumSize(100, 50) description_label.setSizePolicy( - QSizePolicy.MinimumExpanding, QSizePolicy.Minimum + QSizePolicy.Minimum, QSizePolicy.Minimum ) description_label.setWordWrap(True) code_label = QLabel(row.tlc) code_label.setMinimumSize(30, 30) - code_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) + code_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) name_label = QLabel() - name_label.setText(row.genShortDesc) - name_label.setMinimumSize(200, 50) - name_label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) + name_label.setText(row.gen_short_desc) + name_label.setMinimumSize(100, 50) + name_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) name_label.setWordWrap(True) + action_label = QLabel(row.corrective_action) + action_label.setMinimumSize(100, 50) + action_label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) + action_label.setWordWrap(True) + horizontal_layout.addWidget(code_label) horizontal_layout.addWidget(name_label) - horizontal_layout.addWidget(description_label) + horizontal_layout.addWidget(description_label, 2) + horizontal_layout.addWidget(action_label, 2) horizontal_layout.setSpacing(50) horizontal_layout.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)