Results 1 to 10 of 10

Thread: How to plot a simple function with QDateTime X axis and int/double Y axis?

  1. #1
    Join Date
    May 2010
    Posts
    86
    Thanks
    17
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default How to plot a simple function with QDateTime X axis and int/double Y axis?

    Hi,

    It looks like all the included examples are to difficult to me (moving knobs, time-based changes in charts, etc.).
    I simply cannot figure out the basic use of the library.
    Can someone please include here a very-very simple example of a class that can be put in a layout as widget and shown that has only X-Y axes as described in the topic. Can someone include a simple example of Y=2X (where X is QDateTime that is converted to double for example).

    My source data is in QStandardItemModel. First column is QDateTime (real dates and times of logged events), all the other columns are measured values of different objects - so basically different lines in the chart.


    Thank you in advance!

    I include the source where I got, but it is just unreliable.

    HEADER:
    Qt Code:
    1. #ifndef CHARTPLOT_H
    2. #define CHARTPLOT_H
    3.  
    4. #include <qwt_plot.h>
    5. #include <QStandardItemModel>
    6.  
    7. class ChartCurve;
    8.  
    9. class ChartPlot : public QwtPlot
    10. {
    11. Q_OBJECT
    12. public:
    13. ChartPlot(QStandardItemModel *model, QWidget * = 0);
    14. const ChartCurve *getCurve() const
    15. {
    16. return curve;
    17. }
    18.  
    19. void setModel(QStandardItemModel *model)
    20. {
    21. this->model = model;
    22. }
    23.  
    24. QStandardItemModel *getModel()
    25. {
    26. return this->model;
    27. }
    28.  
    29. private Q_SLOTS:
    30. void showCurve(QwtPlotItem *, bool on);
    31.  
    32. private:
    33. ChartCurve *curve;
    34. };
    35.  
    36. #endif
    To copy to clipboard, switch view to plain text mode 

    SOURCE:
    Qt Code:
    1. #include <qapplication.h>
    2. #include <qlayout.h>
    3. #include <qlabel.h>
    4. #include <qtime>
    5. #include <qpainter.h>
    6. #include <qwt_plot_layout.h>
    7. #include <qwt_plot_curve.h>
    8. #include <qwt_scale_draw.h>
    9. #include <qwt_scale_widget.h>
    10. #include <qwt_legend.h>
    11. #include <qwt_legend_item.h>
    12. #include "chartplot.h"
    13. #include <QDebug>
    14.  
    15. class TimeScaleDraw: public QwtScaleDraw
    16. {
    17. public:
    18. TimeScaleDraw(const QTime &base) : baseTime(base)
    19. {
    20. }
    21.  
    22. virtual QwtText label(double v) const
    23. {
    24. QTime upTime = baseTime.addSecs((int)v);
    25. return upTime.toString();
    26. }
    27. private:
    28. QTime baseTime;
    29. };
    30.  
    31. class Background: public QwtPlotItem
    32. {
    33. public:
    34. Background()
    35. {
    36. setZ(0.0);
    37. }
    38.  
    39. virtual int rtti() const
    40. {
    41. return QwtPlotItem::Rtti_PlotUserItem;
    42. }
    43.  
    44. virtual void draw(QPainter *painter,
    45. const QwtScaleMap &, const QwtScaleMap &yMap,
    46. const QRectF &rect) const
    47. {
    48. QColor c(Qt::gray);
    49. c=c.darker(150);
    50. QRectF r = rect;
    51.  
    52. r.setBottom(yMap.transform(500));
    53. r.setTop(yMap.transform(0));
    54. painter->fillRect(r, c);
    55. }
    56. };
    57.  
    58. class ChartCurve: public QwtPlotCurve
    59. {
    60. public:
    61. ChartCurve(const QString &title) : QwtPlotCurve(title)
    62. {
    63. setRenderHint(QwtPlotItem::RenderAntialiased);
    64. }
    65.  
    66. void setColor(const QColor &color)
    67. {
    68. QColor c = color;
    69. c.setAlpha(150);
    70.  
    71. setPen(c);
    72. setBrush(c);
    73. }
    74. };
    75.  
    76. ChartPlot::ChartPlot(QStandardItemModel *model, QWidget *parent) : QwtPlot(parent)
    77. {
    78. setAutoReplot(false);
    79.  
    80. plotLayout()->setAlignCanvasToScales(true);
    81.  
    82. QwtLegend *legend = new QwtLegend;
    83. legend->setItemMode(QwtLegend::CheckableItem);
    84. insertLegend(legend, QwtPlot::RightLegend);
    85.  
    86. setAxisTitle(QwtPlot::xBottom, "Report time");
    87. //setAxisScaleDraw(QwtPlot::xBottom, new TimeScaleDraw(cpuStat.upTime()));
    88. setAxisScale(QwtPlot::xBottom, 0, 10);
    89. setAxisLabelRotation(QwtPlot::xBottom, -45.0);
    90. setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignLeft | Qt::AlignBottom);
    91.  
    92. /*
    93.   In situations, when there is a label at the most right position of the
    94.   scale, additional space is needed to display the overlapping part
    95.   of the label would be taken by reducing the width of scale and canvas.
    96.   To avoid this "jumping canvas" effect, we add a permanent margin.
    97.   We don't need to do the same for the left border, because there
    98.   is enough space for the overlapping label below the left scale.
    99.   */
    100.  
    101. QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xBottom);
    102. const int fmh = QFontMetrics(scaleWidget->font()).height();
    103. scaleWidget->setMinBorderDist(0, fmh / 2);
    104.  
    105. setAxisTitle(QwtPlot::yLeft, "Quantity");
    106. setAxisScale(QwtPlot::yLeft, 0, 100);
    107.  
    108. Background *bg = new Background();
    109. bg->attach(this);
    110.  
    111. curve = new ChartCurve("");
    112. curve->setColor(Qt::blue);
    113. curve->setZ(curve->z() - 1);
    114. curve->attach(this);
    115.  
    116. double xData[model->rowCount()];
    117. double yData[model->rowCount()];
    118. qDebug() <<"ROWCOUNT:"<<model->rowCount();
    119. for (int x=0; x<model->rowCount(); x++)
    120. {
    121. //xData[x] = model->item(x, 0)->data(Qt::EditRole).toDateTime();
    122. xData[x] = x+1;
    123. qDebug()<<"X:"<<xData[x];
    124. }
    125. for (int y=0; y<model->rowCount(); y++)
    126. {
    127. yData[y] = model->item(y, 1)->data(Qt::EditRole).toFloat();
    128. qDebug()<<"Y:"<<yData[y];
    129. }
    130.  
    131. curve->setRawSamples(xData, yData, model->rowCount());
    132. showCurve(curve, true);
    133.  
    134. //for (int i = 0; i < 100; i++) xData[100 - 1 - i] = i;
    135.  
    136. connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)), SLOT(showCurve(QwtPlotItem *, bool)));
    137. }
    138.  
    139. void ChartPlot::showCurve(QwtPlotItem *item, bool on)
    140. {
    141. item->setVisible(on);
    142. QWidget *w = legend()->find(item);
    143. if (w && w->inherits("QwtLegendItem")) ((QwtLegendItem *)w)->setChecked(on);
    144.  
    145. replot();
    146. }
    To copy to clipboard, switch view to plain text mode 

    I have tried to modify CPU plot to simple x/y function. No success.

    Thanks!

  2. #2
    Join Date
    Jul 2010
    Posts
    37
    Thanks
    13
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: How to plot a simple function with QDateTime X axis and int/double Y axis?

    I faced your problem too: if you want to learn how to use an x datetime axis, (that is not changing its values in the time like cpuplot), see friedberg example.
    (I'm using qwt 6.0)

  3. #3
    Join Date
    Feb 2006
    Location
    Munich, Germany
    Posts
    3,318
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: How to plot a simple function with QDateTime X axis and int/double Y axis?

    Scales are always based on doubles, but you can always translate date/time values into doubles by using the difference to a reference date. Additionally you need to implement how to display such a translated value into a time/date string - f.e. for the axis tick labels.

    Unfortunately Qwt doesn't offer a scale engine, that calculates useful scale ticks for date/time intervals. So if you want to have ticks according to something like 60/60/24 or 7/52/365 you need to set the ticks manually - otherwise you get ticks based on decades.

    This is what the friedberg example does - and what doesn't work very well when you zoom in.

    Uwe

  4. #4
    Join Date
    May 2010
    Posts
    86
    Thanks
    17
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: How to plot a simple function with QDateTime X axis and int/double Y axis?

    I found this example hidden in the code as commented, but it cannot be compiled. This looks to be a simple application of Qwt, and it is almost what I need to start with and to learn some basics.

    Qt Code:
    1. #include <cmath>
    2. #include <qwt_series_data.h>
    3. #include <qwt_plot_curve.h>
    4. #include <qwt_plot.h>
    5. #include <qapplication.h>
    6.  
    7. class SinusData: public QwtSyntheticPointData
    8. {
    9. public:
    10. SinusData():
    11. QwtSyntheticPointData(100)
    12. {
    13. }
    14. virtual double y(double x) const
    15. {
    16. return qSin(x);
    17. }
    18. };
    19.  
    20. int main(int argc, char **argv)
    21. {
    22. QApplication a(argc, argv);
    23.  
    24. QwtPlot plot;
    25. plot.setAxisScale(QwtPlot::xBottom, 0.0, 10.0);
    26. plot.setAxisScale(QwtPlot::yLeft, -1.0, 1.0);
    27.  
    28. QwtPlotCurve *curve = new QwtPlotCurve("y = sin(x)");
    29. curve->setData(SinusData());
    30. curve->attach(&plot);
    31.  
    32. plot.show();
    33. return a.exec();
    34. }
    To copy to clipboard, switch view to plain text mode 

    This is what I get as error:

    ..\sinus\main.cpp: In function 'int qMain(int, char**)':
    ..\sinus\main.cpp:29: error: no matching function for call to 'QwtPlotCurve::setData(SinusData)'
    ..\sinus\libraries\qwt/qwt_plot_seriesitem.h:146: note: candidates are: void QwtPlotSeriesItem<T>::setData(QwtSeriesData<T>*) [with T = QPointF]
    mingw32-make[1]: *** [release/main.o] Error 1

    If you can fix this code for me, I think I will be able to extend it with more. Thanx in advance!

  5. #5
    Join Date
    Feb 2006
    Location
    Munich, Germany
    Posts
    3,318
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: How to plot a simple function with QDateTime X axis and int/double Y axis?

    This is basic C++ and the compiler already told you what to do: "curve->setData( new SinusData() );"

    In most applications you want to pass samples from some sort array instead of a data object, that calculates values on the fly. So check all classes derived from QwtSeriesData and the convenience methods QwtPlotCurve::setSamples().

    Uwe

  6. The following user says thank you to Uwe for this useful post:

    falconium (1st May 2011)

  7. #6
    Join Date
    May 2010
    Posts
    86
    Thanks
    17
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: How to plot a simple function with QDateTime X axis and int/double Y axis?

    Yes, it was the problem. I thought that it could be some mismatch in arguments, but I also noticed finally that not the instance is given. Thx!

  8. #7
    Join Date
    May 2010
    Posts
    86
    Thanks
    17
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: How to plot a simple function with QDateTime X axis and int/double Y axis?

    Alright, this is where I got:

    Qt Code:
    1. #include <qapplication.h>
    2. #include <qlayout.h>
    3. #include <qlabel.h>
    4. #include <qtime>
    5. #include <qpainter.h>
    6. #include <qwt_plot_layout.h>
    7. #include <qwt_plot_curve.h>
    8. #include <qwt_plot_grid.h>
    9. #include <qwt_scale_draw.h>
    10. #include <qwt_scale_widget.h>
    11. #include <qwt_legend.h>
    12. #include <qwt_legend_item.h>
    13. #include <qwt_curve_fitter.h>
    14. #include "chartplot.h"
    15. #include <QDebug>
    16.  
    17. class Grid: public QwtPlotGrid
    18. {
    19. public:
    20. Grid()
    21. {
    22. enableXMin(true);
    23. setMajPen(QPen(Qt::white, 0, Qt::DotLine));
    24. setMinPen(QPen(Qt::lightGray, 0 , Qt::DotLine));
    25. }
    26.  
    27. virtual void updateScaleDiv(const QwtScaleDiv &xMap,
    28. const QwtScaleDiv &yMap)
    29. {
    30. QList<double> ticks[QwtScaleDiv::NTickTypes];
    31.  
    32. ticks[QwtScaleDiv::MajorTick] = xMap.ticks(QwtScaleDiv::MajorTick);
    33. ticks[QwtScaleDiv::MinorTick] = xMap.ticks(QwtScaleDiv::MinorTick);
    34.  
    35. QwtPlotGrid::updateScaleDiv(
    36. QwtScaleDiv(xMap.lowerBound(), xMap.upperBound(), ticks),
    37. yMap );
    38. }
    39. };
    40.  
    41. class TimeScaleDraw: public QwtScaleDraw
    42. {
    43. public:
    44. TimeScaleDraw(/*const QTime &base*/)/* : baseTime(base)*/
    45. {
    46. setTickLength(QwtScaleDiv::MajorTick, 6);
    47. setTickLength(QwtScaleDiv::MinorTick, 0);
    48. setTickLength(QwtScaleDiv::MediumTick, 0);
    49. setLabelRotation(0);
    50. setLabelAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    51. setSpacing(20);
    52. }
    53.  
    54. virtual QwtText label(double v) const
    55. {
    56. // QTime upTime = baseTime.addSecs((int)v);
    57. QDateTime time;
    58. time = time.fromTime_t(v);
    59. return time.toString("yyyy.MM.dd.\nhh:mm:ss");
    60. }
    61. //private:
    62. // QTime baseTime;
    63. };
    64.  
    65. class Background: public QwtPlotItem
    66. {
    67. public:
    68. Background()
    69. {
    70. setZ(0.0);
    71. }
    72.  
    73. virtual int rtti() const
    74. {
    75. return QwtPlotItem::Rtti_PlotUserItem;
    76. }
    77.  
    78. virtual void draw(QPainter *painter,
    79. const QwtScaleMap &, const QwtScaleMap &/*yMap*/,
    80. const QRectF &rect) const
    81. {
    82. QColor c(Qt::gray);
    83. c=c.darker(150);
    84. // QRectF r = rect;
    85.  
    86. // r.setBottom(yMap.transform(500));
    87. // r.setTop(yMap.transform(0));
    88. painter->fillRect(rect, c);
    89. }
    90. };
    91.  
    92. class ChartCurve: public QwtPlotCurve
    93. {
    94. public:
    95. ChartCurve(const QString &title) : QwtPlotCurve(title)
    96. {
    97. setRenderHint(QwtPlotItem::RenderAntialiased);
    98. }
    99.  
    100. void setColor(const QColor &color)
    101. {
    102. QColor c = color;
    103. c.setAlpha(150);
    104.  
    105. setPen(c);
    106. setBrush(c);
    107. }
    108. };
    109.  
    110. ChartPlot::ChartPlot(QStandardItemModel *model, QWidget *parent) : QwtPlot(parent)
    111. {
    112. setAutoReplot(false);
    113.  
    114. plotLayout()->setAlignCanvasToScales(true);
    115.  
    116. QwtLegend *legend = new QwtLegend;
    117. legend->setItemMode(QwtLegend::CheckableItem);
    118. insertLegend(legend, QwtPlot::RightLegend);
    119.  
    120. setAxisTitle(QwtPlot::xBottom, "Report time");
    121. setAxisAutoScale(QwtPlot::xBottom);
    122. setAxisLabelRotation(QwtPlot::xBottom, -45.0);
    123. setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignLeft | Qt::AlignBottom);
    124. setAxisScaleDraw(QwtPlot::xBottom, new TimeScaleDraw());
    125.  
    126. QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xBottom);
    127. const int fmh = QFontMetrics(scaleWidget->font()).height();
    128. scaleWidget->setMinBorderDist(0, fmh / 2);
    129.  
    130. setAxisTitle(QwtPlot::yLeft, "Quantity");
    131. //setAxisScale(QwtPlot::yLeft, 0, 50);
    132.  
    133. QwtPlotGrid *grid = new Grid;
    134. grid->attach(this);
    135.  
    136. Background *bg = new Background();
    137. bg->attach(this);
    138.  
    139. for (int column = 1; column < model->columnCount(); column++)
    140. {
    141. curve = new ChartCurve(model->horizontalHeaderItem(column)->text());
    142. curve->setStyle(QwtPlotCurve::Lines);
    143. QVariant decoration = model->item(0, column)->data(Qt::DecorationRole);
    144. if (decoration.type() == QVariant::Color)
    145. {
    146. curve->setColor(decoration.value<QColor>());
    147. }
    148. curve->setCurveAttribute(QwtPlotCurve::Fitted, true);
    149. curve->setCurveFitter(curveFitter);
    150. curve->setZ(curve->z() - 1);
    151. curve->attach(this);
    152.  
    153. QVector<double> xData;
    154. QVector<double> yData;
    155. for (int row=0; row<model->rowCount(); row++)
    156. {
    157. QDateTime xDateTime = model->item(row, 0)->data(Qt::EditRole).toDateTime();
    158. xData << xDateTime.toTime_t();
    159. yData << model->item(row, column)->data(Qt::EditRole).toDouble();
    160. }
    161. curve->setSamples(xData, yData);
    162. showCurve(curve, true);
    163. }
    164.  
    165. connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)), SLOT(showCurve(QwtPlotItem *, bool)));
    166. }
    167.  
    168. void ChartPlot::showCurve(QwtPlotItem *item, bool on)
    169. {
    170. item->setVisible(on);
    171. QWidget *w = legend()->find(item);
    172. if (w && w->inherits("QwtLegendItem")) ((QwtLegendItem *)w)->setChecked(on);
    173.  
    174. replot();
    175. }
    To copy to clipboard, switch view to plain text mode 

    How can I change the values of (major) ticks on axis X to match the date of source values or to match some nice value to be easily read by humans?

    I also have problems with spine, as it doesn't always match precisely. The plot can grow higher than the actual value. I'll send you picture tomorrow. Here it is: wrong spline

    Pictures:

    Source data: link
    Chart: link

    Thanks for any idea!
    Last edited by falconium; 2nd May 2011 at 05:35.

  9. #8
    Join Date
    May 2010
    Posts
    86
    Thanks
    17
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: How to plot a simple function with QDateTime X axis and int/double Y axis?

    OK, I have managed to fill the gaps in the chart by using Floating attribute:

    Qt Code:
    1. scaleEngineX->setAttribute(QwtScaleEngine::Floating, true);
    2. setAxisScaleEngine(QwtPlot::xBottom, scaleEngineX);
    To copy to clipboard, switch view to plain text mode 

    Now, the question is still, how to set major ticks to exact values of the original, source data, not some intermediate, calculated ones. (And of course, if there are too many discrete values on axis, to show only part of them based on an algorithm.)

    I have tried to play around with:

    setAxisMaxMinor(QwtPlot::xBottom, <some value>);
    setAxisMaxMajor(QwtPlot::xBottom, <model->rowCount() or other values>);

    No success. They always put ticks to wrong positions.
    Thank you for the help in advance! This would be the only critical thing to me.

  10. #9
    Join Date
    May 2010
    Posts
    86
    Thanks
    17
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: How to plot a simple function with QDateTime X axis and int/double Y axis?

    Now I know i would have had to use QwtScaleDiv class for this purpose:

    Qt Code:
    1. QwtScaleDiv ChartPlot::scaleDiv()
    2. {
    3. QList<double> ticks[QwtScaleDiv::NTickTypes];
    4.  
    5. QList<double> &majorTicks = ticks[QwtScaleDiv::MajorTick];
    6.  
    7. foreach (double val, xData)
    8. majorTicks += val;
    9.  
    10. QList<double> &mediumTicks = ticks[QwtScaleDiv::MediumTick];
    11. for (int i = 0; i < xData.count() - 1; ++i)
    12. mediumTicks += QDateTime::fromTime_t(xData[i]).addSecs(900).toTime_t();
    13.  
    14. QList<double> &minorTicks = ticks[QwtScaleDiv::MinorTick];
    15. for (int i = 0; i < xData.count() - 1; ++i)
    16. minorTicks += QDateTime::fromTime_t(xData[i]).addSecs(300).toTime_t();
    17.  
    18. return QwtScaleDiv(xData.first(), xData.last(), ticks);
    19. }
    To copy to clipboard, switch view to plain text mode 

    Simply call this function to set axis scale divisions in your QwtPlot instance as following:

    Qt Code:
    1. setAxisScaleDiv(QwtPlot::xBottom, scaleDiv());
    To copy to clipboard, switch view to plain text mode 

    The only problem now I have is to set one minor tick to 1/10 of major tick and one medium tick to 1/5 of major tick. Thanks for suggestions in advance!

  11. #10
    Join Date
    May 2010
    Posts
    86
    Thanks
    17
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: How to plot a simple function with QDateTime X axis and int/double Y axis?

    I solved it, please, find it here for future reference:

    Qt Code:
    1. QwtScaleDiv ChartPlot::scaleDiv()
    2. {
    3. QList<double> ticks[QwtScaleDiv::NTickTypes];
    4.  
    5. QList<double> &majorTicks = ticks[QwtScaleDiv::MajorTick];
    6.  
    7. foreach (double val, xData)
    8. majorTicks += val;
    9.  
    10. if (xData.count()>1)
    11. {
    12. QList<double> &mediumTicks = ticks[QwtScaleDiv::MediumTick];
    13. for (int i = 0; i < xData.count() - 1; i++)
    14. for (int j = 1; j < 6; j++)
    15. mediumTicks += xData[i] + j * (xData[i+1] - xData[i]) / 5;
    16.  
    17. QList<double> &minorTicks = ticks[QwtScaleDiv::MinorTick];
    18. for (int i = 0; i < xData.count()*10 - 1; i++)
    19. for (int j = 1; j < 11; j++)
    20. minorTicks += xData[i] + j * (xData[i+1] - xData[i]) / 10;
    21. }
    22.  
    23. return QwtScaleDiv(xData.first(), xData.last(), ticks);
    24. }
    To copy to clipboard, switch view to plain text mode 

  12. The following user says thank you to falconium for this useful post:

    corrado1972 (4th May 2011)

Similar Threads

  1. Replies: 2
    Last Post: 8th February 2011, 14:53
  2. Replies: 0
    Last Post: 9th August 2010, 10:46
  3. Replies: 1
    Last Post: 30th July 2010, 07:23
  4. Virtual axis ?
    By viridis in forum Qwt
    Replies: 2
    Last Post: 1st July 2008, 15:28
  5. Qwt and custom axis
    By jiveaxe in forum Qwt
    Replies: 3
    Last Post: 14th November 2007, 15:50

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.