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
Я измеряю мсек лин: 1624 мсек лог: 6801
2 ответа
Я могу воспроизвести проблему (с аналогичным прошедшим временем), и, похоже, проблема связана с тем, как 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
Я тоже заметил эту медлительность, в моем случае я очистил и заменил данные в серии. Я использую QML.
Я получил значительное улучшение производительности, когда я сделал серию невидимой перед очисткой и добавлением новых данных и снова сделал ее видимой после того, как я установил минимальное и максимальное значения и т. Д.