chode: навигатор вынесен в отдельный класс

This commit is contained in:
Andrew 2025-01-27 19:12:02 +03:00
parent 93be450da6
commit 05ee548704

View File

@ -58,67 +58,6 @@ class PlotWidget(BasePlotWidget):
# Notify mediator # Notify mediator
self._mediator.notify(self, widgets_datapack) self._mediator.notify(self, widgets_datapack)
@staticmethod
def _downsample_data(x:list, y:list, max_points=5000):
"""
Понижает разрешение данных до заданного количества точек для улучшения производительности навигатора.
"""
if len(x) > max_points:
factor = len(x) // max_points
x_downsampled = x[::factor]
y_downsampled = y[::factor]
return x_downsampled, y_downsampled
return x, y
def _create_navigator(self,
time_region:tuple[float, float],
main_plot: pg.PlotItem) -> Tuple[pg.PlotWidget, pg.LinearRegionItem]:
"""
Создаёт график-навигатор, отображающий все данные в уменьшенном масштабе.
"""
navigator = pg.PlotItem(title="Navigator")
navigator.setFixedHeight(100)
# Получение кривых из 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[-1]])
navigator.addItem(ROI_region)
navigator.getViewBox().setLimits(xMin=0, xMax=x[-1])
# Связываем изменение региона навигатора с обновлением области просмотра основного графика
ROI_region.sigRegionChanged.connect(lambda: self._sync_main_plot_with_navigator(main_plot, ROI_region))
return (navigator, ROI_region)
@staticmethod
def _sync_main_plot_with_navigator(main_plot: pg.PlotItem,
region: pg.LinearRegionItem) -> None:
"""
Синхронизирует область просмотра основного графика с регионом навигатора.
"""
x_min, x_max = region.getRegion()
if main_plot:
main_plot.blockSignals(True)
main_plot.setXRange(x_min, x_max, padding=0)
main_plot.blockSignals(False)
@staticmethod
def _sync_navigator_with_main(main_plot: pg.PlotItem, region:pg.LinearRegionItem):
"""
Синхронизирует регион навигатора с областью просмотра основного графика.
"""
if region:
x_min, x_max = main_plot
region.blockSignals(True) # Предотвращаем рекурсию
region.setRegion([x_min, x_max])
region.blockSignals(False)
def _add_performance_label(self, def _add_performance_label(self,
layout: QVBoxLayout, layout: QVBoxLayout,
timings: ChannelTimings, timings: ChannelTimings,
@ -164,7 +103,6 @@ class PlotWidget(BasePlotWidget):
container_widget, container_layout, plot_layout, pyqt_container = self._generate_widget_container() container_widget, container_layout, plot_layout, pyqt_container = self._generate_widget_container()
plotter = PlotItemGenerator(graphic_passport, len(self._plt_channels), self._stage_colors) plotter = PlotItemGenerator(graphic_passport, len(self._plt_channels), self._stage_colors)
for widget_num, (channel, description) in enumerate(self._plt_channels.items()): for widget_num, (channel, description) in enumerate(self._plt_channels.items()):
plot_item, plot_timings = plotter.generate_plot_item(widget_num, channel, description, pyqt_container) plot_item, plot_timings = plotter.generate_plot_item(widget_num, channel, description, pyqt_container)
@ -179,11 +117,9 @@ class PlotWidget(BasePlotWidget):
plot_layout.addItem(plot_item, widget_num, 0) plot_layout.addItem(plot_item, widget_num, 0)
navigator, ROI_region = self._create_navigator(plot_timings.worst_timeframe, main_plot) navigator = NavigatorPlot(plot_timings.worst_timeframe, main_plot)
if navigator is not None: if navigator is not None:
plot_layout.addItem(navigator, widget_num+1, 0) 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))
container_layout.addWidget(plot_layout) container_layout.addWidget(plot_layout)
container_widget.setProperty("pyqt_container", pyqt_container) container_widget.setProperty("pyqt_container", pyqt_container)
@ -517,4 +453,72 @@ class PlotItemGenerator:
dataframe.loc[point_idxs] = self._shift_data("FE", real_signals, dataframe.loc[point_idxs], lambda x: x + F_comp) dataframe.loc[point_idxs] = self._shift_data("FE", real_signals, dataframe.loc[point_idxs], lambda x: x + F_comp)
return dataframe return dataframe
class NavigatorPlot(pg.PlotItem):
def __init__(self,
time_region:tuple[float, float],
main_plot: pg.PlotItem):
super().__init__()
self._init_navigator(time_region, main_plot)
@staticmethod
def _downsample_data(x:list, y:list, max_points=5000):
"""
Понижает разрешение данных до заданного количества точек для улучшения производительности навигатора.
"""
if len(x) > max_points:
factor = len(x) // max_points
x_downsampled = x[::factor]
y_downsampled = y[::factor]
return x_downsampled, y_downsampled
return x, y
@staticmethod
def _sync_main_plot_with_navigator(main_plot: pg.PlotItem,
region: pg.LinearRegionItem) -> None:
"""
Синхронизирует область просмотра основного графика с регионом навигатора.
"""
x_min, x_max = region.getRegion()
if main_plot:
main_plot.blockSignals(True)
main_plot.setXRange(x_min, x_max, padding=0)
main_plot.blockSignals(False)
@staticmethod
def _sync_navigator_with_main(main_plot: pg.PlotItem, region:pg.LinearRegionItem):
"""
Синхронизирует регион навигатора с областью просмотра основного графика.
"""
if region:
x_min, x_max = main_plot
region.blockSignals(True) # Предотвращаем рекурсию
region.setRegion([x_min, x_max])
region.blockSignals(False)
def _init_navigator(self,
time_region:tuple[float, float],
main_plot: pg.PlotItem) -> None:
"""
Создаёт график-навигатор, отображающий все данные в уменьшенном масштабе.
"""
self.setTitle("Navigator")
self.setFixedHeight(100)
# Получение кривых из 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)
self.plot(x_downsampled, y_downsampled, pen=signal_pen, name=curve_name)
self.ROI_region = pg.LinearRegionItem(values=time_region, movable=True, brush=pg.mkBrush(0, 0, 255, 100), pen=pg.mkPen(width=4))
self.ROI_region.setBounds([0, x[-1]])
self.addItem(self.ROI_region)
self.getViewBox().setLimits(xMin=0, xMax=x[-1])
# Связываем изменение региона навигатора с обновлением области просмотра основного графика
self.ROI_region.sigRegionChanged.connect(lambda: self._sync_main_plot_with_navigator(main_plot, self.ROI_region))
main_plot.sigXRangeChanged.connect(lambda _, plot=main_plot, region=self.ROI_region: self._sync_navigator_with_main(main_plot=plot, region=region))