dev: функционал разделен на подготовительный этап (настройка фильтра) и финальный по соответствующим кнопкам (open filder и calc TCW)

This commit is contained in:
Andrew 2025-02-06 15:59:16 +03:00
parent 86c7c8d1e6
commit 90b6660a15
10 changed files with 120 additions and 45 deletions

View File

@ -3,10 +3,10 @@
0.008 0.008
], ],
"actuator_zero_velocity_trashold": [ "actuator_zero_velocity_trashold": [
10.0 100.0
], ],
"actuator_finishing_velocity": [ "actuator_finishing_velocity": [
2050.0 2000.0
], ],
"actuator_finishing_velocity_trashold": [ "actuator_finishing_velocity_trashold": [
200.0 200.0

View File

@ -104,7 +104,12 @@ class BaseMediator:
data: Union[list[str], list[pd.DataFrame], list[list], list[QWidget], pd.DataFrame]): 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: def set_mode(self, mode: int) -> None:
@ -282,7 +287,8 @@ class BaseFileManager:
monitor: Optional[BaseDirectoryMonitor] = None): monitor: Optional[BaseDirectoryMonitor] = None):
self._mediator = mediator self._mediator = mediator
self._monitor = monitor self._monitor = monitor
self._paths_library = set() self._paths_library:set = set()
self._mode = 0
@property @property
def paths_library(self) -> set: def paths_library(self) -> set:
@ -471,10 +477,12 @@ class BaseRawTraceProcessor:
self._trace_df = None self._trace_df = None
self._text_data = None self._text_data = None
def prerender(self, data:list[str]) -> None: def prerender(self, data:list[str]) -> None:
... ...
def final_render(self) -> None:
...
def update_settings(self, data:Settings) -> None: def update_settings(self, data:Settings) -> None:
... ...

View File

@ -33,7 +33,10 @@ class Controller(BaseController):
self._file_manager.open_custom_file(filepath) self._file_manager.open_custom_file(filepath)
def open_dir(self, dirpath:str) -> None: 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: def save_file(self, data:list[str, QTabWidget]) -> None:
filepath, tab = data filepath, tab = data

View File

@ -9,7 +9,8 @@ class FileManager(BaseFileManager):
def replot_all(self) -> None: def replot_all(self) -> None:
if self._paths_library is not 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: def open_custom_file(self, path:str) -> None:
self._paths_library.add(path) self._paths_library.add(path)
@ -22,14 +23,17 @@ class FileManager(BaseFileManager):
self._paths_library.clear() self._paths_library.clear()
self._paths_library.add('') self._paths_library.add('')
self._mediator.notify(self, list(self._paths_library)) self._mediator.notify(self, list(self._paths_library))
self._mode = 1
case 2: # Режим онлайн-мониторинга папки case 2: # Режим онлайн-мониторинга папки
self._monitor.init_state() self._monitor.init_state()
self._monitor.start() self._monitor.start()
self._mode = 2
case 3: # Режим работы с трейсами клиента case 3: # Режим работы с трейсами клиента
self._monitor.stop() self._monitor.stop()
self._paths_library.clear() self._paths_library.clear()
self._mode = 3
def update_monitor_settings(self, settings:Settings) -> None: def update_monitor_settings(self, settings:Settings) -> None:
directory_path = settings.system['trace_storage_path'][0] directory_path = settings.system['trace_storage_path'][0]
@ -54,6 +58,8 @@ class FileManager(BaseFileManager):
self._mediator.notify(list(new)) self._mediator.notify(list(new))
def open_raw_traces_dir(self, path:str) -> None: def open_raw_traces_dir(self, path:str) -> None:
self._paths_library.clear()
self._paths_library.add(path)
dat_file, txt_file = None, None dat_file, txt_file = None, None
for entry in os.listdir(path): for entry in os.listdir(path):
full_path = os.path.join(path, entry) full_path = os.path.join(path, entry)
@ -69,7 +75,7 @@ class FileManager(BaseFileManager):
break break
if dat_file and txt_file: if dat_file and txt_file:
self._mediator.prerender([dat_file, txt_file]) self._mediator.prerender_TCW(self, [dat_file, txt_file])

View File

@ -20,7 +20,7 @@ class Mediator(BaseMediator):
def notify(self, def notify(self,
source: Union[BaseFileManager, BaseDataConverter, BasePointPassportFormer, BasePlotWidget, BaseController, BaseRawTraceProcessor], 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): if issubclass(source.__class__, BaseFileManager):
self._controller.update_status("CSV found! Calculating...") self._controller.update_status("CSV found! Calculating...")
@ -31,7 +31,7 @@ class Mediator(BaseMediator):
self._passport_former.form_passports(data) self._passport_former.form_passports(data)
if issubclass(source.__class__, BasePointPassportFormer): if issubclass(source.__class__, BasePointPassportFormer):
self._controller.update_progress(2) self._controller.update_progress(10)
self._plot.build(data) self._plot.build(data)
if issubclass(source.__class__, BasePlotWidget): if issubclass(source.__class__, BasePlotWidget):
@ -43,12 +43,32 @@ class Mediator(BaseMediator):
self._passport_former.update_settings(data) self._passport_former.update_settings(data)
self._trace_processor.update_settings(data) self._trace_processor.update_settings(data)
if issubclass(source.__class__, BaseRawTraceProcessor): def prerender_TCW(self, source:Union[BaseController, BaseFileManager, BaseRawTraceProcessor],
self._passport_former.form_customer_passport(data) data:Union[str, list[str], list[pd.DataFrame, dict]]) -> None:
def prerender(self, data:list[str]) -> 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) 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 set_mode(self, mode: int) -> None: def set_mode(self, mode: int) -> None:
self._plot.set_mode(mode) self._plot.set_mode(mode)
self._file_manager.set_mode(mode) self._file_manager.set_mode(mode)

View File

@ -19,6 +19,7 @@ class MainWindow(BaseMainWindow):
signal_open_file = pyqtSignal(str) signal_open_file = pyqtSignal(str)
signal_save_file = pyqtSignal(list) signal_save_file = pyqtSignal(list)
signal_open_dir = pyqtSignal(str) signal_open_dir = pyqtSignal(str)
signal_TCW_for_client = pyqtSignal()
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
@ -118,9 +119,11 @@ class MainWindow(BaseMainWindow):
#TODO: привязать действия к кнопкам #TODO: привязать действия к кнопкам
client_widget.open_folder_btn.clicked.connect(self._open_folder) client_widget.open_folder_btn.clicked.connect(self._open_folder)
client_widget.save_screen_btn.clicked.connect(self._save_plots) 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()) 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: def _set_mode(self, num:int) -> None:
match num: match num:

View File

@ -63,7 +63,7 @@ class PlotWidget(BasePlotWidget):
finally: finally:
self._mediator.notify(self, widgets_datapack) 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) print(3)
def _build_raw_plotitem(self, def _build_raw_plotitem(self,
dataframe:pd.DataFrame, data:list[pd.DataFrame, dict],
pyqt_container:PlotItems) -> pg.GraphicsLayoutWidget: pyqt_container:PlotItems) -> pg.GraphicsLayoutWidget:
plot_item, legend = PlotItemGenerator._init_plot_item("Customer data") plot_item, legend = PlotItemGenerator._init_plot_item("Customer data")
dataframe, events = data
channels = dataframe.columns.to_list() channels = dataframe.columns.to_list()
for i, channel in enumerate(channels): 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) legend.addItem(plot, channel)
pyqt_container.curves["real"].setdefault(channel, {}) pyqt_container.curves["real"].setdefault(channel, {})
pyqt_container.curves["real"][channel] = plot 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 = pg.GraphicsLayoutWidget()
plot_layout.addItem(plot_item) plot_layout.addItem(plot_item)
return plot_layout return plot_layout
def _build_performance_label(self, def _build_performance_label(self,
@ -269,7 +280,7 @@ class PlotItemGenerator:
dataframe = self._apply_force_compensation(force, k_hardness, dataframe, point_data.timeframe, signals) dataframe = self._apply_force_compensation(force, k_hardness, dataframe, point_data.timeframe, signals)
if settings.get("stages", False): 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): if settings.get("force accuracy", False):
force = point_data.useful_data["force"] force = point_data.useful_data["force"]
@ -283,7 +294,7 @@ class PlotItemGenerator:
self._add_workpiece(point_data, plot_item) self._add_workpiece(point_data, plot_item)
if settings.get("ideals", False): 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) 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): if settings.get("performance", False):
@ -333,7 +344,8 @@ class PlotItemGenerator:
) )
return None return None
def _create_stage_region(self, @staticmethod
def _create_stage_region(colors:dict,
stage: str, stage: str,
start_timestamp: float, start_timestamp: float,
finish_timestamp: float, finish_timestamp: float,
@ -343,32 +355,33 @@ class PlotItemGenerator:
""" """
if start_timestamp is not None and finish_timestamp is not None: if start_timestamp is not None and finish_timestamp is not None:
region = pg.LinearRegionItem([start_timestamp, finish_timestamp], movable=False) 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])) region.setBrush(pg.mkBrush(color[:3] + [transparency]))
return region return region
return None return None
def _add_stage_regions(self, @staticmethod
def _add_stage_regions(colors:dict,
plot_item: pg.PlotItem, plot_item: pg.PlotItem,
point_events: dict[str, list[float]], point_events: dict,
dataframe_headers: list[str],
reg_items: dict, reg_items: dict,
transparency: int = 75) -> None: transparency: int = 75) -> None:
""" """
Добавляет регионы для реальных этапов, если все стадии есть в заголовках датафрейма. Добавляет регионы для реальных этапов
""" """
stages = point_events.keys() stages = point_events.keys()
if all(stage in dataframe_headers for stage in stages): #if all(stage in dataframe_headers for stage in stages):
for stage in stages: for stage in stages:
start_t, end_t = point_events[stage] start_t, end_t = point_events[stage]
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 is not None: if region is not None:
region.setZValue(-20) region.setZValue(-20)
plot_item.addItem(region) plot_item.addItem(region)
reg_items["real"].setdefault(stage, []) reg_items["real"].setdefault(stage, [])
reg_items["real"][stage].append(region) reg_items["real"][stage].append(region)
def _add_ideal_stage_regions(self, @staticmethod
def _add_ideal_stage_regions(colors: dict,
plot_item: pg.PlotItem, plot_item: pg.PlotItem,
ideal_data: dict[str, Any], ideal_data: dict[str, Any],
point_events: dict[str, list[float]], point_events: dict[str, list[float]],
@ -382,7 +395,7 @@ class PlotItemGenerator:
for i, stage in enumerate(stages): for i, stage in enumerate(stages):
start_t = point_events[stage][0] start_t = point_events[stage][0]
end_t = start_t + ideal_timings[i] 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: if region:
region.setZValue(-10) region.setZValue(-10)
plot_item.addItem(region) plot_item.addItem(region)

View File

@ -33,6 +33,7 @@ def main():
window.signal_open_file.connect(controller.open_file) window.signal_open_file.connect(controller.open_file)
window.signal_open_dir.connect(controller.open_dir) window.signal_open_dir.connect(controller.open_dir)
window.signal_save_file.connect(controller.save_file) 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_widgets.connect(window.show_plot_tabs)
controller.signal_progress_bar.connect(window.status_widget.set_progress) controller.signal_progress_bar.connect(window.status_widget.set_progress)

View File

@ -261,6 +261,18 @@ class TraceProcessor(BaseRawTraceProcessor):
super().__init__(dataparser, textparser, data_detector, text_detector) super().__init__(dataparser, textparser, data_detector, text_detector)
def prerender(self, data:list[str]) -> None: 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: if data and len(data) == 2:
dat_filepath = data[0] dat_filepath = data[0]
txt_filepath = data[1] txt_filepath = data[1]
@ -271,12 +283,11 @@ class TraceProcessor(BaseRawTraceProcessor):
dat_filepath = None dat_filepath = None
txt_filepath = None txt_filepath = None
trace_df = self._unpack_trace(dat_filepath) self._trace_df = self._unpack_trace(dat_filepath)
text_data = self._unpack_text(txt_filepath) self._text_data = self._unpack_text(txt_filepath)
events = self._detect_stages(trace_df, text_data) events = self._detect_stages(self._trace_df, self._text_data)
dataframe = self._rename_df_columns(trace_df) dataframe = self._rename_df_columns(self._trace_df)
return [dataframe, events]
self._mediator.notify(self, [dataframe, events])
def update_settings(self, data:Settings) -> None: def update_settings(self, data:Settings) -> None:
self._settings = data self._settings = data
@ -359,7 +370,7 @@ class TraceProcessor(BaseRawTraceProcessor):
"Rotor Current, A ME": ["DriveMotorCurr_Act7"], "Rotor Current, A ME": ["DriveMotorCurr_Act7"],
"Cartesian Tool Speed, mm/s ME": ["CartVel_Act"], "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()} working_mapping = {key: [item.lower() for item in items] for key, items in correct_mapping.items()}
try: try:

View File

@ -455,6 +455,16 @@ QLabel {
}""" }"""
colors = [ colors = [
'#FF6F61', # яркий коралловый
'#6B5B95', # приглушенный фиолетовый
'#88B04B', # яркий зеленый
'#F7CAC9', # светлый розовый
'#92A8D1', # светло-голубой
'#955251', # теплый терракотовый
'#B565A7', # лавандовый
'#009B77', # глубокий бирюзовый
'#DD4124', # ярко-красный
'#45B8AC', # мягкий мятный
'#FF6F61', # яркий коралловый '#FF6F61', # яркий коралловый
'#6B5B95', # приглушенный фиолетовый '#6B5B95', # приглушенный фиолетовый
'#88B04B', # яркий зеленый '#88B04B', # яркий зеленый