KChart

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

KDE's Doxygen guidelines are available online.