QCustomPlot Discussion and Comments

Is this the most efficent way for plotting real time dataReturn to overview

Say I have two vectors x and y

x = {1,3,7,9,20}
y = {1,4,5,6,7}

Now initially i would do something like this


cplot->graph(0)->setData(x, y);
ui.myplot->replot();

In my case x remains constant however y tends to change frequently so currently i am doing this

x = {1,3,7,9,20}
y = {1,9,5,6,7} //Only the second y coordinate changed and the others are still the same

so here is what i do

//Update Plot
cplot->graph(0)->setData(x, y);
ui.myplot->replot();

Is this approach correct or is their a better way ?

What you describe is the favourable way to update existing points. If you had new points coming in, you could use addData.

Usually, the replotting/painting is orders of magnitude slower than the data copying, so only care about this if you have actually measured that data copying is the problem. This is only the case if you have alot of data (say > 1 million points) in the entire graph, but only view a small portion of it (1000 points) by scaling the x axis accordingly. Then it may be the case that the copying of a 1 million wide vector takes longer than plotting 1000 points.

In this case, you can avoid the vector copy operation by injecting a QCPDataMap pointer into QCP, and accessing it from the outside, to modify the data. Do this by creating a QCPDataMap on the heap (with new) and then pass the pointer via the setData function that takes a QCPDataMap*. That function also takes the parameter copy, which you obviously set to false. Keep the pointer somewhere outside of QCP to modify the data (you will not get a writable pointer back from QCP, because the ->data() method only returns a const QCPDataMap*). It is important to be aware that this QCPDataMap is then owned by QCP. So if you delete the pointer on the outside, or try to access the pointer after the graph has been removed from the plot, your application will segfault/crash. So using this high performance method is quite a commitment – synchronizing the lifetime of the external pointer with the lifetime of the graph.

As said, make sure by benchmarking the corresponding code sections, that the copying of the vector actually is your bottleneck.

When I set copy=false, it setData() work the first time I call it but the second time is crashes because it cannot "delete mData" in the setData() function. I declared the QCPDataMap as a global variable, not sure why this is happening?

Please post the line where you declare/allocate the QCPDataMap, and the line where you pass it to setData.

Sure, thanks!:

QCPDataMap my_scan;
QCPDataMap* my_scan_ptr = &my_scan;

void MainWindow::slotPlotScan(structScanType scanData)
{
    my_scan.clear();

    for (int i=0; i<static_cast<int>(scanData.numSamples); i++)
        my_scan.insert(i,QCPData(i,scanData.pScanSamples[i]));

    ui->customPlot->graph()->setData(my_scan_ptr,false);
    ui->customPlot->replot();
}

Like I said, you need to create the memory on the heap, with new. Currently you're creating it on the stack, and of course deleting memory on the stack leads to a crash.
As a general rule: Never pass stack pointers to a class that might take ownership of the memory or store the pointer internally. Same situation with QCPGraph. When you pass a pointer to setData with copy=false, the graph takes ownership of the memory.

Allocate heap memory like this:
QCPDataMap *my_scan = new QCPDataMap;

Further, don't pass the pointer with setData a second time, because after the first time, you're not owner of the memory anymore. So QCPGraph will internally delete the memory and thus invalidate the pointer that you're just passing in.

Thank you, that worked! I thought global variables were on the heap, guess not.

I'm surprised it didn't make my plotting rate faster. I have 32000 points and now a point-by-point data copy has been eliminated, correct? Anyway, this is an awesome tool, thank you for writing and supporting it!!!

Well I've told you before this can only be an issue if you have a million points or more and additionally only if you view a small percentage of them at a time on the screen.

Copying 32000 points is nothing for today's architectures. A modern RAM moves 10 gigs per second. This is why I had recommended actually measuring/benchmarking where your performance bottlenecks happen.