From 90b6660a154088496e81fa6c0fced7c6337374e0 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 6 Feb 2025 15:59:16 +0300 Subject: [PATCH] =?UTF-8?q?dev:=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0=D0=BB=20=D1=80=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=B4=D0=B3=D0=BE?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B?= =?UTF-8?q?=D0=B9=20=D1=8D=D1=82=D0=B0=D0=BF=20(=D0=BD=D0=B0=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=B9=D0=BA=D0=B0=20=D1=84=D0=B8=D0=BB=D1=8C=D1=82?= =?UTF-8?q?=D1=80=D0=B0)=20=D0=B8=20=D1=84=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D0=BF=D0=BE=20=D1=81=D0=BE=D0=BE=D1=82?= =?UTF-8?q?=D0=B2=D0=B5=D1=82=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B8?= =?UTF-8?q?=D0=BC=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B0=D0=BC=20(open=20f?= =?UTF-8?q?ilder=20=D0=B8=20calc=20TCW)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- params/filter_params.json | 4 +-- src/base/base.py | 14 +++++++-- src/controller/controller.py | 5 ++- src/controller/file_manager.py | 10 ++++-- src/controller/mediator.py | 32 +++++++++++++++---- src/gui/main_gui.py | 7 +++-- src/gui/plotter.py | 57 +++++++++++++++++++++------------- src/main.py | 1 + src/performance/roboter.py | 25 ++++++++++----- src/utils/qt_settings.py | 10 ++++++ 10 files changed, 120 insertions(+), 45 deletions(-) diff --git a/params/filter_params.json b/params/filter_params.json index 8c0f465..462ce79 100644 --- a/params/filter_params.json +++ b/params/filter_params.json @@ -3,10 +3,10 @@ 0.008 ], "actuator_zero_velocity_trashold": [ - 10.0 + 100.0 ], "actuator_finishing_velocity": [ - 2050.0 + 2000.0 ], "actuator_finishing_velocity_trashold": [ 200.0 diff --git a/src/base/base.py b/src/base/base.py index cf8c1c5..863be46 100644 --- a/src/base/base.py +++ b/src/base/base.py @@ -104,7 +104,12 @@ class BaseMediator: data: Union[list[str], list[pd.DataFrame], list[list], list[QWidget], pd.DataFrame]): ... - def prerender(self, data:list[str]) -> None: + def prerender_TCW(self, source:Union[BaseController, BaseFileManager, BaseRawTraceProcessor], + data:Union[str, list[str], list[pd.DataFrame, dict]]) -> None: + ... + + def render_TCW(self, source:Union[BaseController, BaseRawTraceProcessor], + data:Union[str, list[pd.DataFrame, dict]]) -> None: ... def set_mode(self, mode: int) -> None: @@ -282,7 +287,8 @@ class BaseFileManager: monitor: Optional[BaseDirectoryMonitor] = None): self._mediator = mediator self._monitor = monitor - self._paths_library = set() + self._paths_library:set = set() + self._mode = 0 @property def paths_library(self) -> set: @@ -471,10 +477,12 @@ class BaseRawTraceProcessor: self._trace_df = None self._text_data = None - def prerender(self, data:list[str]) -> None: ... + def final_render(self) -> None: + ... + def update_settings(self, data:Settings) -> None: ... diff --git a/src/controller/controller.py b/src/controller/controller.py index 669d250..7bf91bc 100644 --- a/src/controller/controller.py +++ b/src/controller/controller.py @@ -33,7 +33,10 @@ class Controller(BaseController): self._file_manager.open_custom_file(filepath) def open_dir(self, dirpath:str) -> None: - self._file_manager.open_raw_traces_dir(dirpath) + self._mediator.prerender_TCW(self, dirpath) + + def build_TCW_for_client(self): + self._mediator.render_TCW(self) def save_file(self, data:list[str, QTabWidget]) -> None: filepath, tab = data diff --git a/src/controller/file_manager.py b/src/controller/file_manager.py index d2cf0f9..3c69c8c 100644 --- a/src/controller/file_manager.py +++ b/src/controller/file_manager.py @@ -9,7 +9,8 @@ class FileManager(BaseFileManager): def replot_all(self) -> None: if self._paths_library is not None: - self._mediator.notify(self, list(self._paths_library)) + if self._mode != 3: self._mediator.notify(self, list(self._paths_library)) + else: self.open_raw_traces_dir(list(self._paths_library)[0]) def open_custom_file(self, path:str) -> None: self._paths_library.add(path) @@ -22,14 +23,17 @@ class FileManager(BaseFileManager): self._paths_library.clear() self._paths_library.add('') self._mediator.notify(self, list(self._paths_library)) + self._mode = 1 case 2: # Режим онлайн-мониторинга папки self._monitor.init_state() self._monitor.start() + self._mode = 2 case 3: # Режим работы с трейсами клиента self._monitor.stop() self._paths_library.clear() + self._mode = 3 def update_monitor_settings(self, settings:Settings) -> None: directory_path = settings.system['trace_storage_path'][0] @@ -54,6 +58,8 @@ class FileManager(BaseFileManager): self._mediator.notify(list(new)) def open_raw_traces_dir(self, path:str) -> None: + self._paths_library.clear() + self._paths_library.add(path) dat_file, txt_file = None, None for entry in os.listdir(path): full_path = os.path.join(path, entry) @@ -69,7 +75,7 @@ class FileManager(BaseFileManager): break if dat_file and txt_file: - self._mediator.prerender([dat_file, txt_file]) + self._mediator.prerender_TCW(self, [dat_file, txt_file]) diff --git a/src/controller/mediator.py b/src/controller/mediator.py index a38ac9d..c49e78c 100644 --- a/src/controller/mediator.py +++ b/src/controller/mediator.py @@ -20,7 +20,7 @@ class Mediator(BaseMediator): def notify(self, source: Union[BaseFileManager, BaseDataConverter, BasePointPassportFormer, BasePlotWidget, BaseController, BaseRawTraceProcessor], - data: Union[list[str], list[pd.DataFrame], list[GraphicPassport], list[QWidget], Settings, pd.DataFrame]): + data: Union[list[str], list[pd.DataFrame], list[GraphicPassport], list[QWidget], Settings, pd.DataFrame]) -> None: if issubclass(source.__class__, BaseFileManager): self._controller.update_status("CSV found! Calculating...") @@ -31,7 +31,7 @@ class Mediator(BaseMediator): self._passport_former.form_passports(data) if issubclass(source.__class__, BasePointPassportFormer): - self._controller.update_progress(2) + self._controller.update_progress(10) self._plot.build(data) if issubclass(source.__class__, BasePlotWidget): @@ -42,13 +42,33 @@ class Mediator(BaseMediator): self._file_manager.update_monitor_settings(data) self._passport_former.update_settings(data) self._trace_processor.update_settings(data) + + def prerender_TCW(self, source:Union[BaseController, BaseFileManager, BaseRawTraceProcessor], + data:Union[str, list[str], list[pd.DataFrame, dict]]) -> None: + + if issubclass(source.__class__, BaseController): + self._controller.update_progress(5) + self._file_manager.open_raw_traces_dir(data) + + if issubclass(source.__class__, BaseFileManager): + self._controller.update_progress(15) + self._trace_processor.prerender(data) if issubclass(source.__class__, BaseRawTraceProcessor): + self._controller.update_progress(40) + self._plot.build_raw_trace(data) + + def render_TCW(self, source:Union[BaseController, BaseRawTraceProcessor], + data:Union[str, list[pd.DataFrame, dict]] = None) -> None: + + if issubclass(source.__class__, BaseController): + self._controller.update_progress(5) + self._trace_processor.final_render() + + if issubclass(source.__class__, BaseRawTraceProcessor): + self._controller.update_progress(5) self._passport_former.form_customer_passport(data) - - def prerender(self, data:list[str]) -> None: - self._trace_processor.prerender(data) - + def set_mode(self, mode: int) -> None: self._plot.set_mode(mode) self._file_manager.set_mode(mode) diff --git a/src/gui/main_gui.py b/src/gui/main_gui.py index e21d153..33f4b46 100644 --- a/src/gui/main_gui.py +++ b/src/gui/main_gui.py @@ -19,6 +19,7 @@ class MainWindow(BaseMainWindow): signal_open_file = pyqtSignal(str) signal_save_file = pyqtSignal(list) signal_open_dir = pyqtSignal(str) + signal_TCW_for_client = pyqtSignal() def __init__(self) -> None: super().__init__() @@ -118,9 +119,11 @@ class MainWindow(BaseMainWindow): #TODO: привязать действия к кнопкам client_widget.open_folder_btn.clicked.connect(self._open_folder) client_widget.save_screen_btn.clicked.connect(self._save_plots) + client_widget.build_TCW_btn.clicked.connect(self._build_TCW_for_client) self.setCentralWidget(client_widget.get_widget()) - #client_widget.build_TCW_btn.clicked.connect() - + + def _build_TCW_for_client(self): + self.signal_TCW_for_client.emit() def _set_mode(self, num:int) -> None: match num: diff --git a/src/gui/plotter.py b/src/gui/plotter.py index 89d8371..8904823 100644 --- a/src/gui/plotter.py +++ b/src/gui/plotter.py @@ -63,7 +63,7 @@ class PlotWidget(BasePlotWidget): finally: self._mediator.notify(self, widgets_datapack) - def build_raw_trace(self, data:pd.DataFrame) -> None: + def build_raw_trace(self, data:list[pd.DataFrame, dict]) -> None: """ Создаёт один виджет с одним графиком, где представлены все данные """ @@ -87,17 +87,28 @@ class PlotWidget(BasePlotWidget): print(3) def _build_raw_plotitem(self, - dataframe:pd.DataFrame, + data:list[pd.DataFrame, dict], pyqt_container:PlotItems) -> pg.GraphicsLayoutWidget: + plot_item, legend = PlotItemGenerator._init_plot_item("Customer data") + dataframe, events = data channels = dataframe.columns.to_list() for i, channel in enumerate(channels): - plot = plot_item.plot(dataframe.index.values, dataframe[channel], pen = qts.colors[i], fast = True) + plot = plot_item.plot(dataframe["time"], dataframe[channel], pen = qts.colors[i], fast = True) legend.addItem(plot, channel) pyqt_container.curves["real"].setdefault(channel, {}) pyqt_container.curves["real"][channel] = plot + + for i in range(len(events["Squeeze"][0])): + point_events = {} + for key, item in events.items(): + point_events[key] = [item[0][i], item[1][i]] + PlotItemGenerator._add_stage_regions(self._stage_colors, plot_item, point_events, pyqt_container.regions,20) + print(point_events) + plot_layout = pg.GraphicsLayoutWidget() plot_layout.addItem(plot_item) + return plot_layout def _build_performance_label(self, @@ -269,7 +280,7 @@ class PlotItemGenerator: dataframe = self._apply_force_compensation(force, k_hardness, dataframe, point_data.timeframe, signals) if settings.get("stages", False): - self._add_stage_regions(plot_item, point_data.events, dataframe_headers, pyqt_container.regions, 75) + self._add_stage_regions(self._stage_colors, plot_item, point_data.events, pyqt_container.regions, 75) if settings.get("force accuracy", False): force = point_data.useful_data["force"] @@ -283,7 +294,7 @@ class PlotItemGenerator: self._add_workpiece(point_data, plot_item) if settings.get("ideals", False): - self._add_ideal_stage_regions(plot_item, ideal_data, point_data.events, pyqt_container.regions, 100) + self._add_ideal_stage_regions(self._stage_colors, plot_item, ideal_data, point_data.events, pyqt_container.regions, 100) self._add_ideal_signals(plot_item, legend, ideal_data, point_data.events, description["Ideal_signals"], pyqt_container.curves, is_last) if settings.get("performance", False): @@ -333,7 +344,8 @@ class PlotItemGenerator: ) return None - def _create_stage_region(self, + @staticmethod + def _create_stage_region(colors:dict, stage: str, start_timestamp: float, finish_timestamp: float, @@ -343,32 +355,33 @@ class PlotItemGenerator: """ if start_timestamp is not None and finish_timestamp is not None: region = pg.LinearRegionItem([start_timestamp, finish_timestamp], movable=False) - color = self._stage_colors.get(stage, [100, 100, 100, 100]) + color = colors.get(stage, [100, 100, 100, 100]) region.setBrush(pg.mkBrush(color[:3] + [transparency])) return region return None - def _add_stage_regions(self, + @staticmethod + def _add_stage_regions(colors:dict, plot_item: pg.PlotItem, - point_events: dict[str, list[float]], - dataframe_headers: list[str], + point_events: dict, reg_items: dict, transparency: int = 75) -> None: """ - Добавляет регионы для реальных этапов, если все стадии есть в заголовках датафрейма. + Добавляет регионы для реальных этапов """ stages = point_events.keys() - if all(stage in dataframe_headers for stage in stages): - for stage in stages: - start_t, end_t = point_events[stage] - region = self._create_stage_region(stage, start_t, end_t, transparency) - if region is not None: - region.setZValue(-20) - plot_item.addItem(region) - reg_items["real"].setdefault(stage, []) - reg_items["real"][stage].append(region) + #if all(stage in dataframe_headers for stage in stages): + for stage in stages: + start_t, end_t = point_events[stage] + region = PlotItemGenerator._create_stage_region(colors, stage, start_t, end_t, transparency) + if region is not None: + region.setZValue(-20) + plot_item.addItem(region) + reg_items["real"].setdefault(stage, []) + reg_items["real"][stage].append(region) - def _add_ideal_stage_regions(self, + @staticmethod + def _add_ideal_stage_regions(colors: dict, plot_item: pg.PlotItem, ideal_data: dict[str, Any], point_events: dict[str, list[float]], @@ -382,7 +395,7 @@ class PlotItemGenerator: for i, stage in enumerate(stages): start_t = point_events[stage][0] end_t = start_t + ideal_timings[i] - region = self._create_stage_region(stage, start_t, end_t, transparency) + region = PlotItemGenerator._create_stage_region(colors, stage, start_t, end_t, transparency) if region: region.setZValue(-10) plot_item.addItem(region) diff --git a/src/main.py b/src/main.py index 254de46..f69f64c 100644 --- a/src/main.py +++ b/src/main.py @@ -33,6 +33,7 @@ def main(): window.signal_open_file.connect(controller.open_file) window.signal_open_dir.connect(controller.open_dir) window.signal_save_file.connect(controller.save_file) + window.signal_TCW_for_client.connect(controller.build_TCW_for_client) controller.signal_widgets.connect(window.show_plot_tabs) controller.signal_progress_bar.connect(window.status_widget.set_progress) diff --git a/src/performance/roboter.py b/src/performance/roboter.py index bc25634..1df79b9 100644 --- a/src/performance/roboter.py +++ b/src/performance/roboter.py @@ -261,6 +261,18 @@ class TraceProcessor(BaseRawTraceProcessor): super().__init__(dataparser, textparser, data_detector, text_detector) def prerender(self, data:list[str]) -> None: + + rendered_data = self._render_data(data) + self._mediator.prerender_TCW(self, rendered_data) + + def final_render(self) -> None: + + events = self._detect_stages(self._trace_df, self._text_data) + dataframe = self._rename_df_columns(self._trace_df) + self._mediator.render_TCW(self, [dataframe, events]) + + def _render_data(self, data:list[str]) -> list[pd.DataFrame, dict]: + if data and len(data) == 2: dat_filepath = data[0] txt_filepath = data[1] @@ -271,12 +283,11 @@ class TraceProcessor(BaseRawTraceProcessor): dat_filepath = None txt_filepath = None - trace_df = self._unpack_trace(dat_filepath) - text_data = self._unpack_text(txt_filepath) - events = self._detect_stages(trace_df, text_data) - dataframe = self._rename_df_columns(trace_df) - - self._mediator.notify(self, [dataframe, events]) + self._trace_df = self._unpack_trace(dat_filepath) + self._text_data = self._unpack_text(txt_filepath) + events = self._detect_stages(self._trace_df, self._text_data) + dataframe = self._rename_df_columns(self._trace_df) + return [dataframe, events] def update_settings(self, data:Settings) -> None: self._settings = data @@ -359,7 +370,7 @@ class TraceProcessor(BaseRawTraceProcessor): "Rotor Current, A ME": ["DriveMotorCurr_Act7"], "Cartesian Tool Speed, mm/s ME": ["CartVel_Act"], } - + dataframe = dataframe.copy(deep=True) working_mapping = {key: [item.lower() for item in items] for key, items in correct_mapping.items()} try: diff --git a/src/utils/qt_settings.py b/src/utils/qt_settings.py index 2fb3e29..16b3dd1 100644 --- a/src/utils/qt_settings.py +++ b/src/utils/qt_settings.py @@ -455,6 +455,16 @@ QLabel { }""" colors = [ + '#FF6F61', # яркий коралловый + '#6B5B95', # приглушенный фиолетовый + '#88B04B', # яркий зеленый + '#F7CAC9', # светлый розовый + '#92A8D1', # светло-голубой + '#955251', # теплый терракотовый + '#B565A7', # лавандовый + '#009B77', # глубокий бирюзовый + '#DD4124', # ярко-красный + '#45B8AC', # мягкий мятный '#FF6F61', # яркий коралловый '#6B5B95', # приглушенный фиолетовый '#88B04B', # яркий зеленый