qwt_plot_multi_barchart.cpp
Go to the documentation of this file.
1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
11 #include "qwt_scale_map.h"
12 #include "qwt_column_symbol.h"
13 #include "qwt_painter.h"
14 #include <qpainter.h>
15 #include <qpalette.h>
16 #include <qmap.h>
17 
18 inline static bool qwtIsIncreasing(
19  const QwtScaleMap &map, const QVector<double> &values )
20 {
21  bool isInverting = map.isInverting();
22 
23  for ( int i = 0; i < values.size(); i++ )
24  {
25  const double y = values[ i ];
26  if ( y != 0.0 )
27  return ( map.isInverting() != ( y > 0.0 ) );
28  }
29 
30  return !isInverting;
31 }
32 
34 {
35 public:
38  {
39  }
40 
42  QList<QwtText> barTitles;
43  QMap<int, QwtColumnSymbol *> symbolMap;
44 };
45 
52 {
53  init();
54 }
55 
62 {
63  init();
64 }
65 
68 {
70  delete d_data;
71 }
72 
74 {
75  d_data = new PrivateData;
76  setData( new QwtSetSeriesData() );
77 }
78 
81 {
83 }
84 
90  const QVector<QwtSetSample> &samples )
91 {
92  setData( new QwtSetSeriesData( samples ) );
93 }
94 
100  const QVector< QVector<double> > &samples )
101 {
102  QVector<QwtSetSample> s;
103  s.reserve( samples.size() );
104 
105  for ( int i = 0; i < samples.size(); i++ )
106  s += QwtSetSample( i, samples[ i ] );
107 
108  setData( new QwtSetSeriesData( s ) );
109 }
110 
123 {
124  setData( data );
125 }
126 
136 void QwtPlotMultiBarChart::setBarTitles( const QList<QwtText> &titles )
137 {
138  d_data->barTitles = titles;
139  itemChanged();
140 }
141 
146 QList<QwtText> QwtPlotMultiBarChart::barTitles() const
147 {
148  return d_data->barTitles;
149 }
150 
163 {
164  if ( valueIndex < 0 )
165  return;
166 
167  QMap<int, QwtColumnSymbol *>::iterator it =
168  d_data->symbolMap.find(valueIndex);
169  if ( it == d_data->symbolMap.end() )
170  {
171  if ( symbol != NULL )
172  {
173  d_data->symbolMap.insert( valueIndex, symbol );
174 
175  legendChanged();
176  itemChanged();
177  }
178  }
179  else
180  {
181  if ( symbol != it.value() )
182  {
183  delete it.value();
184 
185  if ( symbol == NULL )
186  {
187  d_data->symbolMap.remove( valueIndex );
188  }
189  else
190  {
191  it.value() = symbol;
192  }
193 
194  legendChanged();
195  itemChanged();
196  }
197  }
198 }
199 
208 const QwtColumnSymbol *QwtPlotMultiBarChart::symbol( int valueIndex ) const
209 {
210  QMap<int, QwtColumnSymbol *>::const_iterator it =
211  d_data->symbolMap.constFind( valueIndex );
212 
213  return ( it == d_data->symbolMap.constEnd() ) ? NULL : it.value();
214 }
215 
225 {
226  QMap<int, QwtColumnSymbol *>::const_iterator it =
227  d_data->symbolMap.constFind( valueIndex );
228 
229  return ( it == d_data->symbolMap.constEnd() ) ? NULL : it.value();
230 }
231 
236 {
237  qDeleteAll( d_data->symbolMap );
238  d_data->symbolMap.clear();
239 }
240 
262  int sampleIndex, int valueIndex ) const
263 {
264  Q_UNUSED( sampleIndex );
265  Q_UNUSED( valueIndex );
266 
267  return NULL;
268 }
269 
277 {
278  if ( style != d_data->style )
279  {
280  d_data->style = style;
281 
282  legendChanged();
283  itemChanged();
284  }
285 }
286 
292 {
293  return d_data->style;
294 }
295 
301 {
302  const size_t numSamples = dataSize();
303 
304  if ( numSamples == 0 )
306 
307  const double baseLine = baseline();
308 
309  QRectF rect;
310 
312  {
314 
315  if ( rect.height() >= 0 )
316  {
317  if ( rect.bottom() < baseLine )
318  rect.setBottom( baseLine );
319  if ( rect.top() > baseLine )
320  rect.setTop( baseLine );
321  }
322  }
323  else
324  {
325  double xMin, xMax, yMin, yMax;
326 
327  xMin = xMax = 0.0;
328  yMin = yMax = baseLine;
329 
330  const QwtSeriesData<QwtSetSample> *series = data();
331 
332  for ( size_t i = 0; i < numSamples; i++ )
333  {
334  const QwtSetSample sample = series->sample( i );
335  if ( i == 0 )
336  {
337  xMin = xMax = sample.value;
338  }
339  else
340  {
341  xMin = qMin( xMin, sample.value );
342  xMax = qMax( xMax, sample.value );
343  }
344 
345  const double y = baseLine + sample.added();
346 
347  yMin = qMin( yMin, y );
348  yMax = qMax( yMax, y );
349  }
350  rect.setRect( xMin, yMin, xMax - xMin, yMax - yMin );
351  }
352 
353  if ( orientation() == Qt::Horizontal )
354  rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
355 
356  return rect;
357 }
358 
372 void QwtPlotMultiBarChart::drawSeries( QPainter *painter,
373  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
374  const QRectF &canvasRect, int from, int to ) const
375 {
376  if ( to < 0 )
377  to = dataSize() - 1;
378 
379  if ( from < 0 )
380  from = 0;
381 
382  if ( from > to )
383  return;
384 
385 
386  const QRectF br = data()->boundingRect();
387  const QwtInterval interval( br.left(), br.right() );
388 
389  painter->save();
390 
391  for ( int i = from; i <= to; i++ )
392  {
393  drawSample( painter, xMap, yMap,
394  canvasRect, interval, i, sample( i ) );
395  }
396 
397  painter->restore();
398 }
399 
413 void QwtPlotMultiBarChart::drawSample( QPainter *painter,
414  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
415  const QRectF &canvasRect, const QwtInterval &boundingInterval,
416  int index, const QwtSetSample& sample ) const
417 {
418  if ( sample.set.size() <= 0 )
419  return;
420 
421  double sampleW;
422 
423  if ( orientation() == Qt::Horizontal )
424  {
425  sampleW = sampleWidth( yMap, canvasRect.height(),
426  boundingInterval.width(), sample.value );
427  }
428  else
429  {
430  sampleW = sampleWidth( xMap, canvasRect.width(),
431  boundingInterval.width(), sample.value );
432  }
433 
434  if ( d_data->style == Stacked )
435  {
436  drawStackedBars( painter, xMap, yMap,
437  canvasRect, index, sampleW, sample );
438  }
439  else
440  {
441  drawGroupedBars( painter, xMap, yMap,
442  canvasRect, index, sampleW, sample );
443  }
444 }
445 
460  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
461  const QRectF &canvasRect, int index, double sampleWidth,
462  const QwtSetSample& sample ) const
463 {
464  Q_UNUSED( canvasRect );
465 
466  const int numBars = sample.set.size();
467  if ( numBars == 0 )
468  return;
469 
470  if ( orientation() == Qt::Vertical )
471  {
472  const double barWidth = sampleWidth / numBars;
473 
474  const double y1 = yMap.transform( baseline() );
475  const double x0 = xMap.transform( sample.value ) - 0.5 * sampleWidth;
476 
477  for ( int i = 0; i < numBars; i++ )
478  {
479  const double x1 = x0 + i * barWidth;
480  const double x2 = x1 + barWidth;
481 
482  const double y2 = yMap.transform( sample.set[i] );
483 
484  QwtColumnRect barRect;
485  barRect.direction = ( y1 < y2 ) ?
487 
488  barRect.hInterval = QwtInterval( x1, x2 ).normalized();
489  if ( i != 0 )
491 
492  barRect.vInterval = QwtInterval( y1, y2 ).normalized();
493 
494  drawBar( painter, index, i, barRect );
495  }
496  }
497  else
498  {
499  const double barHeight = sampleWidth / numBars;
500 
501  const double x1 = xMap.transform( baseline() );
502  const double y0 = yMap.transform( sample.value ) - 0.5 * sampleWidth;
503 
504  for ( int i = 0; i < numBars; i++ )
505  {
506  double y1 = y0 + i * barHeight;
507  double y2 = y1 + barHeight;
508 
509  double x2 = xMap.transform( sample.set[i] );
510 
511  QwtColumnRect barRect;
512  barRect.direction = x1 < x2 ?
514 
515  barRect.hInterval = QwtInterval( x1, x2 ).normalized();
516 
517  barRect.vInterval = QwtInterval( y1, y2 );
518  if ( i != 0 )
520 
521  drawBar( painter, index, i, barRect );
522  }
523  }
524 }
525 
540  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
541  const QRectF &canvasRect, int index,
542  double sampleWidth, const QwtSetSample& sample ) const
543 {
544  Q_UNUSED( canvasRect ); // clipping the bars ?
545 
546  const int numBars = sample.set.size();
547  if ( numBars == 0 )
548  return;
549 
551 
552  if ( orientation() == Qt::Vertical )
553  {
554  const double x1 = xMap.transform( sample.value ) - 0.5 * sampleWidth;
555  const double x2 = x1 + sampleWidth;
556 
557  const bool increasing = qwtIsIncreasing( yMap, sample.set );
558 
559  QwtColumnRect bar;
560  bar.direction = increasing ?
562 
563  bar.hInterval = QwtInterval( x1, x2 ).normalized();
564 
565  double sum = baseline();
566 
567  const int numBars = sample.set.size();
568  for ( int i = 0; i < numBars; i++ )
569  {
570  const double si = sample.set[ i ];
571  if ( si == 0.0 )
572  continue;
573 
574  const double y1 = yMap.transform( sum );
575  const double y2 = yMap.transform( sum + si );
576 
577  if ( ( y2 > y1 ) != increasing )
578  {
579  // stacked bars need to be in the same direction
580  continue;
581  }
582 
583  bar.vInterval = QwtInterval( y1, y2 ).normalized();
584  bar.vInterval.setBorderFlags( borderFlags );
585 
586  drawBar( painter, index, i, bar );
587 
588  sum += si;
589 
590  if ( increasing )
591  borderFlags = QwtInterval::ExcludeMinimum;
592  else
593  borderFlags = QwtInterval::ExcludeMaximum;
594  }
595  }
596  else
597  {
598  const double y1 = yMap.transform( sample.value ) - 0.5 * sampleWidth;
599  const double y2 = y1 + sampleWidth;
600 
601  const bool increasing = qwtIsIncreasing( xMap, sample.set );
602 
603  QwtColumnRect bar;
604  bar.direction = increasing ?
606  bar.vInterval = QwtInterval( y1, y2 ).normalized();
607 
608  double sum = baseline();
609 
610  for ( int i = 0; i < sample.set.size(); i++ )
611  {
612  const double si = sample.set[ i ];
613  if ( si == 0.0 )
614  continue;
615 
616  const double x1 = xMap.transform( sum );
617  const double x2 = xMap.transform( sum + si );
618 
619  if ( ( x2 > x1 ) != increasing )
620  {
621  // stacked bars need to be in the same direction
622  continue;
623  }
624 
625  bar.hInterval = QwtInterval( x1, x2 ).normalized();
626  bar.hInterval.setBorderFlags( borderFlags );
627 
628  drawBar( painter, index, i, bar );
629 
630  sum += si;
631 
632  if ( increasing )
633  borderFlags = QwtInterval::ExcludeMinimum;
634  else
635  borderFlags = QwtInterval::ExcludeMaximum;
636  }
637  }
638 }
639 
651 void QwtPlotMultiBarChart::drawBar( QPainter *painter,
652  int sampleIndex, int valueIndex, const QwtColumnRect &rect ) const
653 {
654  const QwtColumnSymbol *specialSym = NULL;
655  if ( sampleIndex >= 0 )
656  specialSym = specialSymbol( sampleIndex, valueIndex );
657 
658  const QwtColumnSymbol *sym = specialSym;
659  if ( sym == NULL )
660  sym = symbol( valueIndex );
661 
662  if ( sym )
663  {
664  sym->draw( painter, rect );
665  }
666  else
667  {
668  // we build a temporary default symbol
670  sym.setLineWidth( 1 );
672  sym.draw( painter, rect );
673  }
674 
675  delete specialSym;
676 }
677 
686 QList<QwtLegendData> QwtPlotMultiBarChart::legendData() const
687 {
688  QList<QwtLegendData> list;
689 #if QT_VERSION >= 0x040700
690  list.reserve( d_data->barTitles.size() );
691 #endif
692 
693  for ( int i = 0; i < d_data->barTitles.size(); i++ )
694  {
696 
697  QVariant titleValue;
698  qVariantSetValue( titleValue, d_data->barTitles[i] );
699  data.setValue( QwtLegendData::TitleRole, titleValue );
700 
701  if ( !legendIconSize().isEmpty() )
702  {
703  QVariant iconValue;
704  qVariantSetValue( iconValue,
705  legendIcon( i, legendIconSize() ) );
706 
707  data.setValue( QwtLegendData::IconRole, iconValue );
708  }
709 
710  list += data;
711  }
712 
713  return list;
714 }
715 
726  const QSizeF &size ) const
727 {
728  QwtColumnRect column;
729  column.hInterval = QwtInterval( 0.0, size.width() - 1.0 );
730  column.vInterval = QwtInterval( 0.0, size.height() - 1.0 );
731 
732  QwtGraphic icon;
733  icon.setDefaultSize( size );
734  icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
735 
736  QPainter painter( &icon );
737  painter.setRenderHint( QPainter::Antialiasing,
739 
740  drawBar( &painter, -1, index, column );
741 
742  return icon;
743 }
744 
virtual void legendChanged()
QMap< int, QwtColumnSymbol * > symbolMap
virtual size_t dataSize() const
Qt::Orientation orientation() const
QwtInterval vInterval
Interval for the vertical coordinates.
QwtInterval normalized() const
Normalize the limits of the interval.
Enable antialiasing.
A plain frame style.
double value
value
Definition: qwt_samples.h:88
Interface for iterating over an array of samples.
virtual QRectF boundingRect() const =0
From top to bottom.
A class representing an interval.
Definition: qwt_interval.h:26
Max value is not included in the interval.
Definition: qwt_interval.h:42
From left to right.
A drawing primitive for columns.
XmlRpcServer s
For QwtPlotMultiBarChart.
virtual QList< QwtLegendData > legendData() const
void setData(QwtSeriesData< QwtSetSample > *series)
QwtPlotMultiBarChart displays a series of a samples that consist each of a set of values...
Direction direction
Direction.
static bool qwtIsIncreasing(const QwtScaleMap &map, const QVector< double > &values)
virtual void drawBar(QPainter *, int sampleIndex, int barIndex, const QwtColumnRect &) const
Abstract base class for bar chart items.
QwtSeriesData< QwtSetSample > * data()
TFSIMD_FORCE_INLINE const tfScalar & y() const
void setStyle(ChartStyle style)
void setBarTitles(const QList< QwtText > &)
Set the titles for the bars.
void setSamples(const QVector< QwtSetSample > &)
virtual QwtGraphic legendIcon(int index, const QSizeF &) const
QSize legendIconSize() const
A sample of the types (x1...xn, y) or (x, y1..yn)
Definition: qwt_samples.h:76
void setDefaultSize(const QSizeF &)
Set a default size.
virtual void drawSeries(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to) const
QList< QwtText > barTitles() const
double added() const
Definition: qwt_samples.h:128
bool testRenderHint(RenderHint) const
QwtPlotMultiBarChart::ChartStyle style
virtual void drawSample(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, const QwtInterval &boundingInterval, int index, const QwtSetSample &sample) const
virtual QwtColumnSymbol * specialSymbol(int sampleIndex, int valueIndex) const
Create a symbol for special values.
void setFrameStyle(FrameStyle style)
A class representing a text.
Definition: qwt_text.h:51
virtual QRectF boundingRect() const
Min value is not included in the interval.
Definition: qwt_interval.h:39
const QwtColumnSymbol * symbol(int barIndex) const
A paint device for scalable graphics.
Definition: qwt_graphic.h:74
From bottom to top.
virtual QRectF boundingRect() const
void setBorderFlags(BorderFlags)
Definition: qwt_interval.h:158
void setLineWidth(int width)
A scale map.
Definition: qwt_scale_map.h:30
QwtSetSample sample(int index) const
virtual void itemChanged()
virtual ~QwtPlotMultiBarChart()
Destructor.
QwtPlotMultiBarChart(const QString &title=QString())
void drawGroupedBars(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int index, double sampleWidth, const QwtSetSample &sample) const
Directed rectangle representing bounding rectangle and orientation of a column.
void setValue(int role, const QVariant &)
double sampleWidth(const QwtScaleMap &map, double canvasSize, double dataSize, double value) const
virtual void draw(QPainter *, const QwtColumnRect &) const
QwtInterval hInterval
Interval for the horizontal coordinates.
void setSymbol(int barIndex, QwtColumnSymbol *symbol)
Add a symbol to the symbol map.
virtual T sample(size_t i) const =0
The bars of a set are displayed side by side.
void drawStackedBars(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int index, double sampleWidth, const QwtSetSample &sample) const
bool isInverting() const
double transform(double s) const
int i
From right to left.
double width() const
Return the width of an interval.
Definition: qwt_interval.h:228
Min/Max values are inside the interval.
Definition: qwt_interval.h:36
QVector< double > set
Vector of values associated to value.
Definition: qwt_samples.h:91
Attributes of an entry on a legend.
const QwtText & title() const


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:17