Skip to content

Commit ba74138

Browse files
deanleepull[bot]
authored andcommitted
Cabana: add button to display all cached data in chart (commaai#26575)
* display all data btn * remove timer * update toolbar later * dont update axis y in updateSeries faster get_raw_value * faster update * optimize zoom y axis * cleanup * revert changes to get_raw_value * updateState in eventsMerge * cleanup: * cleanup
1 parent 6c4d739 commit ba74138

File tree

2 files changed

+64
-16
lines changed

2 files changed

+64
-16
lines changed

tools/cabana/chartswidget.cc

+59-16
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include <QFutureSynchronizer>
44
#include <QGraphicsLayout>
55
#include <QRubberBand>
6-
#include <QTimer>
76
#include <QToolBar>
87
#include <QToolButton>
98
#include <QtConcurrent>
@@ -19,14 +18,14 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
1918
title_label = new QLabel();
2019
title_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
2120
toolbar->addWidget(title_label);
21+
show_all_values_btn = toolbar->addAction("");
2222
toolbar->addWidget(range_label = new QLabel());
2323
reset_zoom_btn = toolbar->addAction("");
2424
reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)"));
2525
remove_all_btn = toolbar->addAction("");
2626
remove_all_btn->setToolTip(tr("Remove all charts"));
2727
dock_btn = toolbar->addAction("");
2828
main_layout->addWidget(toolbar);
29-
updateToolBar();
3029

3130
// charts
3231
QWidget *charts_container = new QWidget(this);
@@ -37,14 +36,16 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
3736
charts_scroll->setWidgetResizable(true);
3837
charts_scroll->setWidget(charts_container);
3938
charts_scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
40-
4139
main_layout->addWidget(charts_scroll);
4240

41+
max_chart_range = settings.max_chart_x_range;
4342
use_dark_theme = palette().color(QPalette::WindowText).value() > palette().color(QPalette::Background).value();
43+
updateToolBar();
4444

4545
QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll);
4646
QObject::connect(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged);
4747
QObject::connect(can, &CANMessages::updated, this, &ChartsWidget::updateState);
48+
QObject::connect(show_all_values_btn, &QAction::triggered, this, &ChartsWidget::showAllData);
4849
QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll);
4950
QObject::connect(reset_zoom_btn, &QAction::triggered, this, &ChartsWidget::zoomReset);
5051
QObject::connect(dock_btn, &QAction::triggered, [this]() {
@@ -58,7 +59,7 @@ void ChartsWidget::eventsMerged() {
5859
if (auto events = can->events(); events && !events->empty()) {
5960
event_range.first = (events->front()->mono_time / (double)1e9) - can->routeStartTime();
6061
event_range.second = (events->back()->mono_time / (double)1e9) - can->routeStartTime();
61-
updateDisplayRange();
62+
updateState();
6263
}
6364
}
6465

@@ -69,8 +70,8 @@ void ChartsWidget::updateDisplayRange() {
6970
// reached the end, or seeked to a timestamp out of range.
7071
display_range.first = current_sec - 5;
7172
}
72-
display_range.first = std::max(display_range.first, event_range.first);
73-
display_range.second = std::min(display_range.first + settings.max_chart_x_range, event_range.second);
73+
display_range.first = std::floor(std::max(display_range.first, event_range.first) * 10.0) / 10.0;
74+
display_range.second = std::floor(std::min(display_range.first + max_chart_range, event_range.second) * 10.0) / 10.0;
7475
if (prev_range != display_range) {
7576
QFutureSynchronizer<void> future_synchronizer;
7677
for (auto c : charts)
@@ -100,13 +101,29 @@ void ChartsWidget::updateState() {
100101
}
101102

102103
const auto &range = is_zoomed ? zoomed_range : display_range;
104+
setUpdatesEnabled(false);
103105
for (auto c : charts) {
104106
c->setDisplayRange(range.first, range.second);
105107
c->scene()->invalidate({}, QGraphicsScene::ForegroundLayer);
106108
}
109+
setUpdatesEnabled(true);
110+
}
111+
112+
void ChartsWidget::showAllData() {
113+
bool switch_to_show_all = max_chart_range == settings.max_chart_x_range;
114+
max_chart_range = switch_to_show_all ? settings.cached_segment_limit * 60
115+
: settings.max_chart_x_range;
116+
max_chart_range = std::min(max_chart_range, (uint32_t)can->totalSeconds());
117+
updateToolBar();
118+
updateState();
107119
}
108120

109121
void ChartsWidget::updateToolBar() {
122+
int min_range = std::min(settings.max_chart_x_range, (int)can->totalSeconds());
123+
bool displaying_all = max_chart_range != min_range;
124+
show_all_values_btn->setText(tr("%1 minutes").arg(max_chart_range / 60));
125+
show_all_values_btn->setToolTip(tr("Click to display %1 data").arg(displaying_all ? tr("%1 minutes").arg(min_range / 60) : tr("ALL cached")));
126+
show_all_values_btn->setVisible(!is_zoomed);
110127
remove_all_btn->setEnabled(!charts.isEmpty());
111128
reset_zoom_btn->setEnabled(is_zoomed);
112129
range_label->setText(is_zoomed ? tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : "");
@@ -232,6 +249,7 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) {
232249
sigs.push_back({.msg_id = msg_id, .address = address, .source = source, .sig = sig, .series = series});
233250
updateTitle();
234251
updateSeries(sig);
252+
updateAxisY();
235253
}
236254

237255
void ChartView::removeSeries(const QString &msg_id, const Signal *sig) {
@@ -242,8 +260,7 @@ void ChartView::removeSeries(const QString &msg_id, const Signal *sig) {
242260
}
243261

244262
bool ChartView::hasSeries(const QString &msg_id, const Signal *sig) const {
245-
auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; });
246-
return it != sigs.end();
263+
return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; });
247264
}
248265

249266
QList<ChartView::SigItem>::iterator ChartView::removeSeries(const QList<ChartView::SigItem>::iterator &it) {
@@ -261,11 +278,11 @@ QList<ChartView::SigItem>::iterator ChartView::removeSeries(const QList<ChartVie
261278
}
262279

263280
void ChartView::signalUpdated(const Signal *sig) {
264-
auto it = std::find_if(sigs.begin(), sigs.end(), [=](auto &s) { return s.sig == sig; });
265-
if (it != sigs.end()) {
281+
if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.sig == sig; })) {
266282
updateTitle();
267283
// TODO: don't update series if only name changed.
268284
updateSeries(sig);
285+
updateAxisY();
269286
}
270287
}
271288

@@ -276,8 +293,7 @@ void ChartView::signalRemoved(const Signal *sig) {
276293
}
277294

278295
void ChartView::msgUpdated(uint32_t address) {
279-
auto it = std::find_if(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; });
280-
if (it != sigs.end())
296+
if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; }))
281297
updateTitle();
282298
}
283299

@@ -392,7 +408,6 @@ void ChartView::updateSeries(const Signal *sig) {
392408
s.series->replace(s.vals);
393409
}
394410
}
395-
updateAxisY();
396411
}
397412

398413
// auto zoom on yaxis
@@ -422,11 +437,39 @@ void ChartView::updateAxisY() {
422437
axis_y->setRange(min_y - 1, max_y + 1);
423438
} else {
424439
double range = max_y - min_y;
425-
axis_y->setRange(min_y - range * 0.05, max_y + range * 0.05);
426-
axis_y->applyNiceNumbers();
440+
applyNiceNumbers(min_y - range * 0.05, max_y + range * 0.05);
427441
}
428442

429-
QTimer::singleShot(0, this, &ChartView::adjustChartMargins);
443+
adjustChartMargins();
444+
}
445+
446+
void ChartView::applyNiceNumbers(qreal min, qreal max) {
447+
int tick_count = axis_y->tickCount();
448+
qreal range = niceNumber((max - min), true); // range with ceiling
449+
qreal step = niceNumber(range / (tick_count - 1), false);
450+
min = qFloor(min / step);
451+
max = qCeil(max / step);
452+
tick_count = int(max - min) + 1;
453+
axis_y->setRange(min * step, max * step);
454+
axis_y->setTickCount(tick_count);
455+
}
456+
457+
//nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n
458+
qreal ChartView::niceNumber(qreal x, bool ceiling) {
459+
qreal z = qPow(10, qFloor(std::log10(x))); //find corresponding number of the form of 10^n than is smaller than x
460+
qreal q = x / z; //q<10 && q>=1;
461+
if (ceiling) {
462+
if (q <= 1.0) q = 1;
463+
else if (q <= 2.0) q = 2;
464+
else if (q <= 5.0) q = 5;
465+
else q = 10;
466+
} else {
467+
if (q < 1.5) q = 1;
468+
else if (q < 3.0) q = 2;
469+
else if (q < 7.0) q = 5;
470+
else q = 10;
471+
}
472+
return q * z;
430473
}
431474

432475
void ChartView::leaveEvent(QEvent *event) {

tools/cabana/chartswidget.h

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ private slots:
6666
void updateTitle();
6767
void updateFromSettings();
6868
void drawForeground(QPainter *painter, const QRectF &rect) override;
69+
void applyNiceNumbers(qreal min, qreal max);
70+
qreal niceNumber(qreal x, bool ceiling);
6971

7072
QValueAxis *axis_x;
7173
QValueAxis *axis_y;
@@ -102,17 +104,20 @@ class ChartsWidget : public QWidget {
102104
void zoomReset();
103105
void updateToolBar();
104106
void removeAll();
107+
void showAllData();
105108
bool eventFilter(QObject *obj, QEvent *event) override;
106109
ChartView *findChart(const QString &id, const Signal *sig);
107110

108111
QLabel *title_label;
109112
QLabel *range_label;
110113
bool docking = true;
114+
QAction *show_all_values_btn;
111115
QAction *dock_btn;
112116
QAction *reset_zoom_btn;
113117
QAction *remove_all_btn;
114118
QVBoxLayout *charts_layout;
115119
QList<ChartView *> charts;
120+
uint32_t max_chart_range = 0;
116121
bool is_zoomed = false;
117122
std::pair<double, double> event_range;
118123
std::pair<double, double> display_range;

0 commit comments

Comments
 (0)