dev: добавлена возможность задавать параметры оператора для каждой точки
This commit is contained in:
parent
a0d6cba386
commit
0a9b1c50b8
@ -1,16 +1,226 @@
|
|||||||
{
|
{
|
||||||
"dist_open_start_1": 0.005,
|
"dist_open_start_1": [
|
||||||
"dist_open_start_2": 0.005,
|
0.005,
|
||||||
"dist_open_after_1": 0.006,
|
0.005,
|
||||||
"dist_open_after_2": 0.006,
|
0.005,
|
||||||
"dist_open_end_1": 0.01,
|
0.005,
|
||||||
"dist_open_end_2": 0.05,
|
0.005,
|
||||||
"dist_close_end_1": 0.005,
|
0.005,
|
||||||
"dist_close_end_2": 0.005,
|
0.005,
|
||||||
"time_wielding": 1,
|
0.005,
|
||||||
"time_command": 0.0,
|
0.005,
|
||||||
"time_robot_movement": 0.2,
|
0.005,
|
||||||
"object_thickness": 0.0045,
|
0.005,
|
||||||
"force_target": 5000,
|
0.005,
|
||||||
"force_capture": 500
|
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
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@ -1,22 +1,22 @@
|
|||||||
{
|
{
|
||||||
"trace_storage_path": "D:/downloads/a22",
|
"trace_storage_path": ["D:/downloads/a22"],
|
||||||
"monitor_update_period": 100,
|
"monitor_update_period": [100],
|
||||||
"a_max_1": 5.41,
|
"a_max_1": [5.41],
|
||||||
"v_max_1": 0.278,
|
"v_max_1": [0.278],
|
||||||
"a_max_2": 35.81,
|
"a_max_2": [35.81],
|
||||||
"v_max_2": 0.7,
|
"v_max_2": [0.7],
|
||||||
"mass_1": 270,
|
"mass_1": [270],
|
||||||
"mass_2": 1,
|
"mass_2": [1],
|
||||||
"k_hardness_1": 2148570,
|
"k_hardness_1": [2148570],
|
||||||
"k_hardness_2": 0,
|
"k_hardness_2": [0],
|
||||||
"torque_max_1": 20,
|
"torque_max_1": [20],
|
||||||
"torque_max_2": 0,
|
"torque_max_2": [0],
|
||||||
"transmission_ratio_1": 0.00125,
|
"transmission_ratio_1": [0.00125],
|
||||||
"transmission_ratio_2": 1,
|
"transmission_ratio_2": [1],
|
||||||
"position_start_1": 0.08,
|
"position_start_1": [0.08],
|
||||||
"position_start_2": 0.08,
|
"position_start_2": [0.08],
|
||||||
"k_prop": 0.05,
|
"k_prop": [0.05],
|
||||||
"time_capture": 100000,
|
"time_capture": [100000],
|
||||||
"UML_time_scaler": 1000
|
"UML_time_scaler": [1000]
|
||||||
|
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/controller/__pycache__/passportFormer.cpython-310.pyc
Normal file
BIN
src/controller/__pycache__/passportFormer.cpython-310.pyc
Normal file
Binary file not shown.
@ -3,18 +3,21 @@ import pandas as pd
|
|||||||
from typing import Union
|
from typing import Union
|
||||||
from PyQt5.QtWidgets import QWidget
|
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):
|
class Mediator(BaseMediator):
|
||||||
|
|
||||||
def notify(self,
|
def notify(self,
|
||||||
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget],
|
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePointPassportFormer, BasePlotWidget],
|
||||||
data: Union[list[str], list[pd.DataFrame], list[QWidget]]):
|
data: Union[list[str], list[pd.DataFrame], list[list], list[QWidget]]):
|
||||||
if issubclass(source.__class__, BaseDirectoryMonitor):
|
if issubclass(source.__class__, BaseDirectoryMonitor):
|
||||||
self._converter.convert_data(data)
|
self._converter.convert_data(data)
|
||||||
|
|
||||||
if issubclass(source.__class__, BaseDataConverter):
|
if issubclass(source.__class__, BaseDataConverter):
|
||||||
|
self._passportFormer.form_passports(data)
|
||||||
|
|
||||||
|
if issubclass(source.__class__, BasePointPassportFormer):
|
||||||
self._plot.build(data)
|
self._plot.build(data)
|
||||||
|
|
||||||
if issubclass(source.__class__, BasePlotWidget):
|
if issubclass(source.__class__, BasePlotWidget):
|
||||||
@ -22,7 +25,7 @@ class Mediator(BaseMediator):
|
|||||||
|
|
||||||
def push_settings(self, settings: list[dict]):
|
def push_settings(self, settings: list[dict]):
|
||||||
self._monitor.update_settings(settings)
|
self._monitor.update_settings(settings)
|
||||||
self._plot.update_settings(settings)
|
self._passportFormer.update_settings(settings)
|
||||||
self._monitor.force_all_dir()
|
self._monitor.force_all_dir()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -29,8 +29,8 @@ class DirectoryMonitor(BaseDirectoryMonitor):
|
|||||||
def update_settings(self, data: list[dict]) -> None:
|
def update_settings(self, data: list[dict]) -> None:
|
||||||
self.stop()
|
self.stop()
|
||||||
operator_params, system_params = data
|
operator_params, system_params = data
|
||||||
self._directory_path = system_params['trace_storage_path']
|
self._directory_path = system_params['trace_storage_path'][0]
|
||||||
self._update_time = system_params['monitor_update_period']
|
self._update_time = system_params['monitor_update_period'][0]
|
||||||
self._init_state()
|
self._init_state()
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
|
|||||||
63
src/controller/passportFormer.py
Normal file
63
src/controller/passportFormer.py
Normal file
@ -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
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -45,7 +45,7 @@ class MainWindow(BaseMainWindow):
|
|||||||
|
|
||||||
def keyPressEvent(self, a0):
|
def keyPressEvent(self, a0):
|
||||||
if a0.key() == Qt.Key_F5:
|
if a0.key() == Qt.Key_F5:
|
||||||
self.clear()
|
pass
|
||||||
|
|
||||||
def _show_settings(self):
|
def _show_settings(self):
|
||||||
self.operSettings.show()
|
self.operSettings.show()
|
||||||
|
|||||||
@ -5,34 +5,7 @@ import numpy as np
|
|||||||
from numpy import floating
|
from numpy import floating
|
||||||
from typing import Optional, Any, NamedTuple
|
from typing import Optional, Any, NamedTuple
|
||||||
|
|
||||||
from src.utils.base.base import BasePlotWidget, BasePointPassportFormer, BaseIdealDataBuilder
|
from src.utils.base.base import BasePlotWidget
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessStage(NamedTuple):
|
class ProcessStage(NamedTuple):
|
||||||
mean_value: floating[Any]
|
mean_value: floating[Any]
|
||||||
@ -40,16 +13,15 @@ class ProcessStage(NamedTuple):
|
|||||||
finish_index: int
|
finish_index: int
|
||||||
|
|
||||||
|
|
||||||
class PlotWidget(BasePlotWidget, BasePointPassportFormer):
|
class PlotWidget(BasePlotWidget):
|
||||||
def _create_curve_ideal(self,
|
def _create_curve_ideal(self,
|
||||||
stage: str,
|
|
||||||
signal: str,
|
signal: str,
|
||||||
|
ideal_data: pd.DataFrame,
|
||||||
start_timestamp: float,
|
start_timestamp: float,
|
||||||
finish_timestamp: float) -> Optional[pg.PlotDataItem]:
|
finish_timestamp: float) -> Optional[pg.PlotDataItem]:
|
||||||
data = self._stage_ideals[stage]
|
|
||||||
|
|
||||||
if start_timestamp and finish_timestamp:
|
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 plot
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -76,104 +48,109 @@ class PlotWidget(BasePlotWidget, BasePointPassportFormer):
|
|||||||
stage: str,
|
stage: str,
|
||||||
dataframe: pd.DataFrame,
|
dataframe: pd.DataFrame,
|
||||||
signal_name: str) -> Optional[ProcessStage]:
|
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 []
|
stage_diff = np.diff(dataframe[stage])
|
||||||
|
start_index = np.where(stage_diff == 1)[0]
|
||||||
|
finish_index = np.where(stage_diff == -1)[0]
|
||||||
|
|
||||||
if data.size and start_index.size:
|
data = dataframe[signal_name] if signal_name in dataframe.columns.tolist() else []
|
||||||
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:
|
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()
|
widget = QWidget()
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
time_axis = dataframe["time"]
|
|
||||||
dataframe_headers = dataframe.columns.tolist()
|
|
||||||
|
|
||||||
for channel, description in self._plt_channels.items():
|
for channel, description in self._plt_channels.items():
|
||||||
|
performance_list = []
|
||||||
|
df_continuous = pd.DataFrame({})
|
||||||
plot_widget, legend = self._init_plot_widget(title=channel)
|
plot_widget, legend = self._init_plot_widget(title=channel)
|
||||||
|
|
||||||
settings = description["Settings"]
|
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)
|
for dataframe, ideal_data, events in data:
|
||||||
point_quantity = len(events[self._clear_stage][0])
|
df_continuous = pd.concat([df_continuous, dataframe], axis=0)
|
||||||
if settings["stages"]:
|
dataframe_headers = dataframe.columns.tolist()
|
||||||
for stage in self._stages:
|
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]
|
start_t, end_t = events[stage]
|
||||||
for i in range(len(start_t)):
|
region = self._create_stage_region(stage, start_t, end_t)
|
||||||
region = self._create_stage_region(stage, start_t[i], end_t[i])
|
if region:
|
||||||
if region:
|
plot_widget.addItem(region)
|
||||||
plot_widget.addItem(region)
|
|
||||||
for signal in description["Ideal_signals"]:
|
if settings["ideals"]:
|
||||||
ideal_plot = self._create_curve_ideal(stage, signal, start_t[i], end_t[i])
|
for stage in stages:
|
||||||
if ideal_plot:
|
for signal in description["Ideal_signals"]:
|
||||||
plot_widget.addItem(ideal_plot)
|
curve = self._create_curve_ideal(signal, ideal_data[stage], events[stage][0], events[stage][1])
|
||||||
|
if curve:
|
||||||
|
plot_widget.addItem(curve)
|
||||||
|
|
||||||
if settings["performance"]:
|
if settings["performance"]:
|
||||||
ideal_delta = self._opt.get_cycle_time()
|
ideal_delta = ideal_data["Ideal cycle"]
|
||||||
delta = np.zeros(point_quantity)
|
delta = 0
|
||||||
for stage in self._stages:
|
for stage in stages:
|
||||||
try:
|
delta += events[stage][1] - events[stage][0]
|
||||||
start_stage, stop_stage = events[stage]
|
performance = ideal_delta/delta*100
|
||||||
delta += np.array(stop_stage)-np.array(start_stage)
|
performance_list.append(performance)
|
||||||
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)
|
|
||||||
|
|
||||||
if settings["zoom"]:
|
if settings["zoom"]:
|
||||||
if max(time_axis) < 5.0:
|
pass
|
||||||
stages = [self.get_stage_info("Welding",
|
"""if max(time_axis) < 5.0:
|
||||||
dataframe,
|
stages = [self.get_stage_info("Welding",
|
||||||
signal["name"]) for signal in description["Real_signals"]]
|
dataframe,
|
||||||
if stages:
|
signal["name"]) for signal in description["Real_signals"]]
|
||||||
means_raw = [stage.mean_value for stage in stages]
|
if stages:
|
||||||
mean = max(means_raw)
|
means_raw = [stage.mean_value for stage in stages]
|
||||||
start = time_axis[stages[0].start_index]
|
mean = max(means_raw)
|
||||||
finish = time_axis[stages[0].finish_index]
|
start = time_axis[stages[0].start_index]
|
||||||
|
finish = time_axis[stages[0].finish_index]
|
||||||
|
|
||||||
overshoot = pg.BarGraphItem(x0=0,
|
overshoot = pg.BarGraphItem(x0=0,
|
||||||
y0=mean - mean * 0.05,
|
y0=mean - mean * 0.05,
|
||||||
height=mean * 0.05 * 2,
|
height=mean * 0.05 * 2,
|
||||||
width=start,
|
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]))
|
brush=pg.mkBrush([0, 250, 0, 100]))
|
||||||
plot_widget.addItem(overshoot)
|
plot_widget.addItem(stable)
|
||||||
|
|
||||||
stable = pg.BarGraphItem(x0=start,
|
plot_widget.setYRange(mean - 260, mean + 260)
|
||||||
y0=mean - mean * 0.015,
|
plot_widget.setInteractive(False)
|
||||||
height=mean * 0.015 * 2,
|
else:
|
||||||
width=finish - start,
|
max_value = min([max(dataframe[signal["name"]]) for signal in description["Real_signals"]])
|
||||||
brush=pg.mkBrush([0, 250, 0, 100]))
|
region = pg.LinearRegionItem([max_value - max_value * 0.015,
|
||||||
plot_widget.addItem(stable)
|
max_value + max_value * 0.015],
|
||||||
|
movable=False,
|
||||||
|
orientation="horizontal")
|
||||||
|
|
||||||
plot_widget.setYRange(mean - 260, mean + 260)
|
region.setBrush(pg.mkBrush([0, 250, 0, 100]))
|
||||||
plot_widget.setInteractive(False)
|
plot_widget.setYRange(max_value - 200, max_value + 200)
|
||||||
else:
|
plot_widget.setXRange(3.5, 4.5)
|
||||||
max_value = min([max(dataframe[signal["name"]]) for signal in description["Real_signals"]])
|
plot_widget.addItem(region)
|
||||||
region = pg.LinearRegionItem([max_value - max_value * 0.015,
|
plot_widget.setInteractive(False)"""
|
||||||
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)
|
|
||||||
|
|
||||||
for signal in description["Real_signals"]:
|
for signal in description["Real_signals"]:
|
||||||
if signal["name"] in dataframe_headers:
|
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"])
|
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)
|
layout.addWidget(plot_widget)
|
||||||
|
|
||||||
widget.setLayout(layout)
|
widget.setLayout(layout)
|
||||||
@ -183,8 +160,5 @@ class PlotWidget(BasePlotWidget, BasePointPassportFormer):
|
|||||||
widgets = [self._build_widget(data_sample) for data_sample in data]
|
widgets = [self._build_widget(data_sample) for data_sample in data]
|
||||||
self._mediator.notify(self, widgets)
|
self._mediator.notify(self, widgets)
|
||||||
|
|
||||||
def update_settings(self, params: list[dict]):
|
|
||||||
self._initIdealBuilder(idealDataBuilder=idealDataBuilder, params=params)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,55 +1,103 @@
|
|||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.Qt import QtWidgets
|
from PyQt5.QtWidgets import QWidget, QTableWidget, QVBoxLayout, QTableWidgetItem, QLabel, QPushButton, QLineEdit, QHBoxLayout
|
||||||
from pyqtgraph.parametertree import Parameter, ParameterTree
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtGui import QIntValidator
|
||||||
|
|
||||||
|
|
||||||
from src.utils.json_tools import read_json, write_json
|
from src.utils.json_tools import read_json, write_json
|
||||||
from src.gui import qt_settings as qts
|
from src.gui import qt_settings as qts
|
||||||
|
|
||||||
class settingsWindow(QtWidgets.QWidget):
|
class settingsWindow(QWidget):
|
||||||
def __init__(self, path: str, name: str, upd_func):
|
def __init__(self, path: str, name: str, upd_func):
|
||||||
super(settingsWindow, self).__init__()
|
super(settingsWindow, self).__init__()
|
||||||
self.settingsPath = path
|
self._settingsPath = path
|
||||||
self.name = name
|
self._name = name
|
||||||
|
self._data = {}
|
||||||
|
self._upd_func = upd_func
|
||||||
|
|
||||||
self.data = {}
|
|
||||||
self.params = None
|
|
||||||
self.load_settings()
|
self.load_settings()
|
||||||
self._init_ui()
|
self._init_ui()
|
||||||
self.params.sigTreeStateChanged.connect(upd_func)
|
|
||||||
|
|
||||||
def load_settings(self) -> None:
|
def load_settings(self) -> None:
|
||||||
self.data = read_json(self.settingsPath)
|
self._data = read_json(self._settingsPath)
|
||||||
|
|
||||||
def write_settings(self) -> None:
|
def write_settings(self) -> None:
|
||||||
self.getParams()
|
write_json(self._settingsPath, self._data)
|
||||||
write_json(self.settingsPath, 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)
|
|
||||||
|
|
||||||
ParamsTree = ParameterTree()
|
|
||||||
ParamsTree.setParameters(self.params, showTop=True)
|
|
||||||
layout = QtWidgets.QGridLayout()
|
|
||||||
layout.addWidget(ParamsTree, 0,0)
|
|
||||||
self.setLayout(layout)
|
|
||||||
self.setStyleSheet(qts.white_style)
|
|
||||||
# self.show()
|
|
||||||
|
|
||||||
def getParams(self) -> dict:
|
def getParams(self) -> dict:
|
||||||
self.data = {}
|
return self._data
|
||||||
for p in self.params:
|
|
||||||
if p.name() != 'Save':
|
|
||||||
self.data[p.name()] = p.value()
|
def _init_ui(self) -> None:
|
||||||
return self.data
|
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)
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
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__':
|
if __name__ == '__main__':
|
||||||
app = pg.mkQApp("Parameter Tree Example")
|
app = pg.mkQApp("Parameter Tree Example")
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from src.controller.mediator import Mediator
|
|||||||
from src.controller.converter import DataConverter
|
from src.controller.converter import DataConverter
|
||||||
from src.gui.plotter import PlotWidget
|
from src.gui.plotter import PlotWidget
|
||||||
from src.controller.controller import Controller
|
from src.controller.controller import Controller
|
||||||
|
from src.controller.passportFormer import PassportFormer
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -15,8 +16,9 @@ def main():
|
|||||||
data_converter = DataConverter()
|
data_converter = DataConverter()
|
||||||
plot_widget_builder = PlotWidget()
|
plot_widget_builder = PlotWidget()
|
||||||
controller = Controller()
|
controller = Controller()
|
||||||
|
passport_former = PassportFormer()
|
||||||
window = MainWindow(controller)
|
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()
|
window.show()
|
||||||
|
|
||||||
controller.signal_widgets.connect(window.show_plot_tabs)
|
controller.signal_widgets.connect(window.show_plot_tabs)
|
||||||
|
|||||||
Binary file not shown.
@ -18,20 +18,23 @@ class BaseMediator:
|
|||||||
def __init__(self,
|
def __init__(self,
|
||||||
monitor: BaseDirectoryMonitor,
|
monitor: BaseDirectoryMonitor,
|
||||||
converter: BaseDataConverter,
|
converter: BaseDataConverter,
|
||||||
|
passportFormer: BasePointPassportFormer,
|
||||||
plot: BasePlotWidget,
|
plot: BasePlotWidget,
|
||||||
controller: BaseController):
|
controller: BaseController):
|
||||||
self._monitor = monitor
|
self._monitor = monitor
|
||||||
self._monitor.mediator = self
|
self._monitor.mediator = self
|
||||||
self._converter = converter
|
self._converter = converter
|
||||||
self._converter.mediator = self
|
self._converter.mediator = self
|
||||||
|
self._passportFormer = passportFormer
|
||||||
|
self._passportFormer.mediator = self
|
||||||
self._plot = plot
|
self._plot = plot
|
||||||
self._plot.mediator = self
|
self._plot.mediator = self
|
||||||
self._controller = controller
|
self._controller = controller
|
||||||
self._controller.mediator = self
|
self._controller.mediator = self
|
||||||
|
|
||||||
def notify(self,
|
def notify(self,
|
||||||
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget, BaseMainWindow],
|
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePointPassportFormer, BasePlotWidget],
|
||||||
data: Union[list[str], list[pd.DataFrame], list[QWidget], list[dict]]):
|
data: Union[list[str], list[pd.DataFrame], list[list], list[QWidget]]):
|
||||||
...
|
...
|
||||||
def push_settings (self, data: list[dict]):
|
def push_settings (self, data: list[dict]):
|
||||||
...
|
...
|
||||||
@ -120,7 +123,8 @@ class BasePlotWidget:
|
|||||||
"Settings": {
|
"Settings": {
|
||||||
"zoom": False,
|
"zoom": False,
|
||||||
"stages": True,
|
"stages": True,
|
||||||
"performance": True
|
"performance": True,
|
||||||
|
"ideals": True
|
||||||
},
|
},
|
||||||
"Real_signals": [
|
"Real_signals": [
|
||||||
{
|
{
|
||||||
@ -147,7 +151,8 @@ class BasePlotWidget:
|
|||||||
"Settings": {
|
"Settings": {
|
||||||
"zoom": True,
|
"zoom": True,
|
||||||
"stages": False,
|
"stages": False,
|
||||||
"performance": False
|
"performance": False,
|
||||||
|
"ideals": True
|
||||||
},
|
},
|
||||||
"Real_signals": [
|
"Real_signals": [
|
||||||
{
|
{
|
||||||
@ -170,7 +175,8 @@ class BasePlotWidget:
|
|||||||
"Settings": {
|
"Settings": {
|
||||||
"zoom": False,
|
"zoom": False,
|
||||||
"stages": True,
|
"stages": True,
|
||||||
"performance": False
|
"performance": False,
|
||||||
|
"ideals": True
|
||||||
},
|
},
|
||||||
"Real_signals": [
|
"Real_signals": [
|
||||||
{
|
{
|
||||||
@ -218,8 +224,6 @@ class BasePlotWidget:
|
|||||||
def build(self, data: list[pd.DataFrame]) -> list[QWidget]:
|
def build(self, data: list[pd.DataFrame]) -> list[QWidget]:
|
||||||
...
|
...
|
||||||
|
|
||||||
def update_settings(self, data: list[dict]) -> None:
|
|
||||||
...
|
|
||||||
|
|
||||||
class BaseController(QObject):
|
class BaseController(QObject):
|
||||||
|
|
||||||
@ -231,6 +235,7 @@ class BaseController(QObject):
|
|||||||
|
|
||||||
|
|
||||||
class BaseIdealDataBuilder(OptAlgorithm):
|
class BaseIdealDataBuilder(OptAlgorithm):
|
||||||
|
|
||||||
def __init__(self, params: list[dict]):
|
def __init__(self, params: list[dict]):
|
||||||
operator_params, system_params = params
|
operator_params, system_params = params
|
||||||
self.mul = system_params['time_capture']
|
self.mul = system_params['time_capture']
|
||||||
@ -325,13 +330,15 @@ class BaseMainWindow(QWidget):
|
|||||||
|
|
||||||
class BasePointPassportFormer:
|
class BasePointPassportFormer:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self,
|
||||||
|
mediator: Optional[BaseMediator] = None):
|
||||||
|
self._mediator = mediator
|
||||||
self._clear_stage = "Welding"
|
self._clear_stage = "Welding"
|
||||||
self._stages = [
|
self._stages = [
|
||||||
"Closing",
|
"Closing",
|
||||||
"Squeeze",
|
"Squeeze",
|
||||||
"Welding",
|
"Welding",
|
||||||
"Relief",
|
"Relief"
|
||||||
]
|
]
|
||||||
|
|
||||||
def _find_indexes(self,
|
def _find_indexes(self,
|
||||||
@ -355,7 +362,7 @@ class BasePointPassportFormer:
|
|||||||
|
|
||||||
def _filter_events(self,
|
def _filter_events(self,
|
||||||
times: pd.Series,
|
times: pd.Series,
|
||||||
dataframe: pd.DataFrame) -> dict[list[float]]:
|
dataframe: pd.DataFrame) -> list[dict[list[float]], int]:
|
||||||
events = {}
|
events = {}
|
||||||
if self._clear_stage in self._stages:
|
if self._clear_stage in self._stages:
|
||||||
start_list, end_list = self._find_events(self._clear_stage, times, dataframe)
|
start_list, end_list = self._find_events(self._clear_stage, times, dataframe)
|
||||||
@ -363,26 +370,30 @@ class BasePointPassportFormer:
|
|||||||
for stage in self._stages:
|
for stage in self._stages:
|
||||||
start_list, end_list = self._find_events(stage, times, dataframe)
|
start_list, end_list = self._find_events(stage, times, dataframe)
|
||||||
events[stage] = [start_list[:point_quantity], end_list[:point_quantity]]
|
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,
|
idealDataBuilder: Optional[BaseIdealDataBuilder] = None,
|
||||||
params: list[dict] = None):
|
params: list[dict] = None) -> dict:
|
||||||
self.opt = idealDataBuilder(params)
|
self.opt = idealDataBuilder(params)
|
||||||
|
|
||||||
self._stage_ideals = {
|
stage_ideals = {
|
||||||
"Closing": self._opt.get_closingDF(),
|
"Closing": self._opt.get_closingDF(),
|
||||||
"Squeeze": self._opt.get_compressionDF(),
|
"Squeeze": self._opt.get_compressionDF(),
|
||||||
"Welding": self._opt.get_weldingDF(),
|
"Welding": self._opt.get_weldingDF(),
|
||||||
"Relief": self._opt.get_openingDF(),
|
"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,
|
def form_passports(self) -> list[list[pd.DataFrame, dict, list]]:
|
||||||
stage: str):
|
|
||||||
data = self._stage_ideals[stage]
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def update_settings(self, params: list) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def opt(self) -> BaseIdealDataBuilder:
|
def opt(self) -> BaseIdealDataBuilder:
|
||||||
return self._opt
|
return self._opt
|
||||||
@ -390,3 +401,11 @@ class BasePointPassportFormer:
|
|||||||
@opt.setter
|
@opt.setter
|
||||||
def opt(self, opt: BaseIdealDataBuilder):
|
def opt(self, opt: BaseIdealDataBuilder):
|
||||||
self._opt = opt
|
self._opt = opt
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mediator(self) -> BaseMediator:
|
||||||
|
return self._mediator
|
||||||
|
|
||||||
|
@mediator.setter
|
||||||
|
def mediator(self, mediator: BaseMediator) -> None:
|
||||||
|
self._mediator = mediator
|
||||||
Loading…
Reference in New Issue
Block a user