QCustomPlot Discussion and Comments

Graphs are not displayed after their creationReturn to overview

Hi!

I've been working with QCP for a few months now and never encounter big problems. Well, except now... What's strange is that this code worked in another project, so don't see what's wrong here... Maybe the way I create the class that manage the plots?
I have multiple graph in one plot and use a QVector<QVector<double>> as a matrix to store the data that are to be displayed.
The plot contains data, but just don't show.
Maybe with the code it will be clearer. Here, the CentralMiddleLayerDisplayer receive data to be displayed from the CentralMiddleLayerManager (its parent).

Just to simplify, I don't show the code of the Page class which is not relevant. Its just a class that I use to store data for multiple objects.
The QVector labelList contains the name of the graphs.

CentralMiddleLayerDisplayer.cpp:

CentralMiddleLayerDisplayer::CentralMiddleLayerDisplayer(QSize size,
                                                         Ui::MainWindow* ui,
                                                         QVector<QString> labelList,
                                                         Page *page,
                                                         QVector<QVector<double>> initialPlotMatrix)
{
    setGeometry(0, 0, size.width(), size.height());
    pageManager = page;
    nbPlot = labelList.size();
    plotMatrix = initialPlotMatrix;


    // Creation of the x axis
    //--------------------
    xAxis.resize(pageManager->scale);
    for (int i = 0; i < pageManager->scale; i++)
    {
        xAxis[i] = i;
    }


    //==============================
    // Plot creation
    //==============================

    // Plot preparation
    //--------------------
    plot = new QCustomPlot;


    // Creation of the graphs and offset the data so they're not on top of each other
    //--------------------
    QCPRange defaultRange(-100., 100.);
    for (int i = 0; i < nbPlot; i++)
    {
        QCPAxis *axis = plot->axisRect()->addAxis(QCPAxis::atLeft);
        axis->setRange(defaultRange.lower - (nbPlot - 1 - i) * defaultRange.size(),
                        defaultRange.upper + i * defaultRange.size());
        axis->setVisible(false);

        QCPGraph *graph = new QCPGraph(plot->xAxis, axis);
    }


    // Set the data to the plot
    //--------------------
    for (int i = 0; i < plot->graphCount(); i++)
    {
        plot->graph(i)->setData(xAxis, plotMatrix[i], true);
        plot->graph(i)->setPen(QPen(Qt::black, 0.75));
    }


    // Set plots characteristics
    //--------------------
    plot->xAxis->setRange(0, pageManager->scale);

    plot->xAxis->setVisible(false);
    plot->yAxis->setVisible(false);

    plot->axisRect()->setAutoMargins(QCP::msNone);
    plot->axisRect()->setMargins(QMargins(0, 10, 0, 0));
    plot->setStyleSheet(("background:hsva(255, 255, 255, 0%);"));
    plot->setBackground(QBrush(Qt::NoBrush));

    plot->setFixedHeight(700);


    //==============================
    // Layouts creation
    //==============================

    // First vertical layout : plots
    //--------------------
    QVBoxLayout *plotLayout = new QVBoxLayout;
    plotLayout->addWidget(plot);
    plotLayout->setMargin(0);
    plotLayout->setSpacing(0);
    plotLayout->addStretch();


    // Second vertical layout : labels
    //--------------------
    QVBoxLayout *labelLayout= new QVBoxLayout;
    QFont f("Arial", 7);
    for (int i = 0; i < nbPlot; i++)
    {
        QLabel *label = new QLabel;
        label->setText(labelList[i]);
        label->setFixedSize(30, 21); // w,
        label->setFont(f);
        labelLayout->addWidget(label);
    }
    labelLayout->setMargin(10);
    labelLayout->setSpacing(0);
    labelLayout->addStretch();


    // Wrapper layout
    //--------------------
    QHBoxLayout *wrapperLayout = new QHBoxLayout;
    wrapperLayout->addLayout(labelLayout);
    wrapperLayout->addLayout(plotLayout);
    wrapperLayout->setSpacing(0);
    wrapperLayout->setMargin(0);

    setLayout(wrapperLayout);
}

CentralMiddleLayerDisplayer.h:

#ifndef CENTRALMIDDLELAYERDISPLAYER_H
#define CENTRALMIDDLELAYERDISPLAYER_H
#include <QVector>
#include <QString>
#include "ui_MainWindow.h"
#include "qcustomplot.h"
#include "Page.h"

class CentralMiddleLayerDisplayer : public QWidget
{
    Q_OBJECT

public:
    CentralMiddleLayerDisplayer(QSize size,
                                Ui::MainWindow* ui,
                                QVector<QString> labelList,
                                Page *page,
                                QVector<QVector<double>> initialPlotMatrix);

    // Methods (override)
    void paintEvent(QPaintEvent *e);

    // Methods
    void displayEvents(QVector<int> newEventToDisplay);
    void displayNewData(QVector<QVector<double>> dataToDisplay);

    // Members
    int nbPlot;
    int eventNb;
    QCustomPlot *plot;
    QVector<double> xAxis;
    QVector<QVector<double>> plotMatrix;
    QVector<QString> labelList;
    QVector<int> eventInRange; // List the sample (position) of the event in range to be displayed
    Page *pageManager;

public slots:
    void requestEegDisplay(QVector<QVector<double>> dataToDisplay);
    void requestEventDisplay(QVector<QVector<int>> eventToDisplay);
};
#endif // CENTRALMIDDLELAYERDISPLAYER_H


And here's the part of the code of the CentralMiddleLayerManager where I create the displayer.
Same here, I don't provide the code for the Page and eegDataStorage objects, as they are not relevant (they just store data).

CentralMiddleLayerManager.cpp:

void CentralMiddleLayerManager::eegFileLoading(QString eegFilename)
{
    // Creation of the page manager
    pageManager = new Page();

    // Creation of the eeg data manager
    eegDataStorage = new EegDataStorage(eegFilename, pageManager);

    pageManager->setActualRange(0);
    labelList = eegDataStorage->getEegLabel();

    // Creation of the initial plot matrix for the creation of the displayer
    QVector<QVector<double>> initialPlotMatrix;
    initialPlotMatrix = eegDataStorage->dataInRange(pageManager->lowerRangeActual);

    // Creation of the CentralMiddleLayerDisplayer
    displayer = new CentralMiddleLayerDisplayer(sizeCentral, uiCentral, labelList, pageManager, initialPlotMatrix);
    displayer->setParent(this);

    connect(this, SIGNAL(sendEegData(QVector<QVector<double>>)),
            this->displayer, SLOT(requestEegDisplay(QVector<QVector<double>>)));

    emit(fileLoaded());
}

CentralMiddleLayerManager.h:

#ifndef CENTRALMIDDLELAYERMANAGER_H
#define CENTRALMIDDLELAYERMANAGER_H
#include <QDebug>
#include <QVector>
#include <QString>
#include "ui_MainWindow.h"
#include "EegDataStorage.h"
#include "EventDataStorage.h"
#include "ScaleWindow.h"
#include "CentralMiddleLayerDisplayer.h"
#include "Page.h"

class CentralMiddleLayerManager : public QWidget
{
    Q_OBJECT

public:
    CentralMiddleLayerManager(QSize size, Ui::MainWindow* ui);

    // Methods
    void pageChange(QString);
    void pageChange(int);
    void scaleChange(int newScale, QString scaleType);
    void eegFileLoading(QString eegFilename);
    void getEegToDisplay();

    // Members
    int nbPlot;
    QVector<QString> labelList;
    int nbEventDisplayed;
    bool areEventsLoaded;
    Page *pageManager;
    EegDataStorage *eegDataStorage;
    CentralMiddleLayerDisplayer *displayer;
    QSize sizeCentral;
    Ui::MainWindow* uiCentral;

private:
    // Members
    ScaleWindow* scaleWindow;

signals:
    void sendEegData(QVector<QVector<double>> eegMatrix);
    void samplePerPage(int samplePerPage);
    void fileLoaded(); // Just a signal to tell the botoom layer to display the graduations

public slots:
    void requestEegFileLoading(QString eegFilename);
};
#endif // CENTRALMIDDLELAYERMANAGER_H


If you need more details, I'll do my best to provide them.
Any idea might help.

Thanks and have a good day!

maybe i'm missing something, but i dont see a call to replot.

I have another function to replot, for when the data changes. Here its just the creation and initialization of the plots. I never had to call replot() when creating plot for the first time.
I did try to use replot() though but it doesn't do anything neither.

However, I just find a solution.
My project is a little bit complex but here it is:
My MainWindow have a Wrapper (QWidget), that manage all the objects contained in the Central Widget (Bottom-, Central- and Top- MiddleLayer).
The the Wrapper has a child, the CentralMiddleLayerManager, which in turn has a child, the CentralMiddleLayerDisplayer, as seen above.

During some tests, I noticed that if I use the function to create/display the plots (the one in CentralMiddleLayerDisplayer), then everything works well.

So the solution was to make the Displayer a child of the Wrapper instead of the Manager, and then pass the Displayer to the Manager as a pointer during its creation. And here, everything works perfectly (well for now I did not see any problems).

If anyone had a similar problem, hope it will help.

I don't know the reasons of this behavior though... Maybe I did something wrong in the relationship between the Wrapper, Manager and Displayer...