From b8048963b4bfc2fd0e9c225be267d2a97f00d65b Mon Sep 17 00:00:00 2001 From: Patrick Valsecchi Date: Tue, 8 Jul 2025 13:06:05 +0200 Subject: [PATCH] Can now show only the current time range in XY graphs --- plotjuggler_app/mainwindow.cpp | 4 ++ plotjuggler_app/plotwidget.cpp | 56 +++++++++++++++++++ plotjuggler_app/plotwidget.h | 11 ++++ plotjuggler_app/plotwidget_editor.cpp | 9 +++ plotjuggler_app/plotwidget_editor.h | 2 + plotjuggler_app/plotwidget_editor.ui | 10 ++++ plotjuggler_app/point_series_xy.cpp | 19 ++++++- plotjuggler_app/point_series_xy.h | 3 + .../include/PlotJuggler/plotdatabase.h | 4 ++ 9 files changed, 116 insertions(+), 2 deletions(-) diff --git a/plotjuggler_app/mainwindow.cpp b/plotjuggler_app/mainwindow.cpp index a8e35b6c5..225695250 100644 --- a/plotjuggler_app/mainwindow.cpp +++ b/plotjuggler_app/mainwindow.cpp @@ -1000,6 +1000,10 @@ void MainWindow::onPlotZoomChanged(PlotWidget* modified_plot, QRectF new_range) plot->on_zoomOutVertical_triggered(false); plot->replot(); } + if (!modified_plot->isXYPlot() && plot->isXYPlot()) + { + plot->setXYTimeFilter(Range({ new_range.left(), new_range.right() })); + } }; this->forEachWidget(visitor); } diff --git a/plotjuggler_app/plotwidget.cpp b/plotjuggler_app/plotwidget.cpp index 9f06b59e8..469dfc4ca 100644 --- a/plotjuggler_app/plotwidget.cpp +++ b/plotjuggler_app/plotwidget.cpp @@ -80,6 +80,9 @@ PlotWidget::PlotWidget(PlotDataMapRef& datamap, QWidget* parent) , _time_offset(0.0) , _transform_select_dialog(nullptr) , _context_menu_enabled(true) + , _xy_time_filtered(false) + , _xy_time_filter( + { -std::numeric_limits::max(), std::numeric_limits::max() }) { connect(this, &PlotWidget::curveListChanged, this, [this]() { this->updateMaximumZoomArea(); }); @@ -714,6 +717,11 @@ QDomElement PlotWidget::xmlSaveState(QDomDocument& doc) const } } + if (isXYPlot()) + { + plot_el.setAttribute("xy_time_filtered", isXYTimeFiltered() ? "true" : "false"); + } + plot_el.setAttribute("mode", isXYPlot() ? "XYPlot" : "TimeSeries"); plot_el.setAttribute("flip_x", isXYPlot() && _flip_x->isChecked() ? "true" : "false"); @@ -924,6 +932,11 @@ bool PlotWidget::xmlLoadState(QDomElement& plot_widget, bool autozoom) } } + if (isXYPlot()) + { + setXYTimeFiltered(plot_widget.attribute("xy_time_filtered") == "true"); + } + if (autozoom) { updateMaximumZoomArea(); @@ -1751,3 +1764,46 @@ QwtSeriesWrapper* PlotWidget::createTimeSeries(const PlotData* data, output->updateCache(true); return output; } + +bool PlotWidget::isXYTimeFiltered() const +{ + return _xy_time_filtered; +} + +void PlotWidget::setXYTimeFiltered(bool filtered) +{ + _xy_time_filtered = filtered; + updateXYTimeFilter(); +} + +void PlotWidget::updateXYTimeFilter() +{ + for (auto& it : curveList()) + { + if (auto pointSeries = dynamic_cast(it.curve->data())) + { + pointSeries->setTimeFilter(_xy_time_filtered ? + _xy_time_filter : + Range({ -std::numeric_limits::max(), + std::numeric_limits::max() })); + } + } + updateMaximumZoomArea(); + rescaleEqualAxisScaling(); + replot(); +} + +void PlotWidget::setXYTimeFilter(Range filter) +{ + if (_xy_time_filter == filter) + { + return; + } + _xy_time_filter = filter; + updateXYTimeFilter(); +} + +Range PlotWidget::xyTimeFilter() const +{ + return _xy_time_filter; +} diff --git a/plotjuggler_app/plotwidget.h b/plotjuggler_app/plotwidget.h index cf04cf966..502d77fc6 100644 --- a/plotjuggler_app/plotwidget.h +++ b/plotjuggler_app/plotwidget.h @@ -82,6 +82,12 @@ class PlotWidget : public PlotWidgetBase void updateStatistics(bool forceUpdate = false); + bool isXYTimeFiltered() const; + + void setXYTimeFiltered(bool filtered); + void setXYTimeFilter(Range filter); + Range xyTimeFilter() const; + protected: PlotDataMapRef& _mapped_data; @@ -227,6 +233,11 @@ private slots: bool _context_menu_enabled; + bool _xy_time_filtered; + Range _xy_time_filter; + + void updateXYTimeFilter(); + // void updateMaximumZoomArea(); void rescaleEqualAxisScaling(); void overrideCursonMove(); diff --git a/plotjuggler_app/plotwidget_editor.cpp b/plotjuggler_app/plotwidget_editor.cpp index 117f34d63..ddb1d0f88 100644 --- a/plotjuggler_app/plotwidget_editor.cpp +++ b/plotjuggler_app/plotwidget_editor.cpp @@ -37,6 +37,7 @@ PlotwidgetEditor::PlotwidgetEditor(PlotWidget* plotwidget, QWidget* parent) _plotwidget->xmlLoadState(saved_state); _plotwidget->on_changeTimeOffset(plotwidget->timeOffset()); _plotwidget->setContextMenuEnabled(false); + _plotwidget->setXYTimeFilter(plotwidget->xyTimeFilter()); _bounding_rect_original = _plotwidget_origin->currentBoundingRect(); @@ -111,6 +112,9 @@ PlotwidgetEditor::PlotwidgetEditor(PlotWidget* plotwidget, QWidget* parent) { ui->listWidget->item(0)->setSelected(true); } + + ui->checkBoxXYTimeFiltered->setChecked(plotwidget->isXYTimeFiltered()); + ui->checkBoxXYTimeFiltered->setVisible(plotwidget->isXYPlot()); } PlotwidgetEditor::~PlotwidgetEditor() @@ -332,6 +336,11 @@ void PlotwidgetEditor::on_radioStepsInv_toggled(bool checked) } } +void PlotwidgetEditor::on_checkBoxXYTimeFiltered_toggled(bool checked) +{ + _plotwidget->setXYTimeFiltered(checked); +} + void PlotwidgetEditor::on_checkBoxMax_toggled(bool checked) { ui->lineLimitMax->setEnabled(checked); diff --git a/plotjuggler_app/plotwidget_editor.h b/plotjuggler_app/plotwidget_editor.h index 6c1ac7cf2..56e6a2fb1 100644 --- a/plotjuggler_app/plotwidget_editor.h +++ b/plotjuggler_app/plotwidget_editor.h @@ -88,6 +88,8 @@ private slots: void on_radioStepsInv_toggled(bool checked); + void on_checkBoxXYTimeFiltered_toggled(bool checked); + private: Ui::PlotWidgetEditor* ui; diff --git a/plotjuggler_app/plotwidget_editor.ui b/plotjuggler_app/plotwidget_editor.ui index cc49f2c34..26edd3a0e 100644 --- a/plotjuggler_app/plotwidget_editor.ui +++ b/plotjuggler_app/plotwidget_editor.ui @@ -199,6 +199,16 @@ + + + + Qt::NoFocus + + + X/Y time filter + + + diff --git a/plotjuggler_app/point_series_xy.cpp b/plotjuggler_app/point_series_xy.cpp index 9093c63a8..c7dd116fa 100644 --- a/plotjuggler_app/point_series_xy.cpp +++ b/plotjuggler_app/point_series_xy.cpp @@ -13,6 +13,8 @@ PointSeriesXY::PointSeriesXY(const PlotData* x_axis, const PlotData* y_axis) , _x_axis(x_axis) , _y_axis(y_axis) , _cached_curve("", x_axis->group()) + , _time_filter( + { -std::numeric_limits::max(), std::numeric_limits::max() }) { updateCache(true); } @@ -68,8 +70,11 @@ void PointSeriesXY::updateCache(bool reset_old_data) throw std::runtime_error("X and Y axis don't share the same time axis"); } - const QPointF p(_x_axis->at(i).y, _y_axis->at(i).y); - _cached_curve.pushBack({ p.x(), p.y() }); + if (_x_axis->at(i).x >= _time_filter.min && _x_axis->at(i).x <= _time_filter.max) + { + const QPointF p(_x_axis->at(i).y, _y_axis->at(i).y); + _cached_curve.pushBack({ p.x(), p.y() }); + } } } @@ -77,3 +82,13 @@ RangeOpt PointSeriesXY::getVisualizationRangeX() { return _cached_curve.rangeX(); } + +void PointSeriesXY::setTimeFilter(Range filter) +{ + if (_time_filter == filter) + { + return; + } + _time_filter = filter; + updateCache(true); +} diff --git a/plotjuggler_app/point_series_xy.h b/plotjuggler_app/point_series_xy.h index ee63fbc32..2186627c0 100644 --- a/plotjuggler_app/point_series_xy.h +++ b/plotjuggler_app/point_series_xy.h @@ -44,10 +44,13 @@ class PointSeriesXY : public QwtTimeseries return &_cached_curve; } + void setTimeFilter(Range filter); + protected: const PlotData* _x_axis; const PlotData* _y_axis; PlotDataXY _cached_curve; + Range _time_filter; }; #endif // POINT_SERIES_H diff --git a/plotjuggler_base/include/PlotJuggler/plotdatabase.h b/plotjuggler_base/include/PlotJuggler/plotdatabase.h index 82241afb8..3da6f9efb 100644 --- a/plotjuggler_base/include/PlotJuggler/plotdatabase.h +++ b/plotjuggler_base/include/PlotJuggler/plotdatabase.h @@ -25,6 +25,10 @@ struct Range { double min; double max; + bool operator==(const Range& other) const + { + return min == other.min && max == other.max; + } }; #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)