KD Chart 2  [rev.2.7]
KDChartLeveyJenningsAxis.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2020 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
24 #include "KDChartLeveyJenningsAxis_p.h"
25 
26 #include <QDateTime>
27 #include <QPainter>
28 
29 #include "KDChartPaintContext.h"
30 #include "KDChartChart.h"
32 #include "KDChartAbstractGrid.h"
33 #include "KDChartPainterSaver_p.h"
34 #include "KDChartLayoutItems.h"
36 
37 #include <KDABLibFakes>
38 
39 #include <limits>
40 
41 using namespace KDChart;
42 
43 #define d (d_func())
44 
46  : CartesianAxis ( new Private( diagram, this ), diagram )
47 {
48  init();
49 }
50 
52 {
53  // when we remove the first axis it will unregister itself and
54  // propagate the next one to the primary, thus the while loop
55  while ( d->mDiagram ) {
56  LeveyJenningsDiagram *cd = qobject_cast< LeveyJenningsDiagram* >( d->mDiagram );
57  cd->takeAxis( this );
58  }
59  Q_FOREACH( AbstractDiagram *diagram, d->secondaryDiagrams ) {
60  LeveyJenningsDiagram *cd = qobject_cast< LeveyJenningsDiagram* >( diagram );
61  cd->takeAxis( this );
62  }
63 }
64 
65 void LeveyJenningsAxis::init ()
66 {
68  setDateFormat( Qt::TextDate );
69  const QStringList labels = QStringList() << tr( "-3sd" ) << tr( "-2sd" ) << tr( "mean" )
70  << tr( "+2sd" ) << tr( "+3sd" );
71 
72  setLabels( labels );
73 }
74 
79 {
80  return d->type;
81 }
82 
93 {
94  if ( type != d->type )
95  {
97  QPen pen = ta.pen();
98  QColor color = type == LeveyJenningsGridAttributes::Expected ? Qt::black : Qt::blue;
99  if ( qobject_cast< const LeveyJenningsDiagram* >( d->diagram() ) &&
100  qobject_cast< const LeveyJenningsCoordinatePlane* >( d->diagram()->coordinatePlane() ) )
101  {
102  color = qobject_cast< const LeveyJenningsCoordinatePlane* >( d->diagram()->coordinatePlane() )->gridAttributes().gridPen( type ).color();
103  }
104  pen.setColor( color );
105  ta.setPen( pen );
106  setTextAttributes( ta );
107  }
108  d->type = type;
109 }
110 
111 Qt::DateFormat LeveyJenningsAxis::dateFormat() const
112 {
113  return d->format;
114 }
115 
116 void LeveyJenningsAxis::setDateFormat(Qt::DateFormat format)
117 {
118  d->format = format;
119 }
120 
122 {
123  if ( other == this ) return true;
124  if ( ! other ) {
125  //qDebug() << "CartesianAxis::compare() cannot compare to Null pointer";
126  return false;
127  }
128  return ( static_cast<const CartesianAxis*>(this)->compare( other ) ) &&
129  ( type() == other->type() );
130 }
131 
133 {
134 
135  Q_ASSERT_X ( d->diagram(), "LeveyJenningsAxis::paint",
136  "Function call not allowed: The axis is not assigned to any diagram." );
137 
139  Q_ASSERT_X ( plane, "LeveyJenningsAxis::paint",
140  "Bad function call: PaintContext::coodinatePlane() NOT a levey jennings plane." );
141  Q_UNUSED(plane);
142  // note: Not having any data model assigned is no bug
143  // but we can not draw an axis then either.
144  if ( ! d->diagram()->model() )
145  return;
146 
147  if ( isOrdinate() )
148  paintAsOrdinate( context );
149  else
150  paintAsAbscissa( context );
151 }
152 
154 {
155  const LeveyJenningsDiagram* const diag = dynamic_cast< const LeveyJenningsDiagram* >( d->diagram() );
156 
157  Q_ASSERT( isOrdinate() );
159 
160  const qreal meanValue = type() == LeveyJenningsGridAttributes::Expected ? diag->expectedMeanValue()
161  : diag->calculatedMeanValue();
162  const qreal standardDeviation = type() == LeveyJenningsGridAttributes::Expected ? diag->expectedStandardDeviation()
163  : diag->calculatedStandardDeviation();
164  const TextAttributes labelTA = textAttributes();
165  const bool drawLabels = labelTA.isVisible();
166 
167  // nothing to draw, since we've no ticks
168  if ( !drawLabels )
169  return;
170 
171  const QObject* referenceArea = plane->parent();
172 
173  const QVector< qreal > values = QVector< qreal >() << ( meanValue - 3 * standardDeviation )
174  << ( meanValue - 2 * standardDeviation )
175  << ( meanValue )
176  << ( meanValue + 2 * standardDeviation )
177  << ( meanValue + 3 * standardDeviation );
178 
179  Q_ASSERT_X( values.count() <= labels().count(), "LeveyJenningsAxis::paintAsOrdinate", "Need to have at least 5 labels" );
180 
181  TextLayoutItem labelItem( tr( "mean" ),
182  labelTA,
183  referenceArea,
185  Qt::AlignLeft );
186 
187  QPainter* const painter = context->painter();
188  const PainterSaver ps( painter );
189  painter->setRenderHint( QPainter::Antialiasing, true );
190  painter->setClipping( false );
191 
192  painter->setPen ( PrintingParameters::scalePen( labelTA.pen() ) ); // perhaps we want to add a setter method later?
193 
194  for ( int i = 0; i < values.count(); ++i )
195  {
196  const QPointF labelPos = plane->translate( QPointF( 0.0, values.at( i ) ) );
197  const QString label = customizedLabel( labels().at( i ) );
198  labelItem.setText( label );
199  const QSize size = labelItem.sizeHint();
200  const float xPos = position() == Left ? geometry().right() - size.width() : geometry().left();
201  labelItem.setGeometry( QRectF( QPointF( xPos, labelPos.y() - size.height() / 2.0 ), size ).toRect() );
202 
203  // don't draw labels which aren't in the valid range (might happen for calculated SDs)
204  if ( values.at( i ) > diag->expectedMeanValue() + 4 * diag->expectedStandardDeviation() )
205  continue;
206 
207  if ( values.at( i ) < diag->expectedMeanValue() - 4 * diag->expectedStandardDeviation() )
208  continue;
209 
210  labelItem.paint( painter );
211  }
212 }
213 
215 {
216  Q_ASSERT( isAbscissa() );
217 
218  // this triggers drawing of the ticks
219  setLabels( QStringList() << QString::fromLatin1( " " ) );
220  CartesianAxis::paintCtx( context );
221 
222  const LeveyJenningsDiagram* const diag = dynamic_cast< const LeveyJenningsDiagram* >( d->diagram() );
224 
225  const QObject* referenceArea = plane->parent();
226  const TextAttributes labelTA = textAttributes();
227 
228  const bool drawLabels = labelTA.isVisible();
229 
230  if ( !drawLabels )
231  return;
232 
233 
234  const QPair< QDateTime, QDateTime > range = diag->timeRange();
235 
236  QPainter* const painter = context->painter();
237  const PainterSaver ps( painter );
238  painter->setRenderHint( QPainter::Antialiasing, true );
239  painter->setClipping( false );
240 
241 
242  TextLayoutItem labelItem( range.first.date().toString( dateFormat() ),
243  labelTA,
244  referenceArea,
246  Qt::AlignLeft );
247  QSize origSize = labelItem.sizeHint();
248  if ( range.first.secsTo( range.second ) < 86400 )
249  labelItem = TextLayoutItem( range.first.toString( dateFormat() ),
250  labelTA,
251  referenceArea,
253  Qt::AlignLeft );
254  QSize size = labelItem.sizeHint();
255 
256  float yPos = position() == Bottom ? geometry().bottom() - size.height() : geometry().top();
257  labelItem.setGeometry( QRectF( QPointF( geometry().left() - origSize.width() / 2.0, yPos ), size ).toRect() );
258  labelItem.paint( painter );
259 
260 
261  TextLayoutItem labelItem2( range.second.date().toString( dateFormat() ),
262  labelTA,
263  referenceArea,
265  Qt::AlignLeft );
266  origSize = labelItem2.sizeHint();
267  if ( range.first.secsTo( range.second ) < 86400 )
268  labelItem2 = TextLayoutItem( range.second.toString( dateFormat() ),
269  labelTA,
270  referenceArea,
272  Qt::AlignLeft );
273  size = labelItem2.sizeHint();
274  yPos = position() == Bottom ? geometry().bottom() - size.height() : geometry().top();
275  labelItem2.setGeometry( QRectF( QPointF( geometry().right() - size.width() + origSize.width() / 2.0, yPos ), size ).toRect() );
276  labelItem2.paint( painter );
277 }
QPair< QDateTime, QDateTime > timeRange() const
Returns the timerange of the diagram&#39;s data.
virtual void paintAsOrdinate(PaintContext *)
void paintCtx(PaintContext *) override
reimpl
void setLabels(const QStringList &list)
Use this to specify your own set of strings, to be used as axis labels.
void setType(LeveyJenningsGridAttributes::GridType type)
Sets the type of the axis to type.
AbstractCoordinatePlane * coordinatePlane() const
void setPen(const QPen &pen)
Set the pen to use for rendering the text.
const QPointF translate(const QPointF &diagramPoint) const override
Translate the given point in value space coordinates to a position in pixel space.
QPainter * painter() const
Layout item showing a text.
void setDateFormat(Qt::DateFormat format)
Levey Jennings coordinate plane This is actually nothing real more than a plain cartesian coordinate ...
QSize sizeHint() const override
pure virtual in QLayoutItem
AbstractDiagram defines the interface for diagram classes.
QStringList labels() const
Returns a list of strings, that are used as axis labels, as set via setLabels.
const AbstractDiagram * diagram() const
LeveyDiagram defines a Levey Jennings chart.
void paintCtx(PaintContext *) override
reimpl
The class for cartesian axes.
void setTextAttributes(const TextAttributes &a)
Use this to specify the text attributes to be used for axis labels.
bool compare(const LeveyJenningsAxis *other) const
Returns true if both axes have the same settings.
TextAttributes textAttributes() const
Returns the text attributes to be used for axis labels.
float calculatedStandardDeviation() const
Returns the calculated standard deviation over all QC values.
virtual bool isOrdinate() const
float expectedStandardDeviation() const
Returns the expected standard deviation over all QC values.
virtual bool isAbscissa() const
LeveyJenningsGridAttributes::GridType type() const
Stores information about painting diagrams.
virtual const Position position() const
QRect geometry() const override
pure virtual in QLayoutItem
LeveyJenningsAxis(LeveyJenningsDiagram *diagram=0)
C&#39;tor of the class for levey jennings axes.
Class only listed here to document inheritance of some KDChart classes.
static QPen scalePen(const QPen &pen)
virtual const QString customizedLabel(const QString &label) const
Reimplement this method if you want to adjust axis labels before they are printed.
virtual void paintAsAbscissa(PaintContext *)
The class for levey jennings axes.
virtual void takeAxis(CartesianAxis *axis)
Removes the axis from the diagram, without deleting it.
float expectedMeanValue() const
Returns the expected mean values over all QC values.
float calculatedMeanValue() const
Returns the calculated mean values over all QC values.
A set of text attributes.

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/