QCustomPlot Discussion and Comments

Plotting In Other Threads, It Is Safe?Return to overview

It is safe to call QCustomPlot::replot() with QCustomPlot::rpRefreshHint in another thread? I know that is not a good idea to manipulate QWidget from other threads, But my problem was plotting 6k(1k per graph) points in 5 instance of QCustomPlot(points are added using QCPGraph::addData() and I got performance issues with QCustomPlot::replot().

So I tried to move QCustomPlot::replot to another thread and it just work fine without any issue and the performance problem was fixed.

Sample Code:

#include "qcustomplot.h"

#include <QApplication>
#include <QPointer>
#include <QVector>
#include <QThread>
#include <QTimer>
#include <QTime>

class QCustomPlotUpdater : public QObject {
 public:
  QCustomPlotUpdater(QVector<QPointer<QCustomPlot>> const& plots)
      : plots_(plots),
        thread_(new QThread),
        start_time_(QTime::currentTime()) {
    connect(thread_, &QThread::finished, this, &QObject::deleteLater);
    connect(thread_, &QThread::started, &updater_, qOverload<>(&QTimer::start));
    connect(&updater_, &QTimer::timeout, this, &QCustomPlotUpdater::addNewPoint);
    updater_.setInterval(std::chrono::milliseconds(16));
  }
  void start() {
    thread_->start();
  }

 private:
  void addNewPoint() {
    double const key = start_time_.msecsTo(QTime::currentTime()) / 1000.0;
    for (auto const& plot : plots_) {
      for (int index = 0, end = plot->graphCount(); index < end; ++index) {
        plot->graph(index)->addData(
            key * ((index + 1) * 0.25),
            qSin(key) + std::rand() / (double)RAND_MAX * 1 * qSin(key / 0.3843));
      }
      plot->rescaleAxes();
      plot->replot(QCustomPlot::rpRefreshHint);
    }
  }

  QVector<QPointer<QCustomPlot>> plots_;
  QPointer<QThread> thread_;
  QTime const start_time_;
  QTimer updater_;
};

auto CreateCustomPlot() {
  QPointer<QCustomPlot> result = new QCustomPlot;
  for (int i = 0; i < 4; ++i) result->addGraph();
  result->setMinimumSize(500, 300);
  return result;
}

int main(int argc, char* argv[]) {
  QApplication app(argc, argv);
  QVector plots = {
      CreateCustomPlot(),
      CreateCustomPlot(),
      CreateCustomPlot(),
      CreateCustomPlot(),
  };
  auto* const updater = new QCustomPlotUpdater(plots);
  updater->start();
  for (auto const& plot : plots) plot->show();
  app.exec();
}

You could find the complete project files here: https://gist.github.com/another-ghasem/5052517283d14968339c4177b86181f0

I also tried compiling with: -fsanitize=undefined,thread and it's report nothing.

- Compiler: Debian clang version 11.0.1-2~deb10u1
- OS: Debian Buster 4.19.235-1
- Qt: 5.15.2
- QCustomPlot: 2.1.0, released on March 29, 2021

+ moveToThread() Added.

Have you had any issues with this? Was just looking to implement something similar in my own code, sounds like you got it working which is promising but have you ran into any long term performance/memory problems?