#include <qapplication.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qtime>
#include <qpainter.h>
#include "chartplot.h"
{
public:
{
setStateMachine(new QwtPickerTrackerMachine());
setRubberBandPen
(QPen(Qt
::DotLine));
}
private:
{
QwtText text
("X = " + QDateTime::fromTime_t(pos.
x()).
toString("yyyy.MM.dd. hh:mm:ss") + "\nY = " + QString::number(pos.
y()));
QColor bgColor
(Qt
::lightGray);
bgColor.setAlpha(100);
text.
setBackgroundBrush(QBrush(bgColor
));
return text;
}
};
{
QList<double>
&majorTicks
= ticks
[QwtScaleDiv::MajorTick];
QList<double>
&mediumTicks
= ticks
[QwtScaleDiv::MediumTick];
QList<double>
&minorTicks
= ticks
[QwtScaleDiv::MinorTick];
if (xData.count()<11)
{
foreach (double value, xData)
majorTicks += value;
if (xData.count()>1)
{
for (int i = 0; i < xData.count() - 1; i++)
for (int j = 1; j < 6; j++)
mediumTicks += xData[i] + j * (xData[i+1] - xData[i]) / 5;
for (int i = 0; i < xData.count() - 1; i++)
for (int j = 1; j < 11; j++)
minorTicks += xData[i] + j * (xData[i+1] - xData[i]) / 10;
}
}
else
{
// Quantity-based division
// QVector<double> tempXData;
// for (int i=0; i<11; i++)
// {
// int value = (i*(xData.count()-1)/10);
// tempXData.append(xData[value]);
// majorTicks += tempXData[i];
// }
// Value-based division
QVector<double> tempXData;
for (int i=0; i<11; i++)
{
tempXData.append(xData[0] + i*(xData[xData.count()-1] - xData[0])/10);
majorTicks += tempXData.last();
}
for (int i = 0; i < tempXData.count() - 1; i++)
for (int j = 1; j < 6; j++)
mediumTicks += tempXData[i] + j * (tempXData[i+1] - tempXData[i]) / 5;
for (int i = 0; i < tempXData.count() - 1; i++)
for (int j = 1; j < 11; j++)
minorTicks += tempXData[i] + j * (tempXData[i+1] - tempXData[i]) / 10;
}
return QwtScaleDiv(xData.
first(), xData.
last(), ticks
);
}
{
public:
{
setMousePattern
(QwtEventPattern::MouseSelect2, Qt
::RightButton, Qt
::ControlModifier);
setZoomBase();
}
};
{
public:
Grid()
{
enableXMin(true);
setMajPen
(QPen(Qt
::white,
0, Qt
::DotLine));
setMinPen
(QPen(Qt
::lightGray,
0 , Qt
::DotLine));
}
{
}
};
{
public:
TimeScaleDraw()
{
setLabelRotation(0);
setLabelAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
setSpacing(15);
}
virtual QwtText label
(double value
) const {
time = time.fromTime_t(value);
return time.toString("yyyy.MM.dd.\nhh:mm:ss");
}
};
{
public:
Background()
{
setZ(0.0);
}
virtual int rtti() const
{
}
{
color = color.darker(150);
painter->fillRect(rect, color);
}
};
{
public:
{
}
void setColor
(const QColor &color
) {
c.setAlpha(150);
setPen(c);
setBrush(c);
}
};
{
this->model = model;
splineUsed = isSplineUsed;
setAutoReplot(false);
plotLayout()->setAlignCanvasToScales(true);
signs
->setItemMode
(QwtLegend::CheckableItem);
insertLegend
(signs,
QwtPlot::RightLegend);
setAxisTitle
(QwtPlot::xBottom,
"Report time");
setAxisScaleDraw
(QwtPlot::xBottom,
new TimeScaleDraw
());
scaleWidget
= axisWidget
(QwtPlot::xBottom);
scaleWidget->setMinBorderDist(0, fmh / 2);
setAxisTitle
(QwtPlot::yLeft,
"Quantity");
grid = new Grid;
grid->attach(this);
bg = new Background();
bg->attach(this);
countPlot();
setAxisScaleEngine
(QwtPlot::xBottom, scaleEngineX
);
setAxisScaleDiv
(QwtPlot::xBottom, scaleDiv
());
scaleEngineY->setReference(0);
setAxisScaleEngine
(QwtPlot::yLeft, scaleEngineY
);
picker
= new PlotPicker
(QwtPlot::xBottom,
this->canvas());
replot();
zoomer
= new Zoomer
(QwtPlot::xBottom,
QwtPlot::yLeft, this
->canvas
());
zoomer->setZoomBase(false);
}
void ChartPlot
::showCurve(QwtPlotItem *item,
const bool &on,
const bool &replt
) {
item->setVisible(on);
if (w
&& w
->inherits
("QwtLegendItem")) ((QwtLegendItem *)w
)->setChecked
(on
);
if (replt) replot();
}
void ChartPlot::useSpline(bool on, bool refresh)
{
if (on)
{
for (int i=0; i<curve.count(); i++)
{
curve.at(i)->setCurveFitter(curveFitter);
}
}
else
{
for (int i=0; i<curve.count(); i++)
{
curveFitter = new QwtWeedingCurveFitter;
curve.at(i)->setCurveFitter(curveFitter);
}
}
if (refresh) replot();
}
void ChartPlot::countPlot()
{
// Store current visibility of curves if they exist, otherwise initialize visibility to true
QList<bool> visible;
if (curve.isEmpty())
{
for (int column = 1; column < model->columnCount(); column++)
visible.append(true);
}
else
{
for (int column = 1; column < model->columnCount(); column++)
{
visible.append(curve[column - 1]->isVisible());
curve[column - 1]->detach();
}
curve.clear();
}
// Read X-axis data from table
for (int row=0; row<model->rowCount(); row++)
{
QDateTime xDateTime
= model
->item
(row,
0)->data
(Qt
::EditRole).
toDateTime();
xData << xDateTime.toTime_t();
}
// Read Y-axis data from table
for (int column = 1; column < model->columnCount(); column++)
{
QVector<double> yData;
curve.append(new ChartCurve(model->horizontalHeaderItem(column)->text()));
QVariant decoration
= model
->item
(0, column
)->data
(Qt
::DecorationRole);
if (decoration.
type() == QVariant::Color) {
curve.last()->setColor(decoration.value<QColor>());
}
curve.
last()->setCurveAttribute
(QwtPlotCurve::Fitted,
true);
curve.last()->setZ(curve.last()->z() - 1);
curve.last()->attach(this);
for (int row=0; row<model->rowCount(); row++)
{
yData << model->item(row, column)->data(Qt::EditRole).toDouble();
}
curve.last()->setSamples(xData, yData);
showCurve(curve.last(), visible[column - 1], false);
}
useSpline(splineUsed, false);
}
#include <qapplication.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qtime>
#include <qpainter.h>
#include "chartplot.h"
class PlotPicker : public QwtPlotPicker
{
public:
PlotPicker(QwtPlot::Axis xAxis,
QwtPlot::Axis yAxis,
QwtPicker::RubberBand rb,
QwtPicker::DisplayMode dm,
QwtPlotCanvas* canvas) : QwtPlotPicker( xAxis, yAxis, rb , dm , canvas)
{
setStateMachine(new QwtPickerTrackerMachine());
setRubberBandPen(QPen(Qt::DotLine));
setRubberBand(QwtPicker::CrossRubberBand);
}
private:
QwtText trackerTextF(const QPointF &pos) const
{
QwtText text("X = " + QDateTime::fromTime_t(pos.x()).toString("yyyy.MM.dd. hh:mm:ss") + "\nY = " + QString::number(pos.y()));
QColor bgColor(Qt::lightGray);
bgColor.setAlpha(100);
text.setBackgroundBrush(QBrush(bgColor));
return text;
}
};
QwtScaleDiv ChartPlot::scaleDiv()
{
QList<double> ticks[QwtScaleDiv::NTickTypes];
QList<double> &majorTicks = ticks[QwtScaleDiv::MajorTick];
QList<double> &mediumTicks = ticks[QwtScaleDiv::MediumTick];
QList<double> &minorTicks = ticks[QwtScaleDiv::MinorTick];
if (xData.count()<11)
{
foreach (double value, xData)
majorTicks += value;
if (xData.count()>1)
{
for (int i = 0; i < xData.count() - 1; i++)
for (int j = 1; j < 6; j++)
mediumTicks += xData[i] + j * (xData[i+1] - xData[i]) / 5;
for (int i = 0; i < xData.count() - 1; i++)
for (int j = 1; j < 11; j++)
minorTicks += xData[i] + j * (xData[i+1] - xData[i]) / 10;
}
}
else
{
// Quantity-based division
// QVector<double> tempXData;
// for (int i=0; i<11; i++)
// {
// int value = (i*(xData.count()-1)/10);
// tempXData.append(xData[value]);
// majorTicks += tempXData[i];
// }
// Value-based division
QVector<double> tempXData;
for (int i=0; i<11; i++)
{
tempXData.append(xData[0] + i*(xData[xData.count()-1] - xData[0])/10);
majorTicks += tempXData.last();
}
for (int i = 0; i < tempXData.count() - 1; i++)
for (int j = 1; j < 6; j++)
mediumTicks += tempXData[i] + j * (tempXData[i+1] - tempXData[i]) / 5;
for (int i = 0; i < tempXData.count() - 1; i++)
for (int j = 1; j < 11; j++)
minorTicks += tempXData[i] + j * (tempXData[i+1] - tempXData[i]) / 10;
}
return QwtScaleDiv(xData.first(), xData.last(), ticks);
}
class Zoomer: public QwtPlotZoomer
{
public:
Zoomer(int xAxis, int yAxis, QwtPlotCanvas *canvas) : QwtPlotZoomer(xAxis, yAxis, canvas)
{
setMousePattern(QwtEventPattern::MouseSelect2, Qt::RightButton, Qt::ControlModifier);
setMousePattern(QwtEventPattern::MouseSelect3, Qt::RightButton);
setZoomBase();
}
};
class Grid: public QwtPlotGrid
{
public:
Grid()
{
enableXMin(true);
setMajPen(QPen(Qt::white, 0, Qt::DotLine));
setMinPen(QPen(Qt::lightGray, 0 , Qt::DotLine));
}
virtual void updateScaleDiv(const QwtScaleDiv &xMap, const QwtScaleDiv &yMap)
{
QList<double> ticks[QwtScaleDiv::NTickTypes];
ticks[QwtScaleDiv::MajorTick] = xMap.ticks(QwtScaleDiv::MajorTick);
ticks[QwtScaleDiv::MinorTick] = xMap.ticks(QwtScaleDiv::MinorTick);
QwtPlotGrid::updateScaleDiv(QwtScaleDiv(xMap.lowerBound(), xMap.upperBound(), ticks), yMap);
}
};
class TimeScaleDraw: public QwtScaleDraw
{
public:
TimeScaleDraw()
{
setTickLength(QwtScaleDiv::MajorTick, 8);
setTickLength(QwtScaleDiv::MinorTick, 2);
setTickLength(QwtScaleDiv::MediumTick, 4);
setLabelRotation(0);
setLabelAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
setSpacing(15);
}
virtual QwtText label(double value) const
{
QDateTime time;
time = time.fromTime_t(value);
return time.toString("yyyy.MM.dd.\nhh:mm:ss");
}
};
class Background: public QwtPlotItem
{
public:
Background()
{
setZ(0.0);
}
virtual int rtti() const
{
return QwtPlotItem::Rtti_PlotUserItem;
}
virtual void draw(QPainter *painter,
const QwtScaleMap &,
const QwtScaleMap &,
const QRectF &rect) const
{
QColor color(Qt::gray);
color = color.darker(150);
painter->fillRect(rect, color);
}
};
class ChartCurve: public QwtPlotCurve
{
public:
ChartCurve(const QString &title) : QwtPlotCurve(title)
{
setRenderHint(QwtPlotItem::RenderAntialiased);
}
void setColor(const QColor &color)
{
QColor c = color;
c.setAlpha(150);
setPen(c);
setBrush(c);
}
};
ChartPlot::ChartPlot(QStandardItemModel *model, bool isSplineUsed, QWidget *parent) : QwtPlot(parent)
{
this->model = model;
splineUsed = isSplineUsed;
setAutoReplot(false);
plotLayout()->setAlignCanvasToScales(true);
signs = new QwtLegend;
signs->setItemMode(QwtLegend::CheckableItem);
insertLegend(signs, QwtPlot::RightLegend);
setAxisTitle(QwtPlot::xBottom, "Report time");
setAxisScaleDraw(QwtPlot::xBottom, new TimeScaleDraw());
scaleWidget = axisWidget(QwtPlot::xBottom);
const int fmh = QFontMetrics(scaleWidget->font()).height();
scaleWidget->setMinBorderDist(0, fmh / 2);
setAxisTitle(QwtPlot::yLeft, "Quantity");
grid = new Grid;
grid->attach(this);
bg = new Background();
bg->attach(this);
countPlot();
scaleEngineX = new QwtLinearScaleEngine;
scaleEngineX->setAttribute(QwtScaleEngine::Floating, true);
setAxisScaleEngine(QwtPlot::xBottom, scaleEngineX);
setAxisScaleDiv(QwtPlot::xBottom, scaleDiv());
scaleEngineY = new QwtLinearScaleEngine;
scaleEngineY->setAttribute(QwtScaleEngine::IncludeReference, true);
scaleEngineY->setReference(0);
setAxisScaleEngine(QwtPlot::yLeft, scaleEngineY);
picker = new PlotPicker(QwtPlot::xBottom,
QwtPlot::yLeft,
QwtPlotPicker::CrossRubberBand,
QwtPicker::ActiveOnly,
this->canvas());
replot();
zoomer = new Zoomer(QwtPlot::xBottom, QwtPlot::yLeft, this->canvas());
zoomer->setZoomBase(false);
connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)), SLOT(showCurve(QwtPlotItem *, bool)));
}
void ChartPlot::showCurve(QwtPlotItem *item, const bool &on, const bool &replt)
{
item->setVisible(on);
QWidget *w = legend()->find(item);
if (w && w->inherits("QwtLegendItem")) ((QwtLegendItem *)w)->setChecked(on);
if (replt) replot();
}
void ChartPlot::useSpline(bool on, bool refresh)
{
if (on)
{
for (int i=0; i<curve.count(); i++)
{
curveFitter = new QwtSplineCurveFitter;
curve.at(i)->setCurveFitter(curveFitter);
}
}
else
{
for (int i=0; i<curve.count(); i++)
{
curveFitter = new QwtWeedingCurveFitter;
curve.at(i)->setCurveFitter(curveFitter);
}
}
if (refresh) replot();
}
void ChartPlot::countPlot()
{
// Store current visibility of curves if they exist, otherwise initialize visibility to true
QList<bool> visible;
if (curve.isEmpty())
{
for (int column = 1; column < model->columnCount(); column++)
visible.append(true);
}
else
{
for (int column = 1; column < model->columnCount(); column++)
{
visible.append(curve[column - 1]->isVisible());
curve[column - 1]->detach();
}
curve.clear();
}
// Read X-axis data from table
for (int row=0; row<model->rowCount(); row++)
{
QDateTime xDateTime = model->item(row, 0)->data(Qt::EditRole).toDateTime();
xData << xDateTime.toTime_t();
}
// Read Y-axis data from table
for (int column = 1; column < model->columnCount(); column++)
{
QVector<double> yData;
curve.append(new ChartCurve(model->horizontalHeaderItem(column)->text()));
curve.last()->setStyle(QwtPlotCurve::Lines);
QVariant decoration = model->item(0, column)->data(Qt::DecorationRole);
if (decoration.type() == QVariant::Color)
{
curve.last()->setColor(decoration.value<QColor>());
}
curve.last()->setCurveAttribute(QwtPlotCurve::Fitted, true);
curve.last()->setZ(curve.last()->z() - 1);
curve.last()->attach(this);
for (int row=0; row<model->rowCount(); row++)
{
yData << model->item(row, column)->data(Qt::EditRole).toDouble();
}
curve.last()->setSamples(xData, yData);
showCurve(curve.last(), visible[column - 1], false);
}
useSpline(splineUsed, false);
}
To copy to clipboard, switch view to plain text mode
Bookmarks