I'm trying to figure out how to use QCPLayer to only replot certain items in the plot.
The qcustomplot documentation states this:
If you often need to call a full QCustomPlot::replot only because a non-complex object (e.g. an item) has changed while having relatively static but complex graphs in the plot, consider placing the regularly changing objects onto an own layer and setting its mode (QCPLayer::setMode) to QCPLayer::lmBuffered. This makes QCustomPlot allocate a dedicated paint buffer for this layer, and allows it to be replotted individually with QCPLayer::replot, independent of the other layers containing the potentially complex and slow graphs. See the documentation of the respective methods for details.
Which is what I'm trying to do in the example below:
I am creating a custom qcustomplot by inheriting from QCustomPlot
:
QCustomPlot_custom.h
#pragma once
#include "qcustomplot.h"
#define USING_LAYER false
struct QCPCursor{
QCPItemLine *hLine;
QCPItemLine *vLine;
QCPItemText* cursorText;
};
class QCustomPlot_custom :
public QCustomPlot
{
Q_OBJECT
private slots:
void mouseMove(QMouseEvent*);
public:
QCustomPlot_custom(QWidget* parent = NULL);
~QCustomPlot_custom(){}
private:
QCPLayer* cursorLayer;
QCPCursor cursor;
void manageCursor(double x, double y, QPen pen);
public:
void init(QVector<double> xdata, QVector<double> ydata);
};
This class initializes with some data to plot. It also overloads the mouseMove
event to control a custom cursor. USING_LAYER
set to true
means that the custom cursor is added to it's own layer (cursorLayer
).
By setting USING_LAYER
to false I get the desired effect as seen below:
The cursor is displayed by a horizontal and vertical line and the coordinates.
If I have many graphs in the plot and/or a lot of point in each graph, I will see a delay when moving the cursor. (Which is the reason I want to be able to replot only the cursor by setting it in a layer.)
QCustomPlot_custom.cpp
QCustomPlot_custom::QCustomPlot_custom(QWidget* parent)
{
connect(this, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove(QMouseEvent*)));
QCustomPlot::setInteraction(QCP::iRangeDrag, true);
QCustomPlot::setInteraction(QCP::iRangeZoom, true);
if (USING_LAYER){
this->addLayer("cursorLayer", 0, QCustomPlot::limAbove);
cursorLayer = new QCPLayer(this, "cursorLayer");
cursorLayer->setMode(QCPLayer::lmBuffered);
}
}
void QCustomPlot_custom::init(QVector<double> xdata, QVector<double> ydata)
{
this->addGraph();
this->graph(0)->setData(xdata, ydata);
QColor colorPen(10, 25, 180, 255);
QPen pen;
pen.setWidth(50);
pen.setColor(colorPen);
this->graph()->setLineStyle(QCPGraph::lsLine);
this->graph()->setPen(QPen(colorPen));
this->xAxis->setLabel("X-axis");
this->yAxis->setLabel("Y-axis");
this->rescaleAxes();
this->replot();
}
void QCustomPlot_custom::mouseMove(QMouseEvent* event)
{
//Cursor coordinates:
double x = this->xAxis->pixelToCoord(event->pos().x());
double y = this->yAxis->pixelToCoord(event->pos().y());
manageCursor(x, y, QPen(Qt::DashDotLine));
if (USING_LAYER)
cursorLayer->replot();
else
this->replot();
}
void QCustomPlot_custom::manageCursor(double x, double y, QPen pen)
{
if (cursor.hLine)
this->removeItem(cursor.hLine);
cursor.hLine = new QCPItemLine(this);
cursor.hLine->setPen(pen);
cursor.hLine->start->setCoords(-QCPRange::maxRange, y);
cursor.hLine->end->setCoords(QCPRange::maxRange, y);
if (cursor.vLine)
this->removeItem(cursor.vLine);
cursor.vLine = new QCPItemLine(this);
cursor.vLine->setPen(pen);
cursor.vLine->start->setCoords(x, -QCPRange::maxRange);
cursor.vLine->end->setCoords(x, QCPRange::maxRange);
//Coordinates as text:
if (cursor.cursorText)
this->removeItem(cursor.cursorText);
cursor.cursorText = new QCPItemText(this);
cursor.cursorText->setText(QString("(%1, %2)").arg(x).arg(y));
cursor.cursorText->position->setCoords(QPointF(x, y));
QPointF pp = cursor.cursorText->position->pixelPosition() + QPointF(50.0, -15.0);
cursor.cursorText->position->setPixelPosition(pp);
cursor.cursorText->setFont(QFont(font().family(), 8));
//Add to layer:
if (USING_LAYER){
cursor.hLine->setLayer(cursorLayer);
cursor.vLine->setLayer(cursorLayer);
cursor.cursorText->setLayer(cursorLayer);
}
}
The function that initializes the class member:
void Qt_PlotTest::testPlot(){
//Create some data and initalize plot:
QVector<double> yData, xData;
int imax = 100000;
for (int i = 0; i < imax; i++){
double x = double(i) / imax;
xData.push_back(x);
yData.push_back(pow(x, 2)*( 1.0 + 0.5*cos(20*x) + 0.1*sin(500*x - 0.1)));
}
ui.custom_QWidgetPlot->init(xData, yData);
}
When using the layer method, the cursor doesn't render. I tried understanding the documentation, but it is not clear for me how to correctly use QCPLayer
s.
How should I do this?