Compare commits

...

2 Commits

5 changed files with 74 additions and 53 deletions

BIN
src - Ярлык.lnk Normal file

Binary file not shown.

View File

@ -45,18 +45,17 @@ class PlotWidget(BasePlotWidget):
return None
@staticmethod
def _init_plot_widget(title: str) -> tuple[pg.PlotWidget, pg.LegendItem]:
plot_widget = pg.PlotWidget(title=title)
def _init_plot_item(title: str) -> tuple[pg.PlotItem, pg.LegendItem]:
plot_item = pg.PlotItem(title=title)
# Оптимизация отображения графиков
plot_widget.setDownsampling(auto=True, mode='peak')
plot_widget.showGrid(x=True, y=True)
plot_widget.setClipToView(True)
legend = pg.LegendItem((80, 60), offset=(70, 20))
legend.setParentItem(plot_widget.graphicsItem())
return plot_widget, legend
plot_item.setDownsampling(auto=True, mode='peak')
plot_item.showGrid(x=True, y=True)
plot_item.setClipToView(True)
legend = plot_item.addLegend(offset=(70, 20))
return plot_item, legend
def _add_stage_regions(self,
plot_widget: pg.PlotWidget,
plot_item: pg.PlotItem,
point_events: dict[str, list[float]],
dataframe_headers: list[str],
reg_items: dict,
@ -71,12 +70,12 @@ class PlotWidget(BasePlotWidget):
region = self._create_stage_region(stage, start_t, end_t, transparency)
if region is not None:
region.setZValue(-20)
plot_widget.addItem(region)
plot_item.addItem(region)
reg_items["real"].setdefault(stage, [])
reg_items["real"][stage].append(region)
def _add_ideal_stage_regions(self,
plot_widget: pg.PlotWidget,
plot_item: pg.PlotItem,
ideal_data: dict[str, Any],
point_events: dict[str, list[float]],
reg_items: dict,
@ -92,12 +91,12 @@ class PlotWidget(BasePlotWidget):
region = self._create_stage_region(stage, start_t, end_t, transparency)
if region:
region.setZValue(-10)
plot_widget.addItem(region)
plot_item.addItem(region)
reg_items["ideal"].setdefault(stage, [])
reg_items["ideal"][stage].append(region)
def _add_ideal_signals(self,
plot_widget: pg.PlotWidget,
plot_item: pg.PlotItem,
ideal_data: dict[str, Any],
point_events: dict[str, list[float]],
ideal_signals: list[dict[str, Any]],
@ -115,13 +114,13 @@ class PlotWidget(BasePlotWidget):
)
if curve:
curve.setZValue(10)
plot_widget.addItem(curve)
plot_item.addItem(curve)
curve_items["ideal"].setdefault(signal["name"], {})
curve_items["ideal"][signal["name"]].setdefault(stage, [])
curve_items["ideal"][signal["name"]][stage].append(curve)
def _add_real_signals(self,
plot_widget: pg.PlotWidget,
plot_item: pg.PlotItem,
dataframe: pd.DataFrame,
real_signals: list[dict[str, Any]],
legend: pg.LegendItem,
@ -132,7 +131,7 @@ class PlotWidget(BasePlotWidget):
dataframe_headers = dataframe.columns.tolist()
for signal in real_signals:
if signal["name"] in dataframe_headers:
plot = plot_widget.plot(dataframe["time"], dataframe[signal["name"]], pen=signal["pen"], fast=True)
plot = plot_item.plot(dataframe["time"], dataframe[signal["name"]], pen=signal["pen"], fast=True)
plot.setZValue(0)
legend.addItem(plot, signal["name"])
curve_items["real"].setdefault(signal["name"], {})
@ -163,8 +162,9 @@ class PlotWidget(BasePlotWidget):
Собирает графический виджет для одного набора данных.
Параметр `data` предполагается списком: [dataframe, points_pocket, useful_data].
"""
widget = QWidget()
layout = QVBoxLayout(widget)
result_widget = QWidget()
result_layout = QVBoxLayout(result_widget)
plot_layout = pg.GraphicsLayoutWidget()
reg_items = {"real":{}, "ideal":{}}
curve_items = {"real":{}, "ideal":{}}
@ -175,7 +175,7 @@ class PlotWidget(BasePlotWidget):
dataframe_headers = dataframe.columns.tolist()
for widget_num, (channel, description) in enumerate(self._plt_channels.items()):
plot_widget, legend = self._init_plot_widget(title=channel)
plot_item, legend = self._init_plot_item(title=channel)
settings = description["Settings"]
TWC_time = 0.0
@ -184,7 +184,12 @@ class PlotWidget(BasePlotWidget):
# TODO: рассчитать корректный параметр range
if settings["mirror ME"]:
dataframe = self._mirror_shift_data("ME", description["Real_signals"], dataframe, range_ME)
dataframe = self._mirror_shift_data(
"ME",
description["Real_signals"],
dataframe,
range_ME
)
# Итерация по точкам
for cur_point, point_data in enumerate(points_pocket):
@ -207,7 +212,7 @@ class PlotWidget(BasePlotWidget):
# Добавляем реальные стадии
if settings["stages"]:
self._add_stage_regions(plot_widget, point_events, dataframe_headers, reg_items, 75)
self._add_stage_regions(plot_item, point_events, dataframe_headers, reg_items, 75)
# TODO: подобрать не вырвеглазные цвета, возможно ограничить зону
if settings["workpiece"]:
@ -220,12 +225,27 @@ class PlotWidget(BasePlotWidget):
rect_item.setZValue(-5)
rect_item.setBrush(pg.mkBrush('grey'))
rect_item.setPen(pg.mkPen('black', width=3))
plot_widget.addItem(rect_item)
plot_item.addItem(rect_item)
if settings["force accuracy"]:
modifier = 0.05
x1 = point_events["Welding"][0]
dx = point_events["Welding"][1] - x1
force = useful_p_data["force"]
y1 = force*(1-modifier)
dy = force*(2*modifier)
rect_item = QGraphicsRectItem(x1, y1, dx, dy)
rect_item.setZValue(-5)
rect_item.setBrush(pg.mkBrush((0,255,0, 50)))
rect_item.setPen(pg.mkPen('black', width=0))
plot_item.addItem(rect_item)
# Добавляем идеальные стадии и идеальные сигналы
if settings["ideals"]:
self._add_ideal_stage_regions(plot_widget, ideal_data, point_events, reg_items, 100)
self._add_ideal_signals(plot_widget, ideal_data, point_events, description["Ideal_signals"], curve_items)
self._add_ideal_stage_regions(plot_item, ideal_data, point_events, reg_items, 100)
self._add_ideal_signals(plot_item, ideal_data, point_events, description["Ideal_signals"], curve_items)
# Подсчёт производительности
if settings["performance"]:
@ -244,26 +264,26 @@ class PlotWidget(BasePlotWidget):
worst_timeframe = point_timeframe
# Добавляем реальные сигналы
self._add_real_signals(plot_widget, dataframe, description["Real_signals"], legend, curve_items)
self._add_real_signals(plot_item, dataframe, description["Real_signals"], legend, curve_items)
if widget_num == 0:
main_plot = plot_widget
main_plot = plot_item
else:
# Связываем остальные графики с основным графиком
plot_widget.setXLink(main_plot)
plot_item.setXLink(main_plot)
# Если есть настройка производительности, добавляем label
if settings["performance"]:
self._add_performance_label(layout, TWC_time, ideal_time, tesla_time)
navigator, ROI_region = self._create_navigator(worst_timeframe, main_plot, dataframe, description["Real_signals"])
self._add_performance_label(result_layout, TWC_time, ideal_time, tesla_time)
layout.addWidget(plot_widget)
navigator, ROI_region = self._create_navigator(worst_timeframe, main_plot)
plot_layout.addItem(plot_item, widget_num, 0)
layout.addWidget(navigator)
plot_layout.addItem(navigator, widget_num+1, 0)
self._sync_main_plot_with_navigator(main_plot, ROI_region)
main_plot.sigXRangeChanged.connect(lambda _, plot=main_plot, region=ROI_region: self._sync_navigator_with_main(main_plot=plot, region=region))
widget.setLayout(layout)
return widget, reg_items, curve_items
result_layout.addWidget(plot_layout)
return result_widget, reg_items, curve_items
def build(self, data: list[list[Any]]) -> None:
"""

View File

@ -125,7 +125,8 @@ class BasePlotWidget:
"ideals": False,
"mirror ME": False,
"workpiece": False,
"force compensation FE": False
"force compensation FE": False,
"force accuracy":True
},
"Real_signals": [
{
@ -156,7 +157,8 @@ class BasePlotWidget:
"ideals": False,
"mirror ME": True,
"workpiece": True,
"force compensation FE": True
"force compensation FE": True,
"force accuracy":False
},
"Real_signals": [
{
@ -187,7 +189,8 @@ class BasePlotWidget:
"ideals": True,
"mirror ME": False,
"workpiece": False,
"force compensation FE": False
"force compensation FE": False,
"force accuracy":False
},
"Real_signals": [
{
@ -237,27 +240,25 @@ class BasePlotWidget:
def _create_navigator(self,
time_region:tuple[float, float],
main_plot: pg.PlotWidget,
dataframe: pd.DataFrame,
real_signals: list[dict[str, Any]]) -> list[pg.PlotWidget, pg.LinearRegionItem]:
main_plot: pg.PlotItem) -> list[pg.PlotWidget, pg.LinearRegionItem]:
"""
Создаёт график-навигатор, отображающий все данные в уменьшенном масштабе.
"""
navigator = pg.PlotWidget(title="Navigator")
navigator = pg.PlotItem(title="Navigator")
navigator.setFixedHeight(100)
for signal in real_signals:
if signal["name"] in dataframe.columns:
x = dataframe["time"]
y = dataframe[signal["name"]]
x_downsampled, y_downsampled = self._downsample_data(x, y, max_points=1000)
navigator.plot(x_downsampled, y_downsampled, pen=signal["pen"], name=signal["name"])
# Получение кривых из main_plot
for curve in main_plot.listDataItems():
# Извлекаем данные из кривой
x, y = curve.getData()
curve_name = curve.opts.get("name", None)
signal_pen = curve.opts.get("pen", None)
x_downsampled, y_downsampled = self._downsample_data(x, y, max_points=1000)
navigator.plot(x_downsampled, y_downsampled, pen=signal_pen, name=curve_name)
ROI_region = pg.LinearRegionItem(values=time_region, movable=True, brush=pg.mkBrush(0, 0, 255, 100), pen=pg.mkPen(width=4))
ROI_region.setBounds([0, x.iloc[-1]])
ROI_region.setBounds([0, x[-1]])
navigator.addItem(ROI_region)
navigator.getPlotItem().getViewBox().setLimits(xMin=0, xMax=x.iloc[-1])
navigator.getViewBox().setLimits(xMin=0, xMax=x[-1])
# Связываем изменение региона навигатора с обновлением области просмотра основного графика
ROI_region.sigRegionChanged.connect(lambda: self._sync_main_plot_with_navigator(main_plot, ROI_region))
@ -265,7 +266,7 @@ class BasePlotWidget:
return navigator, ROI_region
def _sync_main_plot_with_navigator(self,
main_plot: pg.PlotWidget,
main_plot: pg.PlotItem,
region: pg.LinearRegionItem):
"""
Синхронизирует область просмотра основного графика с регионом навигатора.
@ -298,7 +299,7 @@ class BasePlotWidget:
dataframe[signal["name"]] = dataframe[signal["name"]].apply(lambda x: x + shift)
return dataframe
def _sync_navigator_with_main(self, main_plot: pg.PlotWidget, region:pg.LinearRegionItem):
def _sync_navigator_with_main(self, main_plot: pg.PlotItem, region:pg.LinearRegionItem):
"""
Синхронизирует регион навигатора с областью просмотра основного графика.
"""