KD Chart API Documentation  3.1
KDChartLeveyJenningsAxis.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** This file is part of the KD Chart library.
4 **
5 ** SPDX-FileCopyrightText: 2001 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6 **
7 ** SPDX-License-Identifier: MIT
8 **
9 ****************************************************************************/
10 
12 #include "KDChartLeveyJenningsAxis_p.h"
13 
14 #include <QDateTime>
15 #include <QPainter>
16 
18 #include "KDChartAbstractGrid.h"
19 #include "KDChartChart.h"
20 #include "KDChartLayoutItems.h"
21 #include "KDChartPaintContext.h"
22 #include "KDChartPainterSaver_p.h"
24 
25 #include <KDABLibFakes>
26 
27 #include <limits>
28 
29 using namespace KDChart;
30 
31 #define d (d_func())
32 
34  : CartesianAxis(new Private(diagram, this), diagram)
35 {
36  init();
37 }
38 
40 {
41  // when we remove the first axis it will unregister itself and
42  // propagate the next one to the primary, thus the while loop
43  while (d->mDiagram) {
44  auto *cd = qobject_cast<LeveyJenningsDiagram *>(d->mDiagram);
45  cd->takeAxis(this);
46  }
47  for (AbstractDiagram *diagram : qAsConst(d->secondaryDiagrams)) {
48  auto *cd = qobject_cast<LeveyJenningsDiagram *>(diagram);
49  cd->takeAxis(this);
50  }
51 }
52 
53 void LeveyJenningsAxis::init()
54 {
56  setDateFormat(Qt::TextDate);
57  const QStringList labels = QStringList() << tr("-3sd") << tr("-2sd") << tr("mean")
58  << tr("+2sd") << tr("+3sd");
59 
61 }
62 
67 {
68  return d->type;
69 }
70 
81 {
82  if (type != d->type) {
84  QPen pen = ta.pen();
85  QColor color = type == LeveyJenningsGridAttributes::Expected ? Qt::black : Qt::blue;
86  if (qobject_cast<const LeveyJenningsDiagram *>(d->diagram()) && qobject_cast<const LeveyJenningsCoordinatePlane *>(d->diagram()->coordinatePlane())) {
87  color = qobject_cast<const LeveyJenningsCoordinatePlane *>(d->diagram()->coordinatePlane())->gridAttributes().gridPen(type).color();
88  }
89  pen.setColor(color);
90  ta.setPen(pen);
92  }
93  d->type = type;
94 }
95 
96 Qt::DateFormat LeveyJenningsAxis::dateFormat() const
97 {
98  return d->format;
99 }
100 
101 void LeveyJenningsAxis::setDateFormat(Qt::DateFormat format)
102 {
103  d->format = format;
104 }
105 
107 {
108  if (other == this)
109  return true;
110  if (!other) {
111  // qDebug() << "CartesianAxis::compare() cannot compare to Null pointer";
112  return false;
113  }
114  return (static_cast<const CartesianAxis *>(this)->compare(other)) && (type() == other->type());
115 }
116 
118 {
119  Q_ASSERT_X(d->diagram(), "LeveyJenningsAxis::paint",
120  "Function call not allowed: The axis is not assigned to any diagram.");
121 
122  auto *plane = dynamic_cast<LeveyJenningsCoordinatePlane *>(context->coordinatePlane());
123  Q_ASSERT_X(plane, "LeveyJenningsAxis::paint",
124  "Bad function call: PaintContext::coodinatePlane() NOT a levey jennings plane.");
125  Q_UNUSED(plane);
126  // note: Not having any data model assigned is no bug
127  // but we can not draw an axis then either.
128  if (!d->diagram()->model())
129  return;
130 
131  if (isOrdinate())
132  paintAsOrdinate(context);
133  else
134  paintAsAbscissa(context);
135 }
136 
138 {
139  const auto *const diag = dynamic_cast<const LeveyJenningsDiagram *>(d->diagram());
140 
141  Q_ASSERT(isOrdinate());
142  auto *plane = dynamic_cast<LeveyJenningsCoordinatePlane *>(context->coordinatePlane());
143 
144  const qreal meanValue = type() == LeveyJenningsGridAttributes::Expected ? diag->expectedMeanValue()
145  : diag->calculatedMeanValue();
146  const qreal standardDeviation = type() == LeveyJenningsGridAttributes::Expected ? diag->expectedStandardDeviation()
147  : diag->calculatedStandardDeviation();
148  const TextAttributes labelTA = textAttributes();
149  const bool drawLabels = labelTA.isVisible();
150 
151  // nothing to draw, since we've no ticks
152  if (!drawLabels)
153  return;
154 
155  const QObject *referenceArea = plane->parent();
156 
157  const QVector<qreal> values = QVector<qreal>() << (meanValue - 3 * standardDeviation)
158  << (meanValue - 2 * standardDeviation)
159  << (meanValue)
160  << (meanValue + 2 * standardDeviation)
161  << (meanValue + 3 * standardDeviation);
162 
163  Q_ASSERT_X(values.count() <= labels().count(), "LeveyJenningsAxis::paintAsOrdinate", "Need to have at least 5 labels");
164 
165  TextLayoutItem labelItem(tr("mean"),
166  labelTA,
167  referenceArea,
169  Qt::AlignLeft);
170 
171  QPainter *const painter = context->painter();
172  const PainterSaver ps(painter);
173  painter->setRenderHint(QPainter::Antialiasing, true);
174  painter->setClipping(false);
175 
176  painter->setPen(PrintingParameters::scalePen(labelTA.pen())); // perhaps we want to add a setter method later?
177 
178  for (int i = 0; i < values.count(); ++i) {
179  const QPointF labelPos = plane->translate(QPointF(0.0, values.at(i)));
180  const QString label = customizedLabel(labels().at(i));
181  labelItem.setText(label);
182  const QSize size = labelItem.sizeHint();
183  const float xPos = position() == Left ? geometry().right() - size.width() : geometry().left();
184  labelItem.setGeometry(QRectF(QPointF(xPos, labelPos.y() - size.height() / 2.0), size).toRect());
185 
186  // don't draw labels which aren't in the valid range (might happen for calculated SDs)
187  if (values.at(i) > diag->expectedMeanValue() + 4 * diag->expectedStandardDeviation())
188  continue;
189 
190  if (values.at(i) < diag->expectedMeanValue() - 4 * diag->expectedStandardDeviation())
191  continue;
192 
193  labelItem.paint(painter);
194  }
195 }
196 
198 {
199  Q_ASSERT(isAbscissa());
200 
201  // this triggers drawing of the ticks
202  setLabels(QStringList() << QString::fromLatin1(" "));
203  CartesianAxis::paintCtx(context);
204 
205  const auto *const diag = dynamic_cast<const LeveyJenningsDiagram *>(d->diagram());
206  auto *plane = dynamic_cast<LeveyJenningsCoordinatePlane *>(context->coordinatePlane());
207 
208  const QObject *referenceArea = plane->parent();
209  const TextAttributes labelTA = textAttributes();
210 
211  const bool drawLabels = labelTA.isVisible();
212 
213  if (!drawLabels)
214  return;
215 
216  const QPair<QDateTime, QDateTime> range = diag->timeRange();
217 
218  QPainter *const painter = context->painter();
219  const PainterSaver ps(painter);
220  painter->setRenderHint(QPainter::Antialiasing, true);
221  painter->setClipping(false);
222 
223  TextLayoutItem labelItem(range.first.date().toString(dateFormat()),
224  labelTA,
225  referenceArea,
227  Qt::AlignLeft);
228  QSize origSize = labelItem.sizeHint();
229  if (range.first.secsTo(range.second) < 86400)
230  labelItem = TextLayoutItem(range.first.toString(dateFormat()),
231  labelTA,
232  referenceArea,
234  Qt::AlignLeft);
235  QSize size = labelItem.sizeHint();
236 
237  float yPos = position() == Bottom ? geometry().bottom() - size.height() : geometry().top();
238  labelItem.setGeometry(QRectF(QPointF(geometry().left() - origSize.width() / 2.0, yPos), size).toRect());
239  labelItem.paint(painter);
240 
241  TextLayoutItem labelItem2(range.second.date().toString(dateFormat()),
242  labelTA,
243  referenceArea,
245  Qt::AlignLeft);
246  origSize = labelItem2.sizeHint();
247  if (range.first.secsTo(range.second) < 86400)
248  labelItem2 = TextLayoutItem(range.second.toString(dateFormat()),
249  labelTA,
250  referenceArea,
252  Qt::AlignLeft);
253  size = labelItem2.sizeHint();
254  yPos = position() == Bottom ? geometry().bottom() - size.height() : geometry().top();
255  labelItem2.setGeometry(QRectF(QPointF(geometry().right() - size.width() + origSize.width() / 2.0, yPos), size).toRect());
256  labelItem2.paint(painter);
257 }
@ MeasureOrientationMinimum
Definition: KDChartEnums.h:290
virtual const QString customizedLabel(const QString &label) const
Reimplement this method if you want to adjust axis labels before they are printed.
const AbstractDiagram * diagram() const
void setLabels(const QStringList &list)
Use this to specify your own set of strings, to be used as axis labels.
QStringList labels() const
void setTextAttributes(const TextAttributes &a)
Use this to specify the text attributes to be used for axis labels.
TextAttributes textAttributes() const
Returns the text attributes to be used for axis labels.
AbstractDiagram defines the interface for diagram classes.
virtual bool isOrdinate() const
void paintCtx(PaintContext *) override
virtual bool isAbscissa() const
virtual Position position() const
QRect geometry() const override
void setDateFormat(Qt::DateFormat format)
void paintCtx(PaintContext *) override
LeveyJenningsGridAttributes::GridType type() const
void setType(LeveyJenningsGridAttributes::GridType type)
virtual void paintAsAbscissa(PaintContext *)
bool compare(const LeveyJenningsAxis *other) const
LeveyJenningsAxis(LeveyJenningsDiagram *diagram=nullptr)
virtual void paintAsOrdinate(PaintContext *)
Levey Jennings coordinate plane This is actually nothing real more than a plain cartesian coordinate ...
LeveyDiagram defines a Levey Jennings chart.
Stores information about painting diagrams.
AbstractCoordinatePlane * coordinatePlane() const
QPainter * painter() const
static QPen scalePen(const QPen &pen)
A set of text attributes.
void setPen(const QPen &pen)
QSize sizeHint() const override
void paint(QPainter *) override
void setText(const QString &text)
void setGeometry(const QRect &r) override

© 2001 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-chart/
Generated by doxygen 1.9.1