Is it possible to use a deque as plot data?
Hi everyone,
I want to plot some data in realtime, so at the end new data is added and at the front data is removed.
A perfect job for a deque.
But setSamples does not accept a deque...
So far I used a deque and before replotting, I copied all contents of the deque to a vector.
This works, but it is quite inefficient.
Is there a better way to do this?
Re: Is it possible to use a deque as plot data?
Sure use QwtPlotCurve::setData() and bind your deque to the curve using the QwtSeriesData API.
Uwe
Re: Is it possible to use a deque as plot data?
Thanks for your great help!
One more question:
if my values are in range x: [-10,10] y: [-100,100]
How should boundingRect() look then?
return QRectF(-10, -100, 20, 200);
or
return QRectF(-10, 100, 20, 200);
?
it's a question of which coordinate system is used.
Re: Is it possible to use a deque as plot data?
Always in plot coordinates: QRectF(-10, -100, 20, 200);
I'm not aware of any coordinate system, where QRectF(-10, 100, 20, 200) might make sense and the bounding rectangle of a set of points has nothing to with coordinate systems ( like a QPolygonF::boundingRect() ) at all.
Uwe
Re: Is it possible to use a deque as plot data?
Thanks for your great help again!
Btw are you the or an author of qwt?
I think that many people might need a deque buffer for qwt plot data, so I will post it here for others to use.
Also feel very welcome to make suggestions for improvement!
PlotDataBuffer.h
Code:
#ifndef PLOTDATABUFFER_H_
#define PLOTDATABUFFER_H_
#include <deque>
#include <QPointF>
#include "qwt_series_data.h"
class PlotDataBuffer : public QwtSeriesData<QPointF>
{
public:
PlotDataBuffer(int windowSize);
void setWindowSize(int windowSize);
double getMinX() const;
double getMaxX() const;
double getMinY() const;
double getMaxY() const;
void PlotDataBuffer
::addData(double x,
double y
) {addData
(QPointF(x, y
));
} void addData(const QPointF& p);
void clear();
virtual size_t size() const {return deque_.size();}
virtual QPointF sample
(size_t i
) const {return deque_
[i
];
} virtual QRectF boundingRect
() const;
private:
void makeMinMaxValid() const;
int windowSize_;
std::deque<QPointF> deque_;
mutable double minX_;
mutable double maxX_;
mutable double minY_;
mutable double maxY_;
mutable bool minMaxValid_;
};
#endif
PlotDataBuffer.cpp
Code:
#include "PlotDataBuffer.h"
#include <cmath>
#include <algorithm>
using namespace std;
class MinMax
{
public:
MinMax():
minX_(0.0),
maxX_(0.0),
minY_(0.0),
maxY_(0.0)
{
}
void operator()(const QPointF& p)
{
minX_ = min(minX_, p.x());
maxX_ = max(maxX_, p.x());
minY_ = min(minY_, p.y());
maxY_ = max(maxY_, p.y());
}
double getMinX() const
{
return minX_;
}
double getMaxX() const
{
return maxX_;
}
double getMinY() const
{
return minY_;
}
double getMaxY() const
{
return minY_;
}
private:
double minX_;
double maxX_;
double minY_;
double maxY_;
};
PlotDataBuffer::PlotDataBuffer(int windowSize):
minX_(0.0),
maxX_(0.0),
minY_(0.0),
maxY_(0.0),
windowSize_(windowSize),
minMaxValid_(true)
{
}
void PlotDataBuffer::setWindowSize(int windowSize)
{
if(windowSize == windowSize_)
{
return;
}
windowSize_ = windowSize;
while(deque_.size() > windowSize_)
{
deque_.pop_front();
}
minMaxValid_ = false;
}
void PlotDataBuffer::clear()
{
deque_.clear();
}
QRectF PlotDataBuffer
::boundingRect() const {
makeMinMaxValid();
return QRectF(minX_, minY_, maxX_
- minX_, maxY_
- minY_
);
}
void PlotDataBuffer::addData(const QPointF& p)
{
deque_.push_back(p);
while(deque_.size() > windowSize_)
{
deque_.pop_front();
}
minMaxValid_ = false;
}
void PlotDataBuffer::makeMinMaxValid() const
{
if(!minMaxValid_)
{
MinMax m = for_each(deque_.begin(), deque_.end(), MinMax());
minX_ = m.getMinX();
maxX_ = m.getMaxX();
minY_ = m.getMinY();
maxY_ = m.getMaxY();
minMaxValid_ = true;
}
}
double PlotDataBuffer::getMinX() const
{
makeMinMaxValid();
return minX_;
}
double PlotDataBuffer::getMaxX() const
{
makeMinMaxValid();
return maxX_;
}
double PlotDataBuffer::getMinY() const
{
makeMinMaxValid();
return minY_;
}
double PlotDataBuffer::getMaxY() const
{
makeMinMaxValid();
return maxY_;
}
Re: Is it possible to use a deque as plot data?
there was a dangerous bug in PlotDataBuffer.cpp (initializing min and max with 0.0 instead of numerical limits).
Also I wrote minY_ instead of maxY_ in one getter.
Unfortuantely I cannot edit it anymore, so here is the new version, just in case that some1 wants to use it:
PlotDataBuffer.cpp
Code:
#include "PlotDataBuffer.h"
#include <cmath>
#include <algorithm>
#include <limits>
using namespace std;
class MinMax
{
public:
MinMax():
minX_(numeric_limits<double>::max()),
maxX_(numeric_limits<double>::min()),
minY_(numeric_limits<double>::max()),
maxY_(numeric_limits<double>::min()),
empty_(true)
{
}
void operator()(const QPointF& p)
{
empty_ = false;
minX_ = min(minX_, p.x());
maxX_ = max(maxX_, p.x());
minY_ = min(minY_, p.y());
maxY_ = max(maxY_, p.y());
}
double getMinX() const
{
if(empty_)
{
return 0.0;
}
return minX_;
}
double getMaxX() const
{
if(empty_)
{
return 0.0;
}
return maxX_;
}
double getMinY() const
{
if(empty_)
{
return 0.0;
}
return minY_;
}
double getMaxY() const
{
if(empty_)
{
return 0.0;
}
return maxY_;
}
private:
double minX_;
double maxX_;
double minY_;
double maxY_;
bool empty_;
};
PlotDataBuffer::PlotDataBuffer(int windowSize):
minX_(0.0),
maxX_(0.0),
minY_(0.0),
maxY_(0.0),
windowSize_(windowSize),
minMaxValid_(true)
{
}
void PlotDataBuffer::setWindowSize(int windowSize)
{
if(windowSize == windowSize_)
{
return;
}
windowSize_ = windowSize;
while(deque_.size() > windowSize_)
{
deque_.pop_front();
}
minMaxValid_ = false;
}
void PlotDataBuffer::clear()
{
deque_.clear();
}
QRectF PlotDataBuffer
::boundingRect() const {
makeMinMaxValid();
return QRectF(minX_, minY_, maxX_
- minX_, maxY_
- minY_
);
}
void PlotDataBuffer::addData(const QPointF& p)
{
deque_.push_back(p);
while(deque_.size() > windowSize_)
{
deque_.pop_front();
}
minMaxValid_ = false;
}
void PlotDataBuffer::makeMinMaxValid() const
{
if(!minMaxValid_)
{
MinMax m = for_each(deque_.begin(), deque_.end(), MinMax());
minX_ = m.getMinX();
maxX_ = m.getMaxX();
minY_ = m.getMinY();
maxY_ = m.getMaxY();
minMaxValid_ = true;
}
}
double PlotDataBuffer::getMinX() const
{
makeMinMaxValid();
return minX_;
}
double PlotDataBuffer::getMaxX() const
{
makeMinMaxValid();
return maxX_;
}
double PlotDataBuffer::getMinY() const
{
makeMinMaxValid();
return minY_;
}
double PlotDataBuffer::getMaxY() const
{
makeMinMaxValid();
return maxY_;
}
Edit: I discovered a serious problem with the QwtSeriesData API. It takes ownership of the data...
I want to use one of my buffers for more than one plotcurve, which does not work with this ownership problem.
I'm thinking of employing some kind of smart pointer and share the data of the PlotDataBuffer to work around this problem.
Edit2: What does happen if first call setData and later call setRawSamples?
Re: Is it possible to use a deque as plot data?
Found another bug:
Code:
minX_(numeric_limits<double>::max()),
maxX_(numeric_limits<double>::min()),
minY_(numeric_limits<double>::max()),
maxY_(numeric_limits<double>::min()),
Has to be replaced with:
Code:
minX_(numeric_limits<double>::max()),
maxX_(-numeric_limits<double>::max()),
minY_(numeric_limits<double>::max()),
maxY_(-numeric_limits<double>::max()),
I think I will stop posting bugfixes here , except if some1 really is interested, because it always bumps the thread.
Re: Is it possible to use a deque as plot data?
Quote:
Originally Posted by
P@u1
Edit: I discovered a serious problem with the QwtSeriesData API. It takes ownership of the data...
No you have discovered a problem in your class derived from QwtSeriesData.
QwtSeriesData is just an interface - completely unrelated to how the application stores or shares its samples. In fact it is even possible to calculate samples on the fly storing nothing - like in QwtSyntheticPointData.
Uwe
Re: Is it possible to use a deque as plot data?
I solved it by using a wrapper, which holds a reference to the actual data and does nothing in the destructor.
Re: Is it possible to use a deque as plot data?
Could you elaborate more on your final solution?
I am attempting the same feat