Skip to content

Commit 5339607

Browse files
deanleepd0wm
andauthored
cabana: add capability for switching between line and scatter plots (#27169)
* add capability for switching between line and scatter plots * Update tools/cabana/chartswidget.cc Co-authored-by: Willem Melching <willem.melching@gmail.com> * setUserOpengl in createSeries * update series title * set marker size by pixels_per_point * sync menu state * cleanup * set default series type in settings dlg * remove qdebug --------- Co-authored-by: Willem Melching <willem.melching@gmail.com>
1 parent e3c202b commit 5339607

File tree

4 files changed

+86
-16
lines changed

4 files changed

+86
-16
lines changed

tools/cabana/chartswidget.cc

+69-15
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <QFutureSynchronizer>
88
#include <QGraphicsLayout>
99
#include <QLineEdit>
10+
#include <QMenu>
1011
#include <QRubberBand>
1112
#include <QToolBar>
1213
#include <QToolButton>
@@ -178,6 +179,7 @@ void ChartsWidget::settingChanged() {
178179
range_slider->setRange(1, settings.max_cached_minutes * 60);
179180
for (auto c : charts) {
180181
c->setFixedHeight(settings.chart_height);
182+
c->setSeriesType(settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter);
181183
}
182184
}
183185

@@ -297,6 +299,8 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) {
297299
// ChartView
298300

299301
ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
302+
series_type = settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter;
303+
300304
QChart *chart = new QChart();
301305
chart->setBackgroundRoundness(0);
302306
axis_x = new QValueAxis(this);
@@ -317,9 +321,20 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
317321
close_btn_proxy->setZValue(chart->zValue() + 11);
318322

319323
QToolButton *manage_btn = new QToolButton();
324+
manage_btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
320325
manage_btn->setIcon(utils::icon("gear"));
321326
manage_btn->setAutoRaise(true);
322-
manage_btn->setToolTip(tr("Manage series"));
327+
QMenu *menu = new QMenu(this);
328+
line_series_action = menu->addAction(tr("Line"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeLine); });
329+
line_series_action->setCheckable(true);
330+
line_series_action->setChecked(series_type == QAbstractSeries::SeriesTypeLine);
331+
scatter_series_action = menu->addAction(tr("Scatter"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeScatter); });
332+
scatter_series_action->setCheckable(true);
333+
scatter_series_action->setChecked(series_type == QAbstractSeries::SeriesTypeScatter);
334+
menu->addSeparator();
335+
menu->addAction(tr("Manage series"), this, &ChartView::manageSeries);
336+
manage_btn->setMenu(menu);
337+
manage_btn->setPopupMode(QToolButton::InstantPopup);
323338
manage_btn_proxy = new QGraphicsProxyWidget(chart);
324339
manage_btn_proxy->setWidget(manage_btn);
325340
manage_btn_proxy->setZValue(chart->zValue() + 11);
@@ -334,7 +349,6 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
334349
QObject::connect(dbc(), &DBCManager::msgRemoved, this, &ChartView::msgRemoved);
335350
QObject::connect(dbc(), &DBCManager::msgUpdated, this, &ChartView::msgUpdated);
336351
QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove);
337-
QObject::connect(manage_btn, &QToolButton::clicked, this, &ChartView::manageSeries);
338352
}
339353

340354
qreal ChartView::getYAsixLabelWidth() const {
@@ -354,8 +368,7 @@ void ChartView::setPlotAreaLeftPosition(int pos) {
354368
}
355369

356370
void ChartView::addSeries(const QString &msg_id, const Signal *sig) {
357-
QLineSeries *series = new QLineSeries(this);
358-
371+
QXYSeries *series = createSeries(series_type);
359372
chart()->addSeries(series);
360373
series->attachAxis(axis_x);
361374
series->attachAxis(axis_y);
@@ -478,22 +491,26 @@ void ChartView::updatePlot(double cur, double min, double max) {
478491
int num_points = std::max<int>(end - begin, 1);
479492
int pixels_per_point = width() / num_points;
480493

481-
s.series->setPointsVisible(pixels_per_point > 20);
494+
if (series_type == QAbstractSeries::SeriesTypeScatter) {
495+
((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 1, 8));
496+
} else {
497+
s.series->setPointsVisible(pixels_per_point > 20);
482498

483-
// TODO: On MacOS QChartWidget doesn't work with the OpenGL settings that CameraWidget needs.
499+
// TODO: On MacOS QChartWidget doesn't work with the OpenGL settings that CameraWidget needs.
484500
#ifndef __APPLE
485-
// OpenGL mode lacks certain features (such as showing points), only use when drawing many points
486-
bool use_opengl = pixels_per_point < 1;
487-
s.series->setUseOpenGL(use_opengl);
501+
// OpenGL mode lacks certain features (such as showing points), only use when drawing many points
502+
bool use_opengl = pixels_per_point < 1;
503+
s.series->setUseOpenGL(use_opengl);
488504

489-
// Qt doesn't properly apply device pixel ratio in OpenGL mode
490-
QApplication* application = static_cast<QApplication *>(QApplication::instance());
491-
float scale = use_opengl ? application->devicePixelRatio() : 1.0;
505+
// Qt doesn't properly apply device pixel ratio in OpenGL mode
506+
QApplication *application = static_cast<QApplication *>(QApplication::instance());
507+
float scale = use_opengl ? application->devicePixelRatio() : 1.0;
492508

493-
QPen pen = s.series->pen();
494-
pen.setWidth(2.0 * scale);
495-
s.series->setPen(pen);
509+
QPen pen = s.series->pen();
510+
pen.setWidth(2.0 * scale);
511+
s.series->setPen(pen);
496512
#endif
513+
}
497514
}
498515
}
499516

@@ -733,6 +750,43 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) {
733750
}
734751
}
735752

