I have this code which works well for data sizes up to 1000. Now I tested it with 65536 points.
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);
And the application freezes with 1 core at full power. I stopped it after minutes.
How can I prevent Qt from becoming unresponsive. This data size is not special, I would expect a chart view to handle data sets up to million points.
EDIT: I measured the time
series->append(points);
takes 1 second for 2000 points. That means for about a minute for > 50.000 That is unusable.
Even worse, the log scale plot
serieslog->append(points);
takes 40 seconds for 2000 points. That is completely unusable. The reasons is the debug message, which is printed out for almost every point.
QtCharts::XLogYDomain::calculateGeometryPoints(const QVector&) const>; Logarithms of zero and negative values are undefined.
I can speed up the linear plot with
series->setUseOpenGL(true);
However with 65536 it still takes 14 seconds, that means 200 µs per point. Still to much. I want a live video with 10 Hz minimum, and a live histogramm. the time must << 1 second.
EDIT: Here a working example, using my code
#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
I measure mseconds lin: 1624 mseconds log: 6801
I can repro the problem (with similar elapsed times) and it appears to be an issue with the way
QXYSeries::append
handlesQList
. From the code...and...
So each point addition will potentially result in the
QVector
d->m_points
being resized and thepointAdded
signal being emitted.Given that you clear all data associated with the series before calling
QXYSeries::append
you could useQXYSeries::replace
instead.If you must generate your initial data as a
QList
then just use...However, internally that uses
QList::toVector
so if you can generate the data as aQVector
then so much the better...The above code on my own system results in...
for 10k points, and for 100k points...