JKQtPlotter/examples/speed
jkriege2 d51d47b2f4 requiring higher cmake-version, due to CMP0076
using CMAKE_CURRENT_LIST_DIR instead of CMAKE_CURRENT_SOURCE_DIR
2022-04-18 22:00:31 +02:00
..
CMakeLists.txt requiring higher cmake-version, due to CMP0076 2022-04-18 22:00:31 +02:00
README.md improved speedtest example (context-menu now allows to select the different options) and updated performance table for a newer processor 2019-11-18 16:46:15 +01:00
speed_and_lib.pro using CMake now to build examples 2019-06-20 22:24:47 +02:00
speed.cpp activated high-dpi scaling for all JKQtPlotter examples 2022-04-15 23:01:09 +02:00
speed.pro using CMake now to build examples 2019-06-20 22:24:47 +02:00
speedtestplot.cpp fixed several compiler warnings (mostly Visual Studio): clean-up of use of math constants M_PI ... and j0()/j1()/...-functions etc. 2019-11-24 10:42:44 +01:00
speedtestplot.h improved speedtest example (context-menu now allows to select the different options) and updated performance table for a newer processor 2019-11-18 16:46:15 +01:00

Example (JKQTPlotter): Simple line-graph with live-data (speed test)

This project (see ./examples/speed/) simply creates a JKQTPlotter widget (as a new window) and adds two line-graph (a sine and a cosine wave). Data is stored in two std::array<double, NDATA> objects (X, Y, and Y2) and the data is added as external pointer to the datastore:

    // 3. make data available to JKQTPlotter by adding it to the internal datastore.
    //    Here the data from the std::array's is not copied, but only the pointer to
    //    the array is added to the datastore. therefore the datastore does not manage
    //    the memory, oly uses the data stored in it!
    JKQTPDatastore* ds=getDatastore();
    size_t columnX=ds->addColumn(X.data(), X.size(), "x");
    size_t columnY=ds->addColumn(Y.data(), Y.size(), "y");
    size_t columnY2=ds->addColumn(Y2.data(), Y2.size(), "y2");

The datastore then uses the data from the std::array instances, but does not own their memory, i.e. also does not free it. This is useful, when data fro external sources should be used without copying.

For this example we also don't use axis autoscaling, but set the axes explicitly:

    // 6. scale the plot so the graph is contained
    setX(X[0], X[NDATA-1]);
    setY(-2,2);

Finally a slot is started with a one-shot timer. In that slot, the data is shifted one place to the left and the graph is updated. The slot also calculated the current framerate and displays it in the window title. Finally a single-shot timer with 1ms delay is used to call the slot again (i.e. continuously):

void SpeedTestPlot::plotNewData()
{
    // move old data to the left
    for (size_t i=0; i<NDATA-1; i++) {
        X[i]=X[i+1];
        Y[i]=Y[i+1];
        Y2[i]=Y2[i+1];
    }
    // add one new data point
    X[NDATA-1]=X[NDATA-2]+dx;
    Y[NDATA-1]=sin(X[NDATA-1])+static_cast<double>(std::rand())/static_cast<double>(RAND_MAX + 1u)-0.5;
    Y2[NDATA-1]=cos(X[NDATA-1])+static_cast<double>(std::rand())/static_cast<double>(RAND_MAX + 1u)-0.5;

    // set new x-range and replot
    setX(X[0], X[NDATA-1]);
    redrawPlot();

    // calculate and update FPS-rate in window title
    auto tlastalst=t_lastplot;
    t_lastplot=std::chrono::system_clock::now();
    double delta_secs=static_cast<double>(std::chrono::duration_cast<std::chrono::milliseconds>(t_lastplot-tlastalst).count())/1000.0;
    setWindowTitle(QString("Live Data Speed Test: %2 datapoint, %1 fps").arg(1/delta_secs).arg(NDATA));
    // enqueue call for next data value
    QTimer::singleShot(1, this, SLOT(plotNewData()));
}

The result looks like this:

speed1

There are different facor affecting the replot speed:

  1. Anti-Aliasing: If JKQTPlotter uses Anti-Aliasing for plotting, the plots are much nicer, but also about a factor of 3-4 slower. This is due to the increased amount of calculations, necessary in the drawing sub-system of Qt. You can configrue anti-aliasing with these calls:
       plot.getPlotter()->setUseAntiAliasingForGraphs(false);
       plot.getPlotter()->setUseAntiAliasingForSystem(false);
       plot.getPlotter()->setUseAntiAliasingForText(false);
    
  2. Number of Graphs: The number of plots (and also ther type and complexity) is a major imapct factor in the plotting speed. You can switch off a plot with the context menu:
    contextmenu_graph_visibility
  3. Axis Scales and Plot Appearance: Replotting is done in two steps: First the plot with the axes, labels etc. is drawn. Then the graphs are draw on top. Therefore a replot is faster, if only the graphs change, because the background (plot) does not have to be replotted.

The next table summarizes some results for plotting speed under different conditions, obatined with the test program in this directory (conditions: Qt 5.11, 32-bit, MinGW, Release, Win7, Phenom II X4 765, 500 data points):

Anti-Aliasing X-Axis Redraw # Graphs frame rate [fps]
yes yes 2 4
yes yes 1 7
yes no 2 9
yes no 1 16
no yes 2 18
no yes 1 24
no no 2 32
no no 1 48

Rerunning this test on a modern AMD Ryzen 3600 (conditions: Qt 5.13.1, 64-bit, MinGW, Release, AMD Ryzen 3600, Win10, 500 data points):

Anti-Aliasing X-Axis Redraw # Graphs frame rate [fps]
yes yes 2 7
yes yes 1 14
yes no 2 14
yes no 1 28
no yes 2 30
no yes 1 52
no no 2 59
no no 1 100