QCustomPlot Discussion and Comments

Slow drag response when many points are visible on the plotReturn to overview

I want to understand how can I optimize the QCustomPlot to render many points showing on the plot at the same time.

For this particular example, I have plotted 600 000 points each on 2 seperate graphs (in total 1 200 000) points.

In my .h file, I have 2 vectors declared that hold information about all points:

QVector<double> qv_x,qv_y;
QVector<double> qv_x_voltage,qv_y_voltage;


And in my .cpp, I have the following:

    
//Append list of qv_x and qv_y which contains all current meaurement points
void MainWindow::addPoint_current(double x, double y)
{
    qv_x.append(x);
    qv_y.append(y);
}


//Append list of qv_x_voltage and qv_y_voltage which contains all voltage measuremen points
void MainWindow::addPoint_voltage(double x, double y)
{
    qv_x_voltage.append(x);
    qv_y_voltage.append(y);
}


void MainWindow::setup_graph(QCustomPlot *customPlot)
{
    current_upper_limit = 1;
    current_lower_limit = 0;

    voltage_upper_limit = 3;
    voltage_lower_limit = 0;

    QColor accentColor = QColor(Qt::red);
    QColor themeColor = QColor(Qt::white);
    QColor themeBackgroundColor = QColor(55, 57, 53);


    foreach (QCPAxisRect *rect, customPlot->axisRects())
    {
        foreach (QCPAxis *axis, rect->axes())
        {
            axis->setLabelColor(themeColor);
            axis->setBasePen(QPen(themeColor, 0));
            axis->setTickPen(QPen(themeColor, 0));
            axis->setSubTickPen(QPen(themeColor, 0));
            axis->setTickLabelColor(themeColor);
            axis->grid()->setPen(QPen(themeColor, 0.0, Qt::DotLine));
            axis->grid()->setSubGridVisible(false);

            axis->setSelectedTickLabelColor(accentColor);
            axis->setSelectedLabelColor(accentColor);
            axis->setSelectedBasePen(QPen(accentColor, 0));
            axis->setSelectedSubTickPen(QPen(accentColor, 0));
            axis->setSelectedTickPen(QPen(accentColor, 0));
        }
      }



    customPlot->setBackground(QBrush(themeBackgroundColor));

    // SETUP GRAPH 0 for Current
    customPlot->addGraph();
    customPlot->graph(0)->setScatterStyle(QCPScatterStyle::ssCircle);
    customPlot->graph(0)->setLineStyle(QCPGraph::lsLine);
    QPen pen_current;
    pen_current.setWidth(0);
    pen_current.setColor(QColor(80, 200, 120));
    customPlot->graph(0)->setPen(pen_current);



    // SETUP GRAPH 1 for Voltage
    customPlot->addGraph(customPlot->xAxis, customPlot->yAxis2);
    customPlot->graph(1)->setScatterStyle(QCPScatterStyle::ssCross);
    customPlot->graph(1)->setLineStyle(QCPGraph::lsLine);
    QPen pen_voltage;
    pen_voltage.setWidth(0);
    pen_voltage.setColor(QColor(225,225,50));
    customPlot->graph(1)->setPen(pen_voltage);


    customPlot->xAxis->setLabel("Time(h:m:s)");
    QSharedPointer<CustomTimeTicker> customTicker(new CustomTimeTicker);
    customPlot->xAxis->setTicker(customTicker);

    customPlot->yAxis->setLabel("Current (mA)");
    customPlot->yAxis->setRange(current_lower_limit, current_upper_limit);
    customPlot->yAxis2->setVisible(true);
    customPlot->yAxis2->setLabel("Voltage (V)");
    customPlot->yAxis2->setRange(voltage_lower_limit, voltage_upper_limit);

    connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(xAxisChanged(QCPRange)));



    customPlot->legend->setVisible(true);
    customPlot->graph(0)->setName("Current");
    customPlot->graph(1)->setName("Voltage");


    customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables | QCP::iMultiSelect);
    customPlot->setSelectionRectMode(QCP::srmSelect);

    customPlot->graph(0)->setSelectable(QCP::stDataRange);
    customPlot->graph(1)->setSelectable(QCP::stDataRange);

    customPlot->setNoAntialiasingOnDrag(true);

    foreach (QCPAxisRect *rect, customPlot->axisRects())
    {
        rect->setRangeDrag(Qt::Horizontal);
        rect->setRangeZoom(Qt::Horizontal);
    }

    for (double i = 0; i < 30000; i=i+0.05)
     {
      addPoint_voltage((i),1.0f);
      addPoint_current((i),2.0f);
     }

     customPlot->graph(1)->addData(qv_x_voltage,qv_y_voltage);
     customPlot->graph(0)->addData(qv_x,qv_y);
     customPlot->replot();
}




As you can see from the setup code above, I have the drag enabled for the xAxis. The problem that I am having is very slow and laggy response when I am trying to drag the Plot left/right. As I move my mouse around, the plot is lagging for like 3-4 seconds. If I zoom in on the plot to ensure only 1000 or so points are visible, the dragging works without any issues. It only becomes problem as I zoom out so all the plotted points are visible at once, then the QCustomPlot cannot keep up with rendering so many points as the graph is being moved.

I would like to get some advice on how to reduce the lag and slow response of plot dragging when there are many points visible on the graph.

Perhaps there is a smart way to combine some of the points to a single point when the graph is zoomed out? For example, if there are many samples on the X axis that have same or simmillar Y value, they can be all combined into a 2-3 points "averaged". This way it would be possible to significantly reduce the number of points showing on the graph.

Hello, I have a similar problem now, do you have a relevant solution

Try replacing customPlot->replot(); with customPlot->replot(QCustomPlot::rpQueuedReplot) as suggested in the documentation.

"For example if your application calls replot very quickly in succession (e.g. multiple independent functions change some aspects of the plot and each wants to make sure the change gets replotted), it is advisable to set refreshPriority to QCustomPlot::rpQueuedReplot. This way, the actual replotting is deferred to the next event loop iteration. Multiple successive calls of replot with this priority will only cause a single replot, avoiding redundant replots and improving performance."

Yes, I have replaced all the customPlot->replot() with customPlot->replot(QCustomPlot::rpQueuedReplot), but when redrawing with a large amount of data on the same screen (for example, there are eight QCPAxisRect under a customPlot and about 4 million points drawn on the same screen), there is still a stall. I even turned on OpenGL drawing, but it only had a subtle optimization effect on the redraw frame rate, not a smooth effect. I have seen that setAdaptiveSampling function exists in QCPGraph, but it has been turned on by default.Can I optimize this function again to improve redrawing performance when increasing the number of points on the same screen?