QChart 对大数据集无响应

Mat*_*ech 2 qt qchart

我的这段代码适用于高达 1000 的数据大小。现在我用 65536 个点对其进行了测试。

\n\n
series = new QLineSeries();\n\nQList<QPointF> points;\npoints.reserve(data.size());\n\nfor(std::vector<int>::size_type i = 0; i != data.size(); i++) {\n    QPointF point(i, data[i]*100/max);\n    points.append(point);\n}\nseries->clear();\nseries->append(points);\n
Run Code Online (Sandbox Code Playgroud)\n\n

并且应用程序在 1 个核心全功率运行时冻结。几分钟后我就停下来了。

\n\n

如何防止 Qt 变得无响应。这个数据大小并不特殊,我希望图表视图能够处理高达百万点的数据集。

\n\n

编辑:\n我测量了时间

\n\n
series->append(points);\n
Run Code Online (Sandbox Code Playgroud)\n\n

2000分需要1秒。这意味着大约一分钟内 > 50.000 是无法使用的。

\n\n

更糟糕的是,对数刻度图

\n\n
serieslog->append(points);\n
Run Code Online (Sandbox Code Playgroud)\n\n

2000分需要40秒。那是完全无法使用的。原因是调试消息,几乎每个点都会打印出来。

\n\n
\n

QtCharts::XLogYDomain::calculateGeometryPoints(const QVector&) const>; 零和负值的对数未定义。

\n
\n\n

我可以用以下方法加快线性图的速度

\n\n
 series->setUseOpenGL(true);\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,对于 65536,它仍然需要 14 秒,这意味着每个点 200 \xc2\xb5s。\n仍然太多。我想要一个最低 10 Hz 的实时视频和一个实时直方图。时间必须 << 1 秒。

\n\n

编辑:\n这是一个使用我的代码的工作示例

\n\n
#include <QDebug>\n#include <QTime>\n#include <cmath>\n#include <stdlib.h>\n\n#include <QtCharts/QChartView>\n#include <QtCharts/QLineSeries>\n#include <QtCharts/QLogValueAxis>\n#include <QtCharts/QValueAxis>\n#include <QtWidgets/QApplication>\n#include <QtWidgets/QMainWindow>\n\nQT_CHARTS_USE_NAMESPACE\n\nint main(int argc, char *argv[])\n{\n    QApplication app(argc, argv);\n\n    QLineSeries * series;\n    QLineSeries * serieslog;\n    QChart * chart;\n    QChartView * chartView;\n    QValueAxis * axisX;\n    QValueAxis * axisY;\n    QLogValueAxis * axisY3;\n\n\n    chart = new QChart();\n    chart->legend()->hide();\n    chart->setTitle("Histogramm");\n\n    axisX = new QValueAxis;\n    chart->addAxis(axisX, Qt::AlignBottom);\n\n    series = new QLineSeries;\n    chart->addSeries(series);\n\n    axisY = new QValueAxis;\n    axisY->setTitleText("linear scale");\n    axisY->setLinePenColor(series->pen().color());\n    axisY->setGridLinePen((series->pen()));\n\n    chart->addAxis(axisY, Qt::AlignLeft);\n    series->attachAxis(axisX);\n    series->attachAxis(axisY);\n\n    serieslog = new QLineSeries;\n    chart->addSeries(serieslog);\n\n    axisY3 = new QLogValueAxis();\n    axisY3->setTitleText("logarithmic scale");\n    axisY3->setLabelFormat("%g");\n    axisY3->setLinePenColor(serieslog->pen().color());\n    axisY3->setGridLinePen((serieslog->pen()));\n    axisY3->setMinorTickCount(-1);\n\n    chart->addAxis(axisY3, Qt::AlignRight);\n    serieslog->attachAxis(axisX);\n    serieslog->attachAxis(axisY3);\n\n    chartView = new QChartView(chart);\n    chartView->setRenderHint(QPainter::Antialiasing);\n\n    // create data\n\n    std::vector<int> data;\n    int N = 10000;\n    data.resize(N);\n    for (int i=0; i < N; ++i){\n        int value = static_cast<int>(fabs((sin(static_cast<double>(i)/1000.0)+1)*1+ std::rand() % 100)+10);\n        data[i] = value;\n    }\n\n    QList<QPointF> points;\n    points.reserve(data.size());\n\n    for(std::vector<int>::size_type i = 0; i != data.size(); i++) { //\n        QPointF point(i, data[i]);\n        points.append(point);\n    }\n    QTime myTimer;\n    myTimer.start();\n\n    series->clear();\n//    series->setUseOpenGL(true);\n    series->append(points);\n    qDebug() << "seconds lin: " << myTimer.elapsed();\n    myTimer.start();\n    serieslog->clear();\n    serieslog->append(points);\n    qDebug() << "seconds log: " << myTimer.elapsed();\n\n    chart->axisX()->setRange(0, data.size());\n    chart->axisY()->setRange(-10, 250);\n\n    QMainWindow window;\n    window.setCentralWidget(chartView);\n    window.resize(800, 600);\n    window.show();\n\n    return app.exec();\n}\n\n\nQT += core\nQT += widgets\nQT += gui\nQT += charts\n\nSOURCES += \\\n    main.cpp\n
Run Code Online (Sandbox Code Playgroud)\n\n

我测量\nm秒林:1624\nm秒日志:6801

\n

G.M*_*.M. 6

QXYSeries::append我可以重现该问题(具有相似的经过时间),这似乎是处理方式的问题QList。从代码...

void QXYSeries::append(const QList<QPointF> &points)
{
    foreach (const QPointF &point , points)
        append(point);
}
Run Code Online (Sandbox Code Playgroud)

和...

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

    if (isValidValue(point)) {
        d->m_points << point;
        emit pointAdded(d->m_points.count() - 1);
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,每个点的添加都可能导致QVector d->m_points调整大小并pointAdded发出信号。

鉴于您在调用之前清除了与该系列相关的所有数据,QXYSeries::append您可以QXYSeries::replace改为使用。

如果您必须生成初始数据,那么QList只需使用...

series->replace(points);
Run Code Online (Sandbox Code Playgroud)

但是,在内部使用QList::toVectorso 如果您可以生成数据,那么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";
Run Code Online (Sandbox Code Playgroud)

上面的代码在我自己的系统上会导致......

lin:  1 ms
log:  3 ms
Run Code Online (Sandbox Code Playgroud)

为了10k点,为了100k点......

lin:  6 ms
log:  22 ms
Run Code Online (Sandbox Code Playgroud)