QCustomPlot Discussion and Comments

Overlaping plotsReturn to overview

Hi !

I have multiple independents plots that are, for the moment, one below the other in a vertical layout. Nothing special.

Now, I want to have the same organization, but allow the plot to be partially on top of each other. I think an example would be better to explain: https://en.wikipedia.org/wiki/Electroencephalography#/media/File:Spike-waves.png

Here, the plot all start at fixed positions relative to the window, but the data can be draw over the data of other plot.

My actual plots already have a transparent background. But I don't know how to allow multiple plots to overlap each other. I don't know if it's even possible...
Do you have any tips to achieve something like this ?

Quick proposition :
- each graph must have its own value axis and share the same key axis
- you will have to estimate the range of each value axis based on the default initial range (expected normal values), and the graph index (vertical position)

Let's say you have 4 graphs, each with a default initial range between 0 and 1, the real ranges would be :
Top graph - index 3 - [-3,1]
graph - index 2 - [-2,2]
graph - index 1 - [-1,3]
Bottom graph - index 0 - [0,3]

So put all graph in the same plot but shifting one of their axis ? That could work.
In that case, if I use addGraph() for each dataset, how do I shift the axis in the plot ?

For each graph :
- add an axis
- create a graph linked to this axis and the key axis

// get the axis rect
QCPAxisRect *axisRect= mPlot->axisRect();
// create a new value axis
QCPAxis *myAxis = axisRect->addAxis(QCPAxis::atLeft);
// create a graph
QCPGraph *newGraph = new QCPGraph(myAxis , axisRect->axis(QCPAxis::atBottom));

Small test based on plot-examples.pro

void MainWindow::setupRealtimeDataDemo(QCustomPlot *customPlot)
{
    demoName = "Real Time Data Demo";

    int nbGraphs = 8;
    QCPRange defaultRange(-1.,1.);
    for(int i=0; i< nbGraphs; i++) {
        QCPAxis *axis = customPlot->axisRect()->addAxis(QCPAxis::atLeft);
        axis->setRange(defaultRange.lower - (nbGraphs - 1 - i) * defaultRange.size(),
                       defaultRange.upper + i*defaultRange.size());
        axis->setVisible(false);
        QCPGraph *graph = new QCPGraph( customPlot->xAxis, axis);

        QCPItemText *text = new QCPItemText(customPlot);
        text->setText(QString("Graph %1").arg(i));
        text->position->setTypeX(QCPItemPosition::ptAxisRectRatio);
        text->position->setTypeY(QCPItemPosition::ptPlotCoords);
        text->position->setAxisRect(customPlot->axisRect());
        text->position->setAxes(nullptr, axis);
        text->position->setCoords(0, defaultRange.center());
        text->setPadding(QMargins(3, 0, 3, 0));
        text->setPositionAlignment(Qt::AlignLeft|Qt::AlignVCenter);

        double currentHueAngle = 137.50776 * i;
        int h = int( fmod( currentHueAngle, 360.0 ) );
        int s = 127;
        int v = 242;
        graph->setPen(QPen(QColor::fromHsv( h, s, v )));
    }

    QSharedPointer<QCPAxisTickerDateTime> timeTicker(new QCPAxisTickerDateTime);
    timeTicker->setDateTimeFormat("HH:mm:ss.zzz");
    timeTicker->setDateTimeSpec(Qt::UTC);
    timeTicker->setTickCount(3);
    customPlot->xAxis->setTicker(timeTicker);

    customPlot->yAxis->setVisible(false);

    connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot()));
    dataTimer.start(20); // 50Hz
}

void MainWindow::realtimeDataSlot()
{
    double key = QDateTime::currentMSecsSinceEpoch()/1000.0;

    for(int i=0; i< ui->customPlot->graphCount(); i++) {
        ui->customPlot->graph(i)->addData(key, qSin(key + (i%4 * M_PI_4)) + QRandomGenerator::global()->generateDouble());
        ui->customPlot->graph(i)->data()->removeBefore(key - 30.);
    }

    ui->customPlot->axisRect()->axis(QCPAxis::atBottom)->setRange(key - 30., key);
    ui->customPlot->replot();
}