dev: изменил создание виджета с графиками

This commit is contained in:
Andrew 2024-12-18 14:54:40 +03:00
parent c3d976f6a6
commit 3c7040692e
5 changed files with 54 additions and 51 deletions

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

Binary file not shown.

View File

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

View File

@ -240,27 +240,25 @@ class BasePlotWidget:
def _create_navigator(self, def _create_navigator(self,
time_region:tuple[float, float], time_region:tuple[float, float],
main_plot: pg.PlotWidget, main_plot: pg.PlotItem) -> list[pg.PlotWidget, pg.LinearRegionItem]:
dataframe: pd.DataFrame,
real_signals: list[dict[str, Any]]) -> list[pg.PlotWidget, pg.LinearRegionItem]:
""" """
Создаёт график-навигатор, отображающий все данные в уменьшенном масштабе. Создаёт график-навигатор, отображающий все данные в уменьшенном масштабе.
""" """
navigator = pg.PlotWidget(title="Navigator") navigator = pg.PlotItem(title="Navigator")
navigator.setFixedHeight(100) navigator.setFixedHeight(100)
# Получение кривых из main_plot
for signal in real_signals: for curve in main_plot.listDataItems():
if signal["name"] in dataframe.columns: # Извлекаем данные из кривой
x = dataframe["time"] x, y = curve.getData()
y = dataframe[signal["name"]] 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) x_downsampled, y_downsampled = self._downsample_data(x, y, max_points=1000)
navigator.plot(x_downsampled, y_downsampled, pen=signal["pen"], name=signal["name"]) 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 = 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.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)) ROI_region.sigRegionChanged.connect(lambda: self._sync_main_plot_with_navigator(main_plot, ROI_region))
@ -268,7 +266,7 @@ class BasePlotWidget:
return navigator, ROI_region return navigator, ROI_region
def _sync_main_plot_with_navigator(self, def _sync_main_plot_with_navigator(self,
main_plot: pg.PlotWidget, main_plot: pg.PlotItem,
region: pg.LinearRegionItem): region: pg.LinearRegionItem):
""" """
Синхронизирует область просмотра основного графика с регионом навигатора. Синхронизирует область просмотра основного графика с регионом навигатора.
@ -301,7 +299,7 @@ class BasePlotWidget:
dataframe[signal["name"]] = dataframe[signal["name"]].apply(lambda x: x + shift) dataframe[signal["name"]] = dataframe[signal["name"]].apply(lambda x: x + shift)
return dataframe 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):
""" """
Синхронизирует регион навигатора с областью просмотра основного графика. Синхронизирует регион навигатора с областью просмотра основного графика.
""" """