753+
QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type) {
754+
QXYSeries *series = nullptr;
755+
if (type == QAbstractSeries::SeriesTypeLine) {
756+
series = new QLineSeries(this);
757+
} else {
758+
series = new QScatterSeries(this);
759+
}
760+
// TODO: Due to a bug in CameraWidget the camera frames
761+
// are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed
762+
#ifndef __APPLE__
763+
series->setUseOpenGL(true);
764+
#endif
765+
return series;
766+
}
767+
768+
void ChartView::setSeriesType(QAbstractSeries::SeriesType type) {
769+
if (type != series_type) {
770+
series_type = type;
771+
line_series_action->setChecked(type == QAbstractSeries::SeriesTypeLine);
772+
scatter_series_action->setChecked(type == QAbstractSeries::SeriesTypeScatter);
773+
774+
for (auto &s : sigs) {
775+
chart()->removeSeries(s.series);
776+
s.series->deleteLater();
777+
}
778+
for (auto &s : sigs) {
779+
auto series = createSeries(series_type);
780+
chart()->addSeries(series);
781+
series->attachAxis(axis_x);
782+
series->attachAxis(axis_y);
783+
series->replace(s.vals);
784+
s.series = series;
785+
}
786+
updateTitle();
787+
}
788+
}
789+
736790
// SeriesSelector
737791

738792
SeriesSelector::SeriesSelector(QWidget *parent) {

tools/cabana/chartswidget.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <QTimer>
1111
#include <QtCharts/QChartView>
1212
#include <QtCharts/QLineSeries>
13+
#include <QtCharts/QScatterSeries>
1314
#include <QtCharts/QValueAxis>
1415

1516
#include "tools/cabana/dbcmanager.h"
@@ -30,13 +31,14 @@ class ChartView : public QChartView {
3031
void updatePlot(double cur, double min, double max);
3132
void setPlotAreaLeftPosition(int pos);
3233
qreal getYAsixLabelWidth() const;
34+
void setSeriesType(QAbstractSeries::SeriesType type);
3335

3436
struct SigItem {
3537
QString msg_id;
3638
uint8_t source = 0;
3739
uint32_t address = 0;
3840
const Signal *sig = nullptr;
39-
QLineSeries *series = nullptr;
41+
QXYSeries *series = nullptr;
4042
QVector<QPointF> vals;
4143
uint64_t last_value_mono_time = 0;
4244
};
@@ -70,6 +72,7 @@ private slots:
7072
void drawForeground(QPainter *painter, const QRectF &rect) override;
7173
void applyNiceNumbers(qreal min, qreal max);
7274
qreal niceNumber(qreal x, bool ceiling);
75+
QXYSeries *createSeries(QAbstractSeries::SeriesType type);
7376

7477
QValueAxis *axis_x;
7578
QValueAxis *axis_y;
@@ -79,6 +82,9 @@ private slots:
7982
QList<SigItem> sigs;
8083
double cur_sec = 0;
8184
const QString mime_type = "application/x-cabanachartview";
85+
QAbstractSeries::SeriesType series_type = QAbstractSeries::SeriesTypeLine;
86+
QAction *line_series_action;
87+
QAction *scatter_series_action;
8288
};
8389

8490
class ChartsWidget : public QWidget {

tools/cabana/settings.cc

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ void Settings::save() {
2525
s.setValue("video_splitter_state", video_splitter_state);
2626
s.setValue("recent_files", recent_files);
2727
s.setValue("message_header_state", message_header_state);
28+
s.setValue("chart_series_type", chart_series_type);
2829
}
2930

3031
void Settings::load() {
@@ -40,6 +41,7 @@ void Settings::load() {
4041
video_splitter_state = s.value("video_splitter_state").toByteArray();
4142
recent_files = s.value("recent_files").toStringList();
4243
message_header_state = s.value("message_header_state").toByteArray();
44+
chart_series_type = s.value("chart_series_type", 0).toInt();
4345
}
4446

4547
// SettingsDlg
@@ -60,6 +62,11 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) {
6062
cached_minutes->setValue(settings.max_cached_minutes);
6163
form_layout->addRow(tr("Max Cached Minutes"), cached_minutes);
6264

65+
chart_series_type = new QComboBox(this);
66+
chart_series_type->addItems({tr("Line"), tr("Scatter")});
67+
chart_series_type->setCurrentIndex(settings.chart_series_type);
68+
form_layout->addRow(tr("Chart Default Series Type"), chart_series_type);
69+
6370
chart_height = new QSpinBox(this);
6471
chart_height->setRange(100, 500);
6572
chart_height->setSingleStep(10);
@@ -77,6 +84,7 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) {
7784
void SettingsDlg::save() {
7885
settings.fps = fps->value();
7986
settings.max_cached_minutes = cached_minutes->value();
87+
settings.chart_series_type = chart_series_type->currentIndex();
8088
settings.chart_height = chart_height->value();
8189
settings.save();
8290
accept();

tools/cabana/settings.h

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class Settings : public QObject {
1818
int chart_height = 200;
1919
int chart_column_count = 1;
2020
int chart_range = 3 * 60; // e minutes
21+
int chart_series_type = 0;
2122
QString last_dir;
2223
QByteArray geometry;
2324
QByteArray video_splitter_state;
@@ -38,6 +39,7 @@ class SettingsDlg : public QDialog {
3839
QSpinBox *fps;
3940
QSpinBox *cached_minutes;
4041
QSpinBox *chart_height;
42+
QComboBox *chart_series_type;
4143
};
4244

4345
extern Settings settings;

0 commit comments

Comments
 (0)