KChart

KChartLeveyJenningsAxis.cpp
1 /*
2  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "KChartLeveyJenningsAxis.h"
21 #include "KChartLeveyJenningsAxis_p.h"
22 
23 #include <QDateTime>
24 #include <QPainter>
25 
26 #include "KChartPaintContext.h"
27 #include "KChartChart.h"
28 #include "KChartAbstractCartesianDiagram.h"
29 #include "KChartAbstractGrid.h"
30 #include "KChartPainterSaver_p.h"
31 #include "KChartLayoutItems.h"
32 #include "KChartPrintingParameters.h"
33 #include "KChartMath_p.h"
34 
35 using namespace KChart;
36 
37 #define d (d_func())
38 
40  : CartesianAxis ( new Private( diagram, this ), diagram )
41 {
42  init();
43 }
44 
45 LeveyJenningsAxis::~LeveyJenningsAxis ()
46 {
47  // when we remove the first axis it will unregister itself and
48  // propagate the next one to the primary, thus the while loop
49  while ( d->mDiagram ) {
51  cd->takeAxis( this );
52  }
53  for ( AbstractDiagram *diagram : qAsConst(d->secondaryDiagrams) ) {
55  cd->takeAxis( this );
56  }
57 }
58 
59 void LeveyJenningsAxis::init ()
60 {
61  setType( LeveyJenningsGridAttributes::Expected );
62  setDateFormat( Qt::TextDate );
63  const QStringList labels = QStringList() << tr( "-3sd" ) << tr( "-2sd" ) << tr( "mean" )
64  << tr( "+2sd" ) << tr( "+3sd" );
65 
66  setLabels( labels );
67 }
68 
69 LeveyJenningsGridAttributes::GridType LeveyJenningsAxis::type() const
70 {
71  return d->type;
72 }
73 
74 void LeveyJenningsAxis::setType( LeveyJenningsGridAttributes::GridType type )
75 {
76  if ( type != d->type )
77  {
79  QPen pen = ta.pen();
80  QColor color = type == LeveyJenningsGridAttributes::Expected ? Qt::black : Qt::blue;
81  if ( qobject_cast< const LeveyJenningsDiagram* >( d->diagram() ) &&
82  qobject_cast< const LeveyJenningsCoordinatePlane* >( d->diagram()->coordinatePlane() ) )
83  {
84  color = qobject_cast< const LeveyJenningsCoordinatePlane* >( d->diagram()->coordinatePlane() )->gridAttributes().gridPen( type ).color();
85  }
86  pen.setColor( color );
87  ta.setPen( pen );
88  setTextAttributes( ta );
89  }
90  d->type = type;
91 }
92 
93 Qt::DateFormat LeveyJenningsAxis::dateFormat() const
94 {
95  return d->format;
96 }
97 
98 void LeveyJenningsAxis::setDateFormat(Qt::DateFormat format)
99 {
100  d->format = format;
101 }
102 
104 {
105  if ( other == this ) return true;
106  if ( ! other ) {
107  //qDebug() << "CartesianAxis::compare() cannot compare to Null pointer";
108  return false;
109  }
110  return ( static_cast<const CartesianAxis*>(this)->compare( other ) ) &&
111  ( type() == other->type() );
112 }
113 
115 {
116 
117  Q_ASSERT_X ( d->diagram(), "LeveyJenningsAxis::paint",
118  "Function call not allowed: The axis is not assigned to any diagram." );
119 
120  LeveyJenningsCoordinatePlane* plane = dynamic_cast<LeveyJenningsCoordinatePlane*>(context->coordinatePlane());
121  Q_ASSERT_X ( plane, "LeveyJenningsAxis::paint",
122  "Bad function call: PaintContext::coodinatePlane() NOT a levey jennings plane." );
123  Q_UNUSED(plane);
124  // note: Not having any data model assigned is no bug
125  // but we can not draw an axis then either.
126  if ( ! d->diagram()->model() )
127  return;
128 
129  if ( isOrdinate() )
130  paintAsOrdinate( context );
131  else
132  paintAsAbscissa( context );
133 }
134 
135 void LeveyJenningsAxis::paintAsOrdinate( PaintContext* context )
136 {
137  const LeveyJenningsDiagram* const diag = dynamic_cast< const LeveyJenningsDiagram* >( d->diagram() );
138 
139  Q_ASSERT( isOrdinate() );
140  LeveyJenningsCoordinatePlane* plane = dynamic_cast<LeveyJenningsCoordinatePlane*>(context->coordinatePlane());
141 
142  const qreal meanValue = type() == LeveyJenningsGridAttributes::Expected ? diag->expectedMeanValue()
143  : diag->calculatedMeanValue();
144  const qreal standardDeviation = type() == LeveyJenningsGridAttributes::Expected ? diag->expectedStandardDeviation()
145  : diag->calculatedStandardDeviation();
146  const TextAttributes labelTA = textAttributes();
147  const bool drawLabels = labelTA.isVisible();
148 
149  // nothing to draw, since we've no ticks
150  if ( !drawLabels )
151  return;
152 
153  const QObject* referenceArea = plane->parent();
154 
155  const QVector< qreal > values = QVector< qreal >() << ( meanValue - 3 * standardDeviation )
156  << ( meanValue - 2 * standardDeviation )
157  << ( meanValue )
158  << ( meanValue + 2 * standardDeviation )
159  << ( meanValue + 3 * standardDeviation );
160 
161  Q_ASSERT_X( values.count() <= labels().count(), "LeveyJenningsAxis::paintAsOrdinate", "Need to have at least 5 labels" );
162 
163  TextLayoutItem labelItem( tr( "mean" ),
164  labelTA,
165  referenceArea,
166  KChartEnums::MeasureOrientationMinimum,
167  Qt::AlignLeft );
168 
169  QPainter* const painter = context->painter();
170  const PainterSaver ps( painter );
171  painter->setRenderHint( QPainter::Antialiasing, true );
172  painter->setClipping( false );
173 
174  painter->setPen ( PrintingParameters::scalePen( labelTA.pen() ) ); // perhaps we want to add a setter method later?
175 
176  for ( int i = 0; i < values.count(); ++i )
177  {
178  const QPointF labelPos = plane->translate( QPointF( 0.0, values.at( i ) ) );
179  const QString label = customizedLabel( labels().at( i ) );
180  labelItem.setText( label );
181  const QSize size = labelItem.sizeHint();
182  const float xPos = position() == Left ? geometry().right() - size.width() : geometry().left();
183  labelItem.setGeometry( QRectF( QPointF( xPos, labelPos.y() - size.height() / 2.0 ), size ).toRect() );
184 
185  // don't draw labels which aren't in the valid range (might happen for calculated SDs)
186  if ( values.at( i ) > diag->expectedMeanValue() + 4 * diag->expectedStandardDeviation() )
187  continue;
188 
189  if ( values.at( i ) < diag->expectedMeanValue() - 4 * diag->expectedStandardDeviation() )
190  continue;
191 
192  labelItem.paint( painter );
193  }
194 }
195 
196 void LeveyJenningsAxis::paintAsAbscissa( PaintContext* context )
197 {
198  Q_ASSERT( isAbscissa() );
199 
200  // this triggers drawing of the ticks
202  CartesianAxis::paintCtx( context );
203 
204  const LeveyJenningsDiagram* const diag = dynamic_cast< const LeveyJenningsDiagram* >( d->diagram() );
205  LeveyJenningsCoordinatePlane* plane = dynamic_cast<LeveyJenningsCoordinatePlane*>(context->coordinatePlane());
206 
207  const QObject* referenceArea = plane->parent();
208  const TextAttributes labelTA = textAttributes();
209 
210  const bool drawLabels = labelTA.isVisible();
211 
212  if ( !drawLabels )
213  return;
214 
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 
224  TextLayoutItem labelItem( range.first.date().toString( dateFormat() ),
225  labelTA,
226  referenceArea,
227  KChartEnums::MeasureOrientationMinimum,
228  Qt::AlignLeft );
229  QSize origSize = labelItem.sizeHint();
230  if ( range.first.secsTo( range.second ) < 86400 )
231  labelItem = TextLayoutItem( range.first.toString( dateFormat() ),
232  labelTA,
233  referenceArea,
234  KChartEnums::MeasureOrientationMinimum,
235  Qt::AlignLeft );
236  QSize size = labelItem.sizeHint();
237 
238  float yPos = position() == Bottom ? geometry().bottom() - size.height() : geometry().top();
239  labelItem.setGeometry( QRectF( QPointF( geometry().left() - origSize.width() / 2.0, yPos ), size ).toRect() );
240  labelItem.paint( painter );
241 
242 
243  TextLayoutItem labelItem2( range.second.date().toString( dateFormat() ),
244  labelTA,
245  referenceArea,
246  KChartEnums::MeasureOrientationMinimum,
247  Qt::AlignLeft );
248  origSize = labelItem2.sizeHint();
249  if ( range.first.secsTo( range.second ) < 86400 )
250  labelItem2 = TextLayoutItem( range.second.toString( dateFormat() ),
251  labelTA,
252  referenceArea,
253  KChartEnums::MeasureOrientationMinimum,
254  Qt::AlignLeft );
255  size = labelItem2.sizeHint();
256  yPos = position() == Bottom ? geometry().bottom() - size.height() : geometry().top();
257  labelItem2.setGeometry( QRectF( QPointF( geometry().right() - size.width() + origSize.width() / 2.0, yPos ), size ).toRect() );
258  labelItem2.paint( painter );
259 }
void paintCtx(PaintContext *) override
reimpl
The class for levey jennings axes.
int width() const const
QRect toRect() const const
Levey Jennings coordinate plane This is actually nothing real more than a plain cartesian coordinate ...
AbstractDiagram defines the interface for diagram classes.
void setRenderHint(QPainter::RenderHint hint, bool on)
void setLabels(const QStringList &list)
Use this to specify your own set of strings, to be used as axis labels.
int right() const const
TextDate
bool compare(const LeveyJenningsAxis *other) const
Returns true if both axes have the same settings.
LeveyDiagram defines a Levey Jennings chart.
void setTextAttributes(const TextAttributes &a)
Use this to specify the text attributes to be used for axis labels.
void setClipping(bool enable)
void setPen(const QPen &pen)
Set the pen to use for rendering the text.
QSize sizeHint() const override
pure virtual in QLayoutItem
QString tr(const char *sourceText, const char *disambiguation, int n)
The class for cartesian axes.
AlignLeft
QVector< V > values(const QMultiHash< K, V > &c)
int count(const T &value) const const
qreal y() const const
Stores information about painting diagrams.
int top() const const
Class only listed here to document inheritance of some KChart classes.
void setPen(const QColor &color)
int left() const const
float calculatedMeanValue() const
Returns the calculated mean values over all QC values.
QPair< QDateTime, QDateTime > timeRange() const
Returns the timerange of the diagram&#39;s data.
void setColor(const QColor &color)
virtual const QString customizedLabel(const QString &label) const
Reimplement this method if you want to adjust axis labels before they are printed.
void paintCtx(PaintContext *) override
reimpl
Layout item showing a text.
LeveyJenningsAxis(LeveyJenningsDiagram *diagram=nullptr)
C&#39;tor of the class for levey jennings axes.
QRect geometry() const override
pure virtual in QLayoutItem
const QPointF translate(const QPointF &diagramPoint) const override
Translate the given point in value space coordinates to a position in pixel space.
QStringList labels() const
Returns a list of strings, that are used as axis labels, as set via setLabels.
QCA_EXPORT void init()
const T & at(int i) const const
virtual void takeAxis(CartesianAxis *axis)
Removes the axis from the diagram, without deleting it.
int height() const const
int count(const T &value) const const
int bottom() const const
A set of text attributes.
float calculatedStandardDeviation() const
Returns the calculated standard deviation over all QC values.
QString fromLatin1(const char *str, int size)
float expectedStandardDeviation() const
Returns the expected standard deviation over all QC values.
void setType(LeveyJenningsGridAttributes::GridType type)
Sets the type of the axis to type.
LeveyJenningsGridAttributes::GridType type() const
Global namespace.
T qobject_cast(QObject *object)
float expectedMeanValue() const
Returns the expected mean values over all QC values.
TextAttributes textAttributes() const
Returns the text attributes to be used for axis labels.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Sep 19 2020 22:36:26 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.