Multiple real time plots/charts
-
wrote on 1 Mar 2017, 12:59 last edited by
Hey guys,
Since QT uses a single thread for the GUI I'm experiencing, as expected, low performance when displaying 8 and more charts fed with real time data.
I've tried the QCharts, qcustomplot, qwtPlot. All with and without openGL enabled.
So far the best performance comes with qcustomplot.What would you suggest me to do, to display 10-20 real time charts without performance drop?
Fork a single chart app and use ipc for data exchange?Best regards
framet -
Hey guys,
Since QT uses a single thread for the GUI I'm experiencing, as expected, low performance when displaying 8 and more charts fed with real time data.
I've tried the QCharts, qcustomplot, qwtPlot. All with and without openGL enabled.
So far the best performance comes with qcustomplot.What would you suggest me to do, to display 10-20 real time charts without performance drop?
Fork a single chart app and use ipc for data exchange?Best regards
framet@framet How often do you update all these charts?
-
wrote on 1 Mar 2017, 13:24 last edited by
using QChart, how do you update real time data?
if you receive the "8 and more" data point at the same time (or at least synchronously) you can subclass QAbstractTableModel and update all the values in a signle operation and cause a single repaint of the chart itself (using a model mapper as bridge between the model and the chart)
-
using QChart, how do you update real time data?
if you receive the "8 and more" data point at the same time (or at least synchronously) you can subclass QAbstractTableModel and update all the values in a signle operation and cause a single repaint of the chart itself (using a model mapper as bridge between the model and the chart)
wrote on 1 Mar 2017, 13:29 last edited by@VRonin I have "8 and more" charts simultaneously open and not one chart with 8 and more data points. Each chart does not have more than 3 data point series. As I understand the QAbstractTableModel is only for one single chart correct? So this probably wont safe me the majority of the performance but is still a good point for QCharts.
-
@VRonin I have "8 and more" charts simultaneously open and not one chart with 8 and more data points. Each chart does not have more than 3 data point series. As I understand the QAbstractTableModel is only for one single chart correct? So this probably wont safe me the majority of the performance but is still a good point for QCharts.
wrote on 1 Mar 2017, 14:22 last edited by@framet said in Multiple real time plots/charts:
QAbstractTableModel is only for one single chart correct?
Nope. actually it QAbstractTableModel is perfect for when you have more than 1 chart.
How did you try to update the charts before?
-
@framet said in Multiple real time plots/charts:
QAbstractTableModel is only for one single chart correct?
Nope. actually it QAbstractTableModel is perfect for when you have more than 1 chart.
How did you try to update the charts before?
-
@framet said in Multiple real time plots/charts:
QAbstractTableModel is only for one single chart correct?
Nope. actually it QAbstractTableModel is perfect for when you have more than 1 chart.
How did you try to update the charts before?
wrote on 6 Mar 2017, 10:00 last edited by framet 3 Jun 2017, 10:31@VRonin said in Multiple real time plots/charts:
Nope. actually it QAbstractTableModel is perfect for when you have more than 1 chart.
hey @VRonin im currently working on a test with QAbstractTableModel.
I have a model with 100 rows and 4 columns. If new values would overflow the memory a just start at row zero again.
The problem what I have and I can't find any solution for it is that when I update a specific row and emit dataChanged(topLeft,bottomRight) with the updated values QChart updates/repaints the hole model which leads to flickering when you go above 10 HZ.Is there a way to reimplement this QChart behavior or is there a flag to set?
Cheers
frametEdit: here is an example with 2 HZ https://imgur.com/a/DYR7L
Edit 2: just found out with linesSeries.setUseOpenGL() decreases the flickering
-
wrote on 6 Mar 2017, 10:34 last edited by
Wow, it's unbelievably slow... I'll prepare a minimal example and see if I get the same
-
wrote on 6 Mar 2017, 11:15 last edited by framet 3 Jun 2017, 11:22
Below are two tests with TableModel (100,4)
Both tests run with 20 HZ
With OpenGL on LineSeries enabledTest 1) Single chart https://imgur.com/a/Sfe20
Test 2) 6 charts http://imgur.com/a/FpicuWith OpenGL on LineSeries disabled
Test 3) 6 charts http://imgur.com/a/mnFagAs you can see the problem of QT getting slower with more charts relaying on the same Model still exists.
Edit: just to clarify YES the test before was with 2 HZ and those tests here are with 20 HZ :)
-
wrote on 6 Mar 2017, 13:58 last edited by VRonin 3 Jun 2017, 14:05
Tryed:
#include <QWidget> #include <QTimer> #include <QStandardItemModel> #include <QtCharts/QChart> #include <QtCharts/QChartView> #include <QGridLayout> #include <QtCharts/QVXYModelMapper> #include <QtCharts/QLineSeries> #include <cmath> QT_CHARTS_USE_NAMESPACE class TestChart : public QWidget { Q_OBJECT Q_DISABLE_COPY(TestChart) public: explicit TestChart(QWidget *parent = Q_NULLPTR) :QWidget(parent) , maixLength(360) , frequency(20.0) , shift(0.0) , currentCounter(0.0) , pi(std::acos(-1)) { m_model = new QStandardItemModel(this); m_model->insertColumns(0, 3); //m_model->insertRows(0, maixLength); m_updateTimer = new QTimer(this); m_updateTimer->setInterval(1000.0 / frequency); connect(m_updateTimer, &QTimer::timeout, this, &TestChart::addSeriesData); QGridLayout* mainLay = new QGridLayout(this); for (int i = 0; i < 15; ++i) { QLineSeries *sineSeries = new QLineSeries; sineSeries->setName("Sine Wave"); QVXYModelMapper *mapper = new QVXYModelMapper(this); mapper->setXColumn(0); mapper->setYColumn(1); mapper->setSeries(sineSeries); mapper->setModel(m_model); sineSeries->setColor(Qt::red); QLineSeries *cosineSeries = new QLineSeries; cosineSeries->setName("Cosine Wave"); mapper = new QVXYModelMapper(this); mapper->setXColumn(0); mapper->setYColumn(2); mapper->setSeries(cosineSeries); mapper->setModel(m_model); cosineSeries->setColor(Qt::blue); QChart *chart = new QChart(); chart->legend()->hide(); chart->addSeries(sineSeries); chart->addSeries(cosineSeries); chart->createDefaultAxes(); chart->axisX(sineSeries)->setMin(0); chart->axisX(sineSeries)->setMax(maixLength); chart->axisX(cosineSeries)->setMin(0); chart->axisX(cosineSeries)->setMax(maixLength); chart->axisY(sineSeries)->setMin(-1); chart->axisY(sineSeries)->setMax(1); chart->axisY(cosineSeries)->setMin(-1); chart->axisY(cosineSeries)->setMax(1); chart->setTitle("Simple line chart example"); QChartView *chartView = new QChartView(chart); chartView->setRenderHint(QPainter::Antialiasing); mainLay->addWidget(chartView,i/5,i%5 ); } m_updateTimer->start(); } private slots: void addSeriesData() { if (m_model->rowCount() <= currentCounter) m_model->insertRows(m_model->rowCount(), currentCounter - m_model->rowCount() + 1); m_model->setData(m_model->index(currentCounter, 0), currentCounter); m_model->setData(m_model->index(currentCounter, 1), std::sin((shift+currentCounter)*pi / 180.0)); m_model->setData(m_model->index(currentCounter, 2), std::cos((shift + currentCounter)*pi / 180.0)); currentCounter += 1.0; if (currentCounter >= maixLength) { currentCounter = 0.0; shift += 90; } } private: const double pi; double shift; double currentCounter; double frequency; QTimer* m_updateTimer; QAbstractItemModel* m_model; const int maixLength; };
15 charts, you are right, 20Hz it's not great even if in release mode is better.
-
wrote on 6 Mar 2017, 14:09 last edited by
Do you have any idea how to get 15 charts without severe performance issues?
Except outsourcing single Charts to seperate Qt-Applications and send data over ipc or something in this direction. -
wrote on 6 Mar 2017, 14:30 last edited by VRonin 3 Jun 2017, 20:06
I think yo have to decouple the data arrival frequency to the frequency you send the data to the chart.
In the QAbstractTableModel instead of emitting
dataChanged()
directly, every time a new datapoint arrives (re)start a signle shot timer that emits the signal. I'll try implementing it and update this postEDIT:
My method increased but not to an acceptable level. I have to give up
-
@VRonin thank you for your time and effort!!!
I still have some ideas left. Will post it here when one gives an acceptable result.
cheers!
-
wrote on 19 Sept 2020, 14:24 last edited by
I am working with a application that has 12 curves and I am have the same problem, if I increase the number of curves, the performance decrease. I use qcustomplot. I need to plot 300pixels/second. Does anyone have some ideas?