Skip to content

Commit

Permalink
Cabana: add button to display all cached data in chart (commaai#26575)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
deanlee authored and pull[bot] committed Feb 7, 2024
1 parent 6c4d739 commit ba74138
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 16 deletions.
75 changes: 59 additions & 16 deletions tools/cabana/chartswidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <QFutureSynchronizer>
#include <QGraphicsLayout>
#include <QRubberBand>
#include <QTimer>
#include <QToolBar>
#include <QToolButton>
#include <QtConcurrent>
Expand All @@ -19,14 +18,14 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
title_label = new QLabel();
title_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
toolbar->addWidget(title_label);
show_all_values_btn = toolbar->addAction("");
toolbar->addWidget(range_label = new QLabel());
reset_zoom_btn = toolbar->addAction("");
reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)"));
remove_all_btn = toolbar->addAction("");
remove_all_btn->setToolTip(tr("Remove all charts"));
dock_btn = toolbar->addAction("");
main_layout->addWidget(toolbar);
updateToolBar();

// charts
QWidget *charts_container = new QWidget(this);
Expand All @@ -37,14 +36,16 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
charts_scroll->setWidgetResizable(true);
charts_scroll->setWidget(charts_container);
charts_scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

main_layout->addWidget(charts_scroll);

max_chart_range = settings.max_chart_x_range;
use_dark_theme = palette().color(QPalette::WindowText).value() > palette().color(QPalette::Background).value();
updateToolBar();

QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll);
QObject::connect(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged);
QObject::connect(can, &CANMessages::updated, this, &ChartsWidget::updateState);
QObject::connect(show_all_values_btn, &QAction::triggered, this, &ChartsWidget::showAllData);
QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll);
QObject::connect(reset_zoom_btn, &QAction::triggered, this, &ChartsWidget::zoomReset);
QObject::connect(dock_btn, &QAction::triggered, [this]() {
Expand All @@ -58,7 +59,7 @@ void ChartsWidget::eventsMerged() {
if (auto events = can->events(); events && !events->empty()) {
event_range.first = (events->front()->mono_time / (double)1e9) - can->routeStartTime();
event_range.second = (events->back()->mono_time / (double)1e9) - can->routeStartTime();
updateDisplayRange();
updateState();
}
}

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

const auto &range = is_zoomed ? zoomed_range : display_range;
setUpdatesEnabled(false);
for (auto c : charts) {
c->setDisplayRange(range.first, range.second);
c->scene()->invalidate({}, QGraphicsScene::ForegroundLayer);
}
setUpdatesEnabled(true);
}

void ChartsWidget::showAllData() {
bool switch_to_show_all = max_chart_range == settings.max_chart_x_range;
max_chart_range = switch_to_show_all ? settings.cached_segment_limit * 60
: settings.max_chart_x_range;
max_chart_range = std::min(max_chart_range, (uint32_t)can->totalSeconds());
updateToolBar();
updateState();
}

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

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

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

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

void ChartView::signalUpdated(const Signal *sig) {
auto it = std::find_if(sigs.begin(), sigs.end(), [=](auto &s) { return s.sig == sig; });
if (it != sigs.end()) {
if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.sig == sig; })) {
updateTitle();
// TODO: don't update series if only name changed.
updateSeries(sig);
updateAxisY();
}
}

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

void ChartView::msgUpdated(uint32_t address) {
auto it = std::find_if(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; });
if (it != sigs.end())
if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; }))
updateTitle();
}

Expand Down Expand Up @@ -392,7 +408,6 @@ void ChartView::updateSeries(const Signal *sig) {
s.series->replace(s.vals);
}
}
updateAxisY();
}

// auto zoom on yaxis
Expand Down Expand Up @@ -422,11 +437,39 @@ void ChartView::updateAxisY() {
axis_y->setRange(min_y - 1, max_y + 1);
} else {
double range = max_y - min_y;
axis_y->setRange(min_y - range * 0.05, max_y + range * 0.05);
axis_y->applyNiceNumbers();
applyNiceNumbers(min_y - range * 0.05, max_y + range * 0.05);
}

QTimer::singleShot(0, this, &ChartView::adjustChartMargins);
adjustChartMargins();
}

void ChartView::applyNiceNumbers(qreal min, qreal max) {
int tick_count = axis_y->tickCount();
qreal range = niceNumber((max - min), true); // range with ceiling
qreal step = niceNumber(range / (tick_count - 1), false);
min = qFloor(min / step);
max = qCeil(max / step);
tick_count = int(max - min) + 1;
axis_y->setRange(min * step, max * step);
axis_y->setTickCount(tick_count);
}

//nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n
qreal ChartView::niceNumber(qreal x, bool ceiling) {
qreal z = qPow(10, qFloor(std::log10(x))); //find corresponding number of the form of 10^n than is smaller than x
qreal q = x / z; //q<10 && q>=1;
if (ceiling) {
if (q <= 1.0) q = 1;
else if (q <= 2.0) q = 2;
else if (q <= 5.0) q = 5;
else q = 10;
} else {
if (q < 1.5) q = 1;
else if (q < 3.0) q = 2;
else if (q < 7.0) q = 5;
else q = 10;
}
return q * z;
}

void ChartView::leaveEvent(QEvent *event) {
Expand Down
5 changes: 5 additions & 0 deletions tools/cabana/chartswidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ private slots:
void updateTitle();
void updateFromSettings();
void drawForeground(QPainter *painter, const QRectF &rect) override;
void applyNiceNumbers(qreal min, qreal max);
qreal niceNumber(qreal x, bool ceiling);

QValueAxis *axis_x;
QValueAxis *axis_y;
Expand Down Expand Up @@ -102,17 +104,20 @@ class ChartsWidget : public QWidget {
void zoomReset();
void updateToolBar();
void removeAll();
void showAllData();
bool eventFilter(QObject *obj, QEvent *event) override;
ChartView *findChart(const QString &id, const Signal *sig);

QLabel *title_label;
QLabel *range_label;
bool docking = true;
QAction *show_all_values_btn;
QAction *dock_btn;
QAction *reset_zoom_btn;
QAction *remove_all_btn;
QVBoxLayout *charts_layout;
QList<ChartView *> charts;
uint32_t max_chart_range = 0;
bool is_zoomed = false;
std::pair<double, double> event_range;
std::pair<double, double> display_range;
Expand Down

0 comments on commit ba74138

Please sign in to comment.