diff --git a/params/operator_params.json b/params/operator_params.json index 5a96d09..f1666e2 100644 --- a/params/operator_params.json +++ b/params/operator_params.json @@ -1,16 +1,226 @@ { - "dist_open_start_1": 0.005, - "dist_open_start_2": 0.005, - "dist_open_after_1": 0.006, - "dist_open_after_2": 0.006, - "dist_open_end_1": 0.01, - "dist_open_end_2": 0.05, - "dist_close_end_1": 0.005, - "dist_close_end_2": 0.005, - "time_wielding": 1, - "time_command": 0.0, - "time_robot_movement": 0.2, - "object_thickness": 0.0045, - "force_target": 5000, - "force_capture": 500 + "dist_open_start_1": [ + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005 + ], + "dist_open_start_2": [ + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005 + ], + "dist_open_after_1": [ + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006 + ], + "dist_open_after_2": [ + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006, + 0.006 + ], + "dist_open_end_1": [ + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01, + 0.01 + ], + "dist_open_end_2": [ + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + 0.05, + 0.05 + ], + "dist_close_end_1": [ + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005 + ], + "dist_close_end_2": [ + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005, + 0.005 + ], + "time_wielding": [ + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0 + ], + "time_command": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "time_robot_movement": [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ], + "object_thickness": [ + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045, + 0.0045 + ], + "force_target": [ + 4000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0, + 5000.0 + ], + "force_capture": [ + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0 + ] } \ No newline at end of file diff --git a/params/system_params.json b/params/system_params.json index b34adee..5060aa8 100644 --- a/params/system_params.json +++ b/params/system_params.json @@ -1,22 +1,22 @@ { - "trace_storage_path": "D:/downloads/a22", - "monitor_update_period": 100, - "a_max_1": 5.41, - "v_max_1": 0.278, - "a_max_2": 35.81, - "v_max_2": 0.7, - "mass_1": 270, - "mass_2": 1, - "k_hardness_1": 2148570, - "k_hardness_2": 0, - "torque_max_1": 20, - "torque_max_2": 0, - "transmission_ratio_1": 0.00125, - "transmission_ratio_2": 1, - "position_start_1": 0.08, - "position_start_2": 0.08, - "k_prop": 0.05, - "time_capture": 100000, - "UML_time_scaler": 1000 + "trace_storage_path": ["D:/downloads/a22"], + "monitor_update_period": [100], + "a_max_1": [5.41], + "v_max_1": [0.278], + "a_max_2": [35.81], + "v_max_2": [0.7], + "mass_1": [270], + "mass_2": [1], + "k_hardness_1": [2148570], + "k_hardness_2": [0], + "torque_max_1": [20], + "torque_max_2": [0], + "transmission_ratio_1": [0.00125], + "transmission_ratio_2": [1], + "position_start_1": [0.08], + "position_start_2": [0.08], + "k_prop": [0.05], + "time_capture": [100000], + "UML_time_scaler": [1000] } \ No newline at end of file diff --git a/src/__pycache__/main.cpython-310.pyc b/src/__pycache__/main.cpython-310.pyc index 443fd68..73ed599 100644 Binary files a/src/__pycache__/main.cpython-310.pyc and b/src/__pycache__/main.cpython-310.pyc differ diff --git a/src/controller/__pycache__/mediator.cpython-310.pyc b/src/controller/__pycache__/mediator.cpython-310.pyc index 5725fb2..32d6421 100644 Binary files a/src/controller/__pycache__/mediator.cpython-310.pyc and b/src/controller/__pycache__/mediator.cpython-310.pyc differ diff --git a/src/controller/__pycache__/monitor.cpython-310.pyc b/src/controller/__pycache__/monitor.cpython-310.pyc index 77287fb..e876406 100644 Binary files a/src/controller/__pycache__/monitor.cpython-310.pyc and b/src/controller/__pycache__/monitor.cpython-310.pyc differ diff --git a/src/controller/__pycache__/passportFormer.cpython-310.pyc b/src/controller/__pycache__/passportFormer.cpython-310.pyc new file mode 100644 index 0000000..6d74626 Binary files /dev/null and b/src/controller/__pycache__/passportFormer.cpython-310.pyc differ diff --git a/src/controller/mediator.py b/src/controller/mediator.py index b32edd0..d7cd6ef 100644 --- a/src/controller/mediator.py +++ b/src/controller/mediator.py @@ -3,18 +3,21 @@ import pandas as pd from typing import Union from PyQt5.QtWidgets import QWidget -from src.utils.base.base import BaseMediator, BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget +from src.utils.base.base import BaseMediator, BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget, BasePointPassportFormer class Mediator(BaseMediator): def notify(self, - source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget], - data: Union[list[str], list[pd.DataFrame], list[QWidget]]): + source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePointPassportFormer, BasePlotWidget], + data: Union[list[str], list[pd.DataFrame], list[list], list[QWidget]]): if issubclass(source.__class__, BaseDirectoryMonitor): self._converter.convert_data(data) if issubclass(source.__class__, BaseDataConverter): + self._passportFormer.form_passports(data) + + if issubclass(source.__class__, BasePointPassportFormer): self._plot.build(data) if issubclass(source.__class__, BasePlotWidget): @@ -22,7 +25,7 @@ class Mediator(BaseMediator): def push_settings(self, settings: list[dict]): self._monitor.update_settings(settings) - self._plot.update_settings(settings) + self._passportFormer.update_settings(settings) self._monitor.force_all_dir() diff --git a/src/controller/monitor.py b/src/controller/monitor.py index 4e24920..bb3f9fc 100644 --- a/src/controller/monitor.py +++ b/src/controller/monitor.py @@ -29,8 +29,8 @@ class DirectoryMonitor(BaseDirectoryMonitor): def update_settings(self, data: list[dict]) -> None: self.stop() operator_params, system_params = data - self._directory_path = system_params['trace_storage_path'] - self._update_time = system_params['monitor_update_period'] + self._directory_path = system_params['trace_storage_path'][0] + self._update_time = system_params['monitor_update_period'][0] self._init_state() self.start() diff --git a/src/controller/passportFormer.py b/src/controller/passportFormer.py new file mode 100644 index 0000000..4561aa8 --- /dev/null +++ b/src/controller/passportFormer.py @@ -0,0 +1,63 @@ +from src.utils.base.base import BasePointPassportFormer, BaseIdealDataBuilder +import pandas as pd + +class idealDataBuilder(BaseIdealDataBuilder): + def get_closingDF(self) -> pd.DataFrame: + return self._get_data(self.Ts['tclose'], self.calcPhaseClose) + + def get_compressionDF(self) -> pd.DataFrame: + return self._get_data(self.Ts['tgrow'], self.calcPhaseGrow) + + def get_openingDF(self) -> pd.DataFrame: + return self._get_data(self.getMarkOpen(), self.calcPhaseOpen) + + def get_oncomingDF(self) -> pd.DataFrame: + return self._get_data(self.Ts['tmovement'], self.calcPhaseMovement) + + def get_weldingDF(self) -> pd.DataFrame: + data = [] + X1, X2, V1, V2, F = self.calcPhaseGrow(self.Ts['tgrow']) + data.append({"time":0, "Posicion FE":X1,"Posicion ME":X2, "Rotor Speed FE":V1, "Rotor Speed ME":V2, "Force":F}) + data.append({"time":self.welding_time, "Posicion FE":X1,"Posicion ME":X2, "Rotor Speed FE":V1, "Rotor Speed ME":V2, "Force":F}) + return pd.DataFrame(data) + + def get_ideal_timings(self) -> list[float]: + data = self.Ts + ideal_timings = [data['tclose'], data['tgrow'], self.welding_time, self.getMarkOpen()] # TODO: add data['tmovement'], Oncoming не учитывается в производительности + return ideal_timings + +class PassportFormer(BasePointPassportFormer): + + def form_passports(self, data: list[pd.DataFrame]) -> list[list[pd.DataFrame, dict, list]]: + return_data = [self._build_passports_pocket(dataframe) for dataframe in data] + self._mediator.notify(self, return_data) + + + def _build_passports_pocket(self, dataframe: pd.DataFrame) -> list[pd.DataFrame, dict, list]: + passports_pocket = [] + events, point_quantity = self._filter_events(dataframe["time"], dataframe) + system_settings = {key: value[0] for key, value in self._params[1].items()} + + for i in range(0, point_quantity): + if not dataframe["time"].isna().all(): + operator_settings = {} + for key, value in self._params[0].items(): + if len(value) > i: + operator_settings[key] = value[i] + else: + operator_settings[key] = value[0] + params_list = [operator_settings, system_settings] + ideal_data = self._build_ideal_data(idealDataBuilder=idealDataBuilder, params=params_list) + + if i < point_quantity-1: + cut_time = events[self._stages[0]][0][i+1] + frame = dataframe[dataframe["time"] < cut_time] + dataframe = dataframe[dataframe["time"] >= cut_time] + else: + frame = dataframe + point_events = {key: [value[0][i], value[1][i]] for key, value in events.items()} + passports_pocket.append([frame, ideal_data, point_events]) + return passports_pocket + + def update_settings(self, params: list[dict, dict]): + self._params = params \ No newline at end of file diff --git a/src/gui/__pycache__/mainGui.cpython-310.pyc b/src/gui/__pycache__/mainGui.cpython-310.pyc index d52d6d0..e2297de 100644 Binary files a/src/gui/__pycache__/mainGui.cpython-310.pyc and b/src/gui/__pycache__/mainGui.cpython-310.pyc differ diff --git a/src/gui/__pycache__/plotter.cpython-310.pyc b/src/gui/__pycache__/plotter.cpython-310.pyc index 603d3c5..ed41dee 100644 Binary files a/src/gui/__pycache__/plotter.cpython-310.pyc and b/src/gui/__pycache__/plotter.cpython-310.pyc differ diff --git a/src/gui/__pycache__/settings_window.cpython-310.pyc b/src/gui/__pycache__/settings_window.cpython-310.pyc index 5434731..76e27e9 100644 Binary files a/src/gui/__pycache__/settings_window.cpython-310.pyc and b/src/gui/__pycache__/settings_window.cpython-310.pyc differ diff --git a/src/gui/mainGui.py b/src/gui/mainGui.py index 8df989a..0f076aa 100644 --- a/src/gui/mainGui.py +++ b/src/gui/mainGui.py @@ -45,7 +45,7 @@ class MainWindow(BaseMainWindow): def keyPressEvent(self, a0): if a0.key() == Qt.Key_F5: - self.clear() + pass def _show_settings(self): self.operSettings.show() diff --git a/src/gui/plotter.py b/src/gui/plotter.py index 18e39dc..fb53772 100644 --- a/src/gui/plotter.py +++ b/src/gui/plotter.py @@ -5,34 +5,7 @@ import numpy as np from numpy import floating from typing import Optional, Any, NamedTuple -from src.utils.base.base import BasePlotWidget, BasePointPassportFormer, BaseIdealDataBuilder - - -class idealDataBuilder(BaseIdealDataBuilder): - def get_closingDF(self) -> pd.DataFrame: - return self._get_data(self.Ts['tclose'], self.calcPhaseClose) - - def get_compressionDF(self) -> pd.DataFrame: - return self._get_data(self.Ts['tgrow'], self.calcPhaseGrow) - - def get_openingDF(self) -> pd.DataFrame: - return self._get_data(self.getMarkOpen(), self.calcPhaseOpen) - - def get_oncomingDF(self) -> pd.DataFrame: - return self._get_data(self.Ts['tmovement'], self.calcPhaseMovement) - - def get_weldingDF(self) -> pd.DataFrame: - data = [] - X1, X2, V1, V2, F = self.calcPhaseGrow(self.Ts['tgrow']) - data.append({"time":0, "Posicion FE":X1,"Posicion ME":X2, "Rotor Speed FE":V1, "Rotor Speed ME":V2, "Force":F}) - data.append({"time":self.welding_time, "Posicion FE":X1,"Posicion ME":X2, "Rotor Speed FE":V1, "Rotor Speed ME":V2, "Force":F}) - return pd.DataFrame(data) - - def get_ideal_timings(self) -> list[float, float, float, float]: - data = self.Ts - ideal_timings = [data['tclose'], data['tgrow'], self.welding_time, self.getMarkOpen()] # TODO: add data['tmovement'], Oncoming не учитывается в производительности - return ideal_timings - +from src.utils.base.base import BasePlotWidget class ProcessStage(NamedTuple): mean_value: floating[Any] @@ -40,16 +13,15 @@ class ProcessStage(NamedTuple): finish_index: int -class PlotWidget(BasePlotWidget, BasePointPassportFormer): +class PlotWidget(BasePlotWidget): def _create_curve_ideal(self, - stage: str, - signal: str, + signal: str, + ideal_data: pd.DataFrame, start_timestamp: float, finish_timestamp: float) -> Optional[pg.PlotDataItem]: - data = self._stage_ideals[stage] if start_timestamp and finish_timestamp: - plot = pg.PlotDataItem(x=start_timestamp+data["time"], y=data[signal["name"]], pen=signal["pen"]) + plot = pg.PlotDataItem(x=start_timestamp+ideal_data["time"], y=ideal_data[signal["name"]], pen=signal["pen"]) return plot return None @@ -76,104 +48,109 @@ class PlotWidget(BasePlotWidget, BasePointPassportFormer): stage: str, dataframe: pd.DataFrame, signal_name: str) -> Optional[ProcessStage]: - if stage in self._stages: - stage_diff = np.diff(dataframe[stage]) - start_index = np.where(stage_diff == 1)[0] - finish_index = np.where(stage_diff == -1)[0] - - data = dataframe[signal_name] if signal_name in dataframe.columns.tolist() else [] - - if data.size and start_index.size: - start = start_index[0] - finish = finish_index[0] if finish_index.size else (len(data) - 1) - data_slice = data[start:finish] - mean = np.mean(data_slice) - return ProcessStage(mean_value=mean, start_index=int(start), finish_index=int(finish)) - return None - def _build_widget(self, dataframe: pd.DataFrame) -> QWidget: + stage_diff = np.diff(dataframe[stage]) + start_index = np.where(stage_diff == 1)[0] + finish_index = np.where(stage_diff == -1)[0] + + data = dataframe[signal_name] if signal_name in dataframe.columns.tolist() else [] + + if data.size and start_index.size: + start = start_index[0] + finish = finish_index[0] if finish_index.size else (len(data) - 1) + data_slice = data[start:finish] + mean = np.mean(data_slice) + return ProcessStage(mean_value=mean, start_index=int(start), finish_index=int(finish)) + return None + + def _build_widget(self, data: list[pd.DataFrame, dict, list]) -> QWidget: widget = QWidget() layout = QVBoxLayout() - time_axis = dataframe["time"] - dataframe_headers = dataframe.columns.tolist() - for channel, description in self._plt_channels.items(): + performance_list = [] + df_continuous = pd.DataFrame({}) plot_widget, legend = self._init_plot_widget(title=channel) - settings = description["Settings"] - if (settings["stages"] or settings["performance"]) and all([stage in dataframe_headers for stage in self._stages]): - events = self._filter_events(time_axis, dataframe) - point_quantity = len(events[self._clear_stage][0]) - if settings["stages"]: - for stage in self._stages: + + for dataframe, ideal_data, events in data: + df_continuous = pd.concat([df_continuous, dataframe], axis=0) + dataframe_headers = dataframe.columns.tolist() + stages = events.keys() + + if settings["stages"] and all([stage in dataframe_headers for stage in stages]): + for stage in stages: start_t, end_t = events[stage] - for i in range(len(start_t)): - region = self._create_stage_region(stage, start_t[i], end_t[i]) - if region: - plot_widget.addItem(region) - for signal in description["Ideal_signals"]: - ideal_plot = self._create_curve_ideal(stage, signal, start_t[i], end_t[i]) - if ideal_plot: - plot_widget.addItem(ideal_plot) + region = self._create_stage_region(stage, start_t, end_t) + if region: + plot_widget.addItem(region) + + if settings["ideals"]: + for stage in stages: + for signal in description["Ideal_signals"]: + curve = self._create_curve_ideal(signal, ideal_data[stage], events[stage][0], events[stage][1]) + if curve: + plot_widget.addItem(curve) if settings["performance"]: - ideal_delta = self._opt.get_cycle_time() - delta = np.zeros(point_quantity) - for stage in self._stages: - try: - start_stage, stop_stage = events[stage] - delta += np.array(stop_stage)-np.array(start_stage) - except: print("Signal ", stage, " is abnormal..." ) - performance_list = ideal_delta/delta*100 - performance_label = QLabel(f"Performance: best = {performance_list.max()} %, worse = {performance_list.min()} %, average = {performance_list.mean()}") - layout.addWidget(performance_label) + ideal_delta = ideal_data["Ideal cycle"] + delta = 0 + for stage in stages: + delta += events[stage][1] - events[stage][0] + performance = ideal_delta/delta*100 + performance_list.append(performance) - if settings["zoom"]: - if max(time_axis) < 5.0: - stages = [self.get_stage_info("Welding", - dataframe, - signal["name"]) for signal in description["Real_signals"]] - if stages: - means_raw = [stage.mean_value for stage in stages] - mean = max(means_raw) - start = time_axis[stages[0].start_index] - finish = time_axis[stages[0].finish_index] + if settings["zoom"]: + pass + """if max(time_axis) < 5.0: + stages = [self.get_stage_info("Welding", + dataframe, + signal["name"]) for signal in description["Real_signals"]] + if stages: + means_raw = [stage.mean_value for stage in stages] + mean = max(means_raw) + start = time_axis[stages[0].start_index] + finish = time_axis[stages[0].finish_index] - overshoot = pg.BarGraphItem(x0=0, - y0=mean - mean * 0.05, - height=mean * 0.05 * 2, - width=start, + overshoot = pg.BarGraphItem(x0=0, + y0=mean - mean * 0.05, + height=mean * 0.05 * 2, + width=start, + brush=pg.mkBrush([0, 250, 0, 100])) + plot_widget.addItem(overshoot) + + stable = pg.BarGraphItem(x0=start, + y0=mean - mean * 0.015, + height=mean * 0.015 * 2, + width=finish - start, brush=pg.mkBrush([0, 250, 0, 100])) - plot_widget.addItem(overshoot) + plot_widget.addItem(stable) - stable = pg.BarGraphItem(x0=start, - y0=mean - mean * 0.015, - height=mean * 0.015 * 2, - width=finish - start, - brush=pg.mkBrush([0, 250, 0, 100])) - plot_widget.addItem(stable) + plot_widget.setYRange(mean - 260, mean + 260) + plot_widget.setInteractive(False) + else: + max_value = min([max(dataframe[signal["name"]]) for signal in description["Real_signals"]]) + region = pg.LinearRegionItem([max_value - max_value * 0.015, + max_value + max_value * 0.015], + movable=False, + orientation="horizontal") - plot_widget.setYRange(mean - 260, mean + 260) - plot_widget.setInteractive(False) - else: - max_value = min([max(dataframe[signal["name"]]) for signal in description["Real_signals"]]) - region = pg.LinearRegionItem([max_value - max_value * 0.015, - max_value + max_value * 0.015], - movable=False, - orientation="horizontal") - - region.setBrush(pg.mkBrush([0, 250, 0, 100])) - plot_widget.setYRange(max_value - 200, max_value + 200) - plot_widget.setXRange(3.5, 4.5) - plot_widget.addItem(region) - plot_widget.setInteractive(False) + region.setBrush(pg.mkBrush([0, 250, 0, 100])) + plot_widget.setYRange(max_value - 200, max_value + 200) + plot_widget.setXRange(3.5, 4.5) + plot_widget.addItem(region) + plot_widget.setInteractive(False)""" for signal in description["Real_signals"]: if signal["name"] in dataframe_headers: - plot = plot_widget.plot(time_axis, dataframe[signal["name"]], pen=signal["pen"]) + plot = plot_widget.plot(df_continuous["time"], df_continuous[signal["name"]], pen=signal["pen"]) legend.addItem(plot, signal["name"]) + if settings["performance"]: + performance_list = np.array(performance_list) + performance_label = QLabel(f"""Performance: best = {round(performance_list.max(),2)} %, worse = {round(performance_list.min(),2)} %, average = {round(performance_list.mean(),2)}%""") + layout.addWidget(performance_label) + layout.addWidget(plot_widget) widget.setLayout(layout) @@ -183,8 +160,5 @@ class PlotWidget(BasePlotWidget, BasePointPassportFormer): widgets = [self._build_widget(data_sample) for data_sample in data] self._mediator.notify(self, widgets) - def update_settings(self, params: list[dict]): - self._initIdealBuilder(idealDataBuilder=idealDataBuilder, params=params) - diff --git a/src/gui/settings_window.py b/src/gui/settings_window.py index c67ba93..cdda08e 100644 --- a/src/gui/settings_window.py +++ b/src/gui/settings_window.py @@ -1,55 +1,103 @@ import pyqtgraph as pg -from pyqtgraph.Qt import QtWidgets -from pyqtgraph.parametertree import Parameter, ParameterTree +from PyQt5.QtWidgets import QWidget, QTableWidget, QVBoxLayout, QTableWidgetItem, QLabel, QPushButton, QLineEdit, QHBoxLayout +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QIntValidator + from src.utils.json_tools import read_json, write_json from src.gui import qt_settings as qts -class settingsWindow(QtWidgets.QWidget): +class settingsWindow(QWidget): def __init__(self, path: str, name: str, upd_func): super(settingsWindow, self).__init__() - self.settingsPath = path - self.name = name - - self.data = {} - self.params = None + self._settingsPath = path + self._name = name + self._data = {} + self._upd_func = upd_func + self.load_settings() self._init_ui() - self.params.sigTreeStateChanged.connect(upd_func) def load_settings(self) -> None: - self.data = read_json(self.settingsPath) + self._data = read_json(self._settingsPath) def write_settings(self) -> None: - self.getParams() - write_json(self.settingsPath, self.data) + write_json(self._settingsPath, self._data) + + def getParams(self) -> dict: + return self._data - def _getTreeStructure(self) -> list: - params = [] - for key, value in self.data.items(): - params.append({'name': str(key), 'type': type(value).__name__, 'value': value}) - params.append({'name': 'Save', 'type': 'action'}) - return params def _init_ui(self) -> None: - temp = self._getTreeStructure() - self.params = Parameter.create(name=self.name, type='group', children=temp) - self.params.param('Save').sigActivated.connect(self.write_settings) + save_button = QPushButton() + restore_button = QPushButton() + save_button.setText("Save") + restore_button.setText("Restore") + self._num_points = QLineEdit() + self._num_points.setPlaceholderText("Enter the number of welding points") + self._num_points.setValidator(QIntValidator()) + control_layout = QHBoxLayout() + control_layout.addWidget(save_button) + control_layout.addWidget(restore_button) + control_layout.addWidget(self._num_points) - ParamsTree = ParameterTree() - ParamsTree.setParameters(self.params, showTop=True) - layout = QtWidgets.QGridLayout() - layout.addWidget(ParamsTree, 0,0) + save_button.pressed.connect(self._save) + restore_button.pressed.connect(self._restore) + self._num_points.editingFinished.connect(self._expand) + + self._param_table = QTableWidget() + self._param_table.setColumnCount(2) + self._param_table.setRowCount(len(self._data)) + for i, (key, items) in enumerate(self._data.items()): + self._param_table.setItem(i, 0, QTableWidgetItem(key)) + self._param_table.setItem(i, 1, QTableWidgetItem(str(items[0]))) + + layout = QVBoxLayout() + header = QLabel(self._name) + layout.addWidget(header) + layout.addLayout(control_layout) + layout.addWidget(self._param_table) self.setLayout(layout) self.setStyleSheet(qts.white_style) - # self.show() + #self.show() - def getParams(self) -> dict: - self.data = {} - for p in self.params: - if p.name() != 'Save': - self.data[p.name()] = p.value() - return self.data + def _save(self) -> dict: + self._data = {} + for i in range(self._param_table.rowCount()): + key = self._param_table.item(i, 0).text() + data = [] + for j in range(1, self._param_table.columnCount()): + param = self._param_table.item(i, j).text() + if key != "trace_storage_path": + param = float(param) + data.append(param) + self._data[key] = data + self.write_settings() + self._upd_func() + + + def _restore(self) -> None: + self._param_table.setRowCount(len(self._data)) + self._param_table.setColumnCount(len(self._data[self._data.keys()[0]])) + for i, (key, items) in enumerate(self._data.items()): + self._param_table.setItem(i, 0, QTableWidgetItem(key)) + for j, item in enumerate(items): + self._param_table.setItem(i, j+1, QTableWidgetItem(str(item))) + + def _expand(self) -> None: + param=int(self._num_points.text()) + prev_columns = self._param_table.columnCount() + self._param_table.setColumnCount(param+1) + if prev_columns < param+1: + for i in range(prev_columns, param+1): + for j, (key, items) in enumerate(self._data.items()): + self._param_table.setItem(j, i, QTableWidgetItem(str(items[-1]))) + + + + + + if __name__ == '__main__': app = pg.mkQApp("Parameter Tree Example") diff --git a/src/main.py b/src/main.py index 3d20261..d3ed19d 100644 --- a/src/main.py +++ b/src/main.py @@ -7,6 +7,7 @@ from src.controller.mediator import Mediator from src.controller.converter import DataConverter from src.gui.plotter import PlotWidget from src.controller.controller import Controller +from src.controller.passportFormer import PassportFormer def main(): @@ -15,8 +16,9 @@ def main(): data_converter = DataConverter() plot_widget_builder = PlotWidget() controller = Controller() + passport_former = PassportFormer() window = MainWindow(controller) - mediator = Mediator(monitor, data_converter, plot_widget_builder, controller) + mediator = Mediator(monitor, data_converter, passport_former, plot_widget_builder, controller) window.show() controller.signal_widgets.connect(window.show_plot_tabs) diff --git a/src/utils/base/__pycache__/base.cpython-310.pyc b/src/utils/base/__pycache__/base.cpython-310.pyc index 3854e03..fc1ef8d 100644 Binary files a/src/utils/base/__pycache__/base.cpython-310.pyc and b/src/utils/base/__pycache__/base.cpython-310.pyc differ diff --git a/src/utils/base/base.py b/src/utils/base/base.py index abb97ac..2908f17 100644 --- a/src/utils/base/base.py +++ b/src/utils/base/base.py @@ -18,20 +18,23 @@ class BaseMediator: def __init__(self, monitor: BaseDirectoryMonitor, converter: BaseDataConverter, + passportFormer: BasePointPassportFormer, plot: BasePlotWidget, controller: BaseController): self._monitor = monitor self._monitor.mediator = self self._converter = converter self._converter.mediator = self + self._passportFormer = passportFormer + self._passportFormer.mediator = self self._plot = plot self._plot.mediator = self self._controller = controller self._controller.mediator = self def notify(self, - source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget, BaseMainWindow], - data: Union[list[str], list[pd.DataFrame], list[QWidget], list[dict]]): + source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePointPassportFormer, BasePlotWidget], + data: Union[list[str], list[pd.DataFrame], list[list], list[QWidget]]): ... def push_settings (self, data: list[dict]): ... @@ -120,7 +123,8 @@ class BasePlotWidget: "Settings": { "zoom": False, "stages": True, - "performance": True + "performance": True, + "ideals": True }, "Real_signals": [ { @@ -147,7 +151,8 @@ class BasePlotWidget: "Settings": { "zoom": True, "stages": False, - "performance": False + "performance": False, + "ideals": True }, "Real_signals": [ { @@ -170,7 +175,8 @@ class BasePlotWidget: "Settings": { "zoom": False, "stages": True, - "performance": False + "performance": False, + "ideals": True }, "Real_signals": [ { @@ -218,8 +224,6 @@ class BasePlotWidget: def build(self, data: list[pd.DataFrame]) -> list[QWidget]: ... - def update_settings(self, data: list[dict]) -> None: - ... class BaseController(QObject): @@ -231,6 +235,7 @@ class BaseController(QObject): class BaseIdealDataBuilder(OptAlgorithm): + def __init__(self, params: list[dict]): operator_params, system_params = params self.mul = system_params['time_capture'] @@ -324,14 +329,16 @@ class BaseMainWindow(QWidget): """) class BasePointPassportFormer: - - def __init__(self): + + def __init__(self, + mediator: Optional[BaseMediator] = None): + self._mediator = mediator self._clear_stage = "Welding" self._stages = [ "Closing", "Squeeze", "Welding", - "Relief", + "Relief" ] def _find_indexes(self, @@ -355,7 +362,7 @@ class BasePointPassportFormer: def _filter_events(self, times: pd.Series, - dataframe: pd.DataFrame) -> dict[list[float]]: + dataframe: pd.DataFrame) -> list[dict[list[float]], int]: events = {} if self._clear_stage in self._stages: start_list, end_list = self._find_events(self._clear_stage, times, dataframe) @@ -363,25 +370,29 @@ class BasePointPassportFormer: for stage in self._stages: start_list, end_list = self._find_events(stage, times, dataframe) events[stage] = [start_list[:point_quantity], end_list[:point_quantity]] - return events + return events, point_quantity - def _initIdealBuilder(self, + def _build_ideal_data(self, idealDataBuilder: Optional[BaseIdealDataBuilder] = None, - params: list[dict] = None): + params: list[dict] = None) -> dict: self.opt = idealDataBuilder(params) - self._stage_ideals = { + stage_ideals = { "Closing": self._opt.get_closingDF(), "Squeeze": self._opt.get_compressionDF(), "Welding": self._opt.get_weldingDF(), "Relief": self._opt.get_openingDF(), - "Oncomming": self._opt.get_oncomingDF() + "Oncomming": self._opt.get_oncomingDF(), + "Ideal cycle": self._opt.get_cycle_time() } + return stage_ideals - def _create_curve_ideal(self, - stage: str): - data = self._stage_ideals[stage] + def form_passports(self) -> list[list[pd.DataFrame, dict, list]]: ... + + def update_settings(self, params: list) -> None: + ... + @property def opt(self) -> BaseIdealDataBuilder: @@ -389,4 +400,12 @@ class BasePointPassportFormer: @opt.setter def opt(self, opt: BaseIdealDataBuilder): - self._opt = opt \ No newline at end of file + self._opt = opt + + @property + def mediator(self) -> BaseMediator: + return self._mediator + + @mediator.setter + def mediator(self, mediator: BaseMediator) -> None: + self._mediator = mediator \ No newline at end of file