WedX - журнал о программировании и компьютерных науках

QChart не отвечает с большим набором данных

У меня есть этот код, который хорошо работает для размеров данных до 1000. Теперь я протестировал его с 65536 точками.

series = new QLineSeries();

QList<QPointF> points;
points.reserve(data.size());

for(std::vector<int>::size_type i = 0; i != data.size(); i++) {
    QPointF point(i, data[i]*100/max);
    points.append(point);
}
series->clear();
series->append(points);

И приложение зависает с 1 ядром на полной мощности. Я остановил его через несколько минут.

Как я могу предотвратить зависание Qt. Этот размер данных не является особенным, я ожидаю, что представление диаграммы будет обрабатывать наборы данных до миллиона точек.

РЕДАКТИРОВАТЬ: я измерил время

series->append(points);

занимает 1 секунду для 2000 очков. Это означает, что около минуты для > 50 000 Это непригодно для использования.

Хуже того, график в логарифмическом масштабе

serieslog->append(points);

занимает 40 секунд для 2000 очков. Это совершенно непригодно. Причина в отладочном сообщении, которое выводится практически для каждой точки.

QtCharts::XLogYDomain::calculateGeometryPoints(const QVector&) const>; Логарифмы нуля и отрицательных значений не определены.

Я могу ускорить линейный сюжет с помощью

 series->setUseOpenGL(true);

Однако с 65536 это по-прежнему занимает 14 секунд, что означает 200 мкс на точку. Все еще слишком много. Я хочу живое видео с минимальной частотой 10 Гц и живую гистограмму. время должно ‹‹ 1 секунда.

РЕДАКТИРОВАТЬ: вот рабочий пример, используя мой код

#include <QDebug>
#include <QTime>
#include <cmath>
#include <stdlib.h>

#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QLogValueAxis>
#include <QtCharts/QValueAxis>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>

QT_CHARTS_USE_NAMESPACE

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QLineSeries * series;
    QLineSeries * serieslog;
    QChart * chart;
    QChartView * chartView;
    QValueAxis * axisX;
    QValueAxis * axisY;
    QLogValueAxis * axisY3;


    chart = new QChart();
    chart->legend()->hide();
    chart->setTitle("Histogramm");

    axisX = new QValueAxis;
    chart->addAxis(axisX, Qt::AlignBottom);

    series = new QLineSeries;
    chart->addSeries(series);

    axisY = new QValueAxis;
    axisY->setTitleText("linear scale");
    axisY->setLinePenColor(series->pen().color());
    axisY->setGridLinePen((series->pen()));

    chart->addAxis(axisY, Qt::AlignLeft);
    series->attachAxis(axisX);
    series->attachAxis(axisY);

    serieslog = new QLineSeries;
    chart->addSeries(serieslog);

    axisY3 = new QLogValueAxis();
    axisY3->setTitleText("logarithmic scale");
    axisY3->setLabelFormat("%g");
    axisY3->setLinePenColor(serieslog->pen().color());
    axisY3->setGridLinePen((serieslog->pen()));
    axisY3->setMinorTickCount(-1);

    chart->addAxis(axisY3, Qt::AlignRight);
    serieslog->attachAxis(axisX);
    serieslog->attachAxis(axisY3);

    chartView = new QChartView(chart);
    chartView->setRenderHint(QPainter::Antialiasing);

    // create data

    std::vector<int> data;
    int N = 10000;
    data.resize(N);
    for (int i=0; i < N; ++i){
        int value = static_cast<int>(fabs((sin(static_cast<double>(i)/1000.0)+1)*1+ std::rand() % 100)+10);
        data[i] = value;
    }

    QList<QPointF> points;
    points.reserve(data.size());

    for(std::vector<int>::size_type i = 0; i != data.size(); i++) { //
        QPointF point(i, data[i]);
        points.append(point);
    }
    QTime myTimer;
    myTimer.start();

    series->clear();
//    series->setUseOpenGL(true);
    series->append(points);
    qDebug() << "seconds lin: " << myTimer.elapsed();
    myTimer.start();
    serieslog->clear();
    serieslog->append(points);
    qDebug() << "seconds log: " << myTimer.elapsed();

    chart->axisX()->setRange(0, data.size());
    chart->axisY()->setRange(-10, 250);

    QMainWindow window;
    window.setCentralWidget(chartView);
    window.resize(800, 600);
    window.show();

    return app.exec();
}


QT += core
QT += widgets
QT += gui
QT += charts

SOURCES += \
    main.cpp

Я измеряю mseconds lin: 1624 mseconds log: 6801

13.09.2018

  • Что здесь data? 14.09.2018
  • Вектор инт. std::vector<int> histVector 14.09.2018
  • serieslog->append(points); может вызвать множество вещей и даже пройти через ваш код (вызвать сигнал). Я рекомендую использовать профайлер в первую очередь. 14.09.2018
  • Что вы имеете в виду под профайлером? 14.09.2018
  • Извините, но я думал, вы установили, что основной причиной проблемы является огромное количество регистрируемых предупреждающих сообщений — или это просто отвлекающий маневр? Вы должны отредактировать свой вопрос, чтобы предоставить минимально воспроизводимый пример, если это возможно. 14.09.2018
  • Хорошо, я могу привести минимальный пример. 14.09.2018
  • Ваше обновление по-прежнему не является MCVE, в частности, отсутствуют все настройки QtCharts. 14.09.2018
  • Я добавил пример кода 14.09.2018

Ответы:


1

Я могу воспроизвести проблему (с одинаковым прошедшим временем), и, похоже, проблема связана с тем, как QXYSeries::append обрабатывает QList. Из кода...

void QXYSeries::append(const QList<QPointF> &points)
{
    foreach (const QPointF &point , points)
        append(point);
}

а также...

void QXYSeries::append(const QPointF &point)
{
    Q_D(QXYSeries);

    if (isValidValue(point)) {
        d->m_points << point;
        emit pointAdded(d->m_points.count() - 1);
    }
}

Таким образом, каждое добавление точки потенциально может привести к изменению размера QVector d->m_points и излучению сигнала pointAdded.

Учитывая, что вы очищаете все данные, связанные с серией, перед вызовом QXYSeries::append, вместо этого вы можете использовать QXYSeries::replace.

Если вы должны сгенерировать исходные данные как QList, просто используйте...

series->replace(points);

Однако внутри используется QList::toVector, поэтому, если вы можете сгенерировать данные как QVector, тогда тем лучше...

QVector<QPointF> points(data.size());

for(std::vector<int>::size_type i = 0; i != data.size(); ++i) {
  points[i] = QPointF(i, data[i]);
}

QTime myTimer;
myTimer.start();

series->replace(points);
qDebug() << "\nlin: " << myTimer.elapsed() << "ms\n";

myTimer.start();
serieslog->replace(points);
qDebug() << "\nlog: " << myTimer.elapsed() << "ms\n";

Приведенный выше код в моей собственной системе приводит к...

lin:  1 ms
log:  3 ms

за 10к баллов и за 100к баллов...

lin:  6 ms
log:  22 ms
14.09.2018
Новые материалы

Как проанализировать работу вашего классификатора?
Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

ИИ в аэрокосмической отрасли
Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


Для любых предложений по сайту: [email protected]