2024-11-25 14:01:09 +03:00
|
|
|
import pandas as pd
|
2024-12-05 11:19:55 +03:00
|
|
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QGraphicsRectItem
|
2024-11-25 14:01:09 +03:00
|
|
|
import pyqtgraph as pg
|
|
|
|
|
import numpy as np
|
|
|
|
|
from numpy import floating
|
|
|
|
|
from typing import Optional, Any, NamedTuple
|
|
|
|
|
|
2024-12-04 20:01:30 +03:00
|
|
|
from src.utils.base.base import BasePlotWidget
|
2024-11-25 17:20:00 +03:00
|
|
|
|
2024-11-25 14:01:09 +03:00
|
|
|
class ProcessStage(NamedTuple):
|
|
|
|
|
mean_value: floating[Any]
|
|
|
|
|
start_index: int
|
|
|
|
|
finish_index: int
|
|
|
|
|
|
|
|
|
|
|
2024-12-04 20:01:30 +03:00
|
|
|
class PlotWidget(BasePlotWidget):
|
2024-12-02 11:04:15 +03:00
|
|
|
def _create_curve_ideal(self,
|
2024-12-04 20:01:30 +03:00
|
|
|
signal: str,
|
|
|
|
|
ideal_data: pd.DataFrame,
|
2024-12-02 11:04:15 +03:00
|
|
|
start_timestamp: float,
|
|
|
|
|
finish_timestamp: float) -> Optional[pg.PlotDataItem]:
|
2024-11-25 14:01:09 +03:00
|
|
|
|
2024-12-02 11:04:15 +03:00
|
|
|
if start_timestamp and finish_timestamp:
|
2024-12-04 20:01:30 +03:00
|
|
|
plot = pg.PlotDataItem(x=start_timestamp+ideal_data["time"], y=ideal_data[signal["name"]], pen=signal["pen"])
|
2024-11-25 14:01:09 +03:00
|
|
|
return plot
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def _create_stage_region(self,
|
|
|
|
|
stage: str,
|
2024-12-02 11:04:15 +03:00
|
|
|
start_timestamp: float,
|
2024-12-05 12:02:07 +03:00
|
|
|
finish_timestamp: float,
|
|
|
|
|
transparency:int) -> Optional[pg.LinearRegionItem]:
|
2024-12-02 11:04:15 +03:00
|
|
|
|
|
|
|
|
if start_timestamp and finish_timestamp:
|
|
|
|
|
region = pg.LinearRegionItem([start_timestamp, finish_timestamp], movable=False)
|
2024-12-05 12:02:07 +03:00
|
|
|
region.setBrush(pg.mkBrush(self._stage_colors[stage][:3] + [transparency]))
|
2024-12-02 11:04:15 +03:00
|
|
|
return region
|
|
|
|
|
return None
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
@staticmethod
|
2024-11-25 17:20:00 +03:00
|
|
|
def _init_plot_widget(title: str) -> tuple[pg.PlotWidget, pg.LegendItem]:
|
2024-11-25 14:01:09 +03:00
|
|
|
plot_widget = pg.PlotWidget(title=title)
|
|
|
|
|
plot_widget.showGrid(x=True, y=True)
|
|
|
|
|
legend = pg.LegendItem((80, 60), offset=(70, 20))
|
|
|
|
|
legend.setParentItem(plot_widget.graphicsItem())
|
|
|
|
|
return plot_widget, legend
|
|
|
|
|
|
|
|
|
|
def get_stage_info(self,
|
|
|
|
|
stage: str,
|
|
|
|
|
dataframe: pd.DataFrame,
|
|
|
|
|
signal_name: str) -> Optional[ProcessStage]:
|
|
|
|
|
|
2024-12-04 20:01:30 +03:00
|
|
|
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
|
|
|
|
|
|
2024-12-05 11:19:55 +03:00
|
|
|
def _build_widget(self, data: list[pd.DataFrame, dict, dict, list]) -> QWidget:
|
2024-11-25 14:01:09 +03:00
|
|
|
widget = QWidget()
|
|
|
|
|
layout = QVBoxLayout()
|
|
|
|
|
|
|
|
|
|
for channel, description in self._plt_channels.items():
|
2024-12-04 20:01:30 +03:00
|
|
|
performance_list = []
|
|
|
|
|
df_continuous = pd.DataFrame({})
|
2024-11-25 14:01:09 +03:00
|
|
|
plot_widget, legend = self._init_plot_widget(title=channel)
|
|
|
|
|
settings = description["Settings"]
|
2024-12-05 11:19:55 +03:00
|
|
|
|
2024-12-05 12:02:07 +03:00
|
|
|
if settings["performance"]:
|
|
|
|
|
TWC_time = 0
|
|
|
|
|
ideal_time = 0
|
|
|
|
|
|
|
|
|
|
for cur_point, (dataframe, ideal_data, events, tesla_time) in enumerate(data):
|
2024-12-04 20:01:30 +03:00
|
|
|
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:
|
2024-12-03 17:21:22 +03:00
|
|
|
start_t, end_t = events[stage]
|
2024-12-05 12:02:07 +03:00
|
|
|
region = self._create_stage_region(stage, start_t, end_t, 75)
|
2024-12-04 20:01:30 +03:00
|
|
|
if region:
|
|
|
|
|
plot_widget.addItem(region)
|
|
|
|
|
|
|
|
|
|
if settings["ideals"]:
|
2024-12-05 12:02:07 +03:00
|
|
|
for i, stage in enumerate(stages):
|
|
|
|
|
start_t, _ = events[stage]
|
|
|
|
|
end_t = start_t + ideal_data["Ideal timings"][i]
|
|
|
|
|
region = self._create_stage_region(stage, start_t, end_t, 125)
|
|
|
|
|
if region:
|
|
|
|
|
plot_widget.addItem(region)
|
2024-12-04 20:01:30 +03:00
|
|
|
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)
|
2024-12-03 17:21:22 +03:00
|
|
|
|
|
|
|
|
if settings["performance"]:
|
2024-12-05 12:02:07 +03:00
|
|
|
if cur_point == len(data) -1:
|
|
|
|
|
ideal_time += sum(ideal_data["Ideal timings"][0:3])
|
|
|
|
|
TWC_time += sum([events[stage][1] - events[stage][0] for stage in ["Closing", "Squeeze", "Welding"]])
|
|
|
|
|
else:
|
|
|
|
|
for stage in stages:
|
|
|
|
|
TWC_time += events[stage][1] - events[stage][0]
|
|
|
|
|
ideal_time += ideal_data["Ideal cycle"]
|
2024-12-04 20:01:30 +03:00
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
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,
|
2024-11-25 14:01:09 +03:00
|
|
|
brush=pg.mkBrush([0, 250, 0, 100]))
|
2024-12-04 20:01:30 +03:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
|
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)"""
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
for signal in description["Real_signals"]:
|
|
|
|
|
if signal["name"] in dataframe_headers:
|
2024-12-04 20:01:30 +03:00
|
|
|
plot = plot_widget.plot(df_continuous["time"], df_continuous[signal["name"]], pen=signal["pen"])
|
2024-11-25 14:01:09 +03:00
|
|
|
legend.addItem(plot, signal["name"])
|
|
|
|
|
|
2024-12-04 20:01:30 +03:00
|
|
|
if settings["performance"]:
|
2024-12-05 12:02:07 +03:00
|
|
|
tesla_TWC = round((1 - TWC_time/tesla_time)*100,2)
|
|
|
|
|
tesla_ideal = round((1 - ideal_time/tesla_time)*100,2)
|
|
|
|
|
TWC_ideal = round((TWC_time/ideal_time - 1)*100,2)
|
|
|
|
|
performance_label = QLabel(f"Сокращение длительности: фактическое = {tesla_TWC} %, идеальное = {tesla_ideal} %, разница идеала и факта = {TWC_ideal}%")
|
2024-12-04 20:01:30 +03:00
|
|
|
layout.addWidget(performance_label)
|
2024-11-25 14:01:09 +03:00
|
|
|
layout.addWidget(plot_widget)
|
|
|
|
|
|
|
|
|
|
widget.setLayout(layout)
|
|
|
|
|
return widget
|
|
|
|
|
|
|
|
|
|
def build(self, data: list[pd.DataFrame]) -> None:
|
|
|
|
|
widgets = [self._build_widget(data_sample) for data_sample in data]
|
|
|
|
|
self._mediator.notify(self, widgets)
|
|
|
|
|
|
2024-11-25 17:20:00 +03:00
|
|
|
|
2024-11-25 14:01:09 +03:00
|
|
|
|