Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
qwt_plot_multi_barchart.cpp
1/******************************************************************************
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
10#include "qwt_plot_multi_barchart.h"
11#include "qwt_scale_map.h"
12#include "qwt_column_symbol.h"
13#include "qwt_text.h"
14#include "qwt_graphic.h"
15#include "qwt_legend_data.h"
16#include "qwt_math.h"
17
18#include <qmap.h>
19
20inline static bool qwtIsIncreasing(
21 const QwtScaleMap& map, const QVector< double >& values )
22{
23 bool isInverting = map.isInverting();
24
25 for ( int i = 0; i < values.size(); i++ )
26 {
27 const double y = values[ i ];
28 if ( y != 0.0 )
29 return ( map.isInverting() != ( y > 0.0 ) );
30 }
31
32 return !isInverting;
33}
34
35class QwtPlotMultiBarChart::PrivateData
36{
37 public:
38 PrivateData()
40 {
41 }
42
44 QList< QwtText > barTitles;
46};
47
54{
55 init();
56}
57
64{
65 init();
66}
67
74
75void QwtPlotMultiBarChart::init()
76{
77 m_data = new PrivateData;
79}
80
86
92 const QVector< QwtSetSample >& samples )
93{
94 setData( new QwtSetSeriesData( samples ) );
95}
96
102 const QVector< QVector< double > >& samples )
103{
105 s.reserve( samples.size() );
106
107 for ( int i = 0; i < samples.size(); i++ )
108 s += QwtSetSample( i, samples[ i ] );
109
110 setData( new QwtSetSeriesData( s ) );
111}
112
128
139{
140 m_data->barTitles = titles;
141 itemChanged();
142}
143
149{
150 return m_data->barTitles;
151}
152
165{
166 if ( valueIndex < 0 )
167 return;
168
170 m_data->symbolMap.find(valueIndex);
171 if ( it == m_data->symbolMap.end() )
172 {
173 if ( symbol != NULL )
174 {
175 m_data->symbolMap.insert( valueIndex, symbol );
176
178 itemChanged();
179 }
180 }
181 else
182 {
183 if ( symbol != it.value() )
184 {
185 delete it.value();
186
187 if ( symbol == NULL )
188 {
189 m_data->symbolMap.remove( valueIndex );
190 }
191 else
192 {
193 it.value() = symbol;
194 }
195
197 itemChanged();
198 }
199 }
200}
201
210const QwtColumnSymbol* QwtPlotMultiBarChart::symbol( int valueIndex ) const
211{
213 m_data->symbolMap.constFind( valueIndex );
214
215 return ( it == m_data->symbolMap.constEnd() ) ? NULL : it.value();
216}
217
227{
229 m_data->symbolMap.constFind( valueIndex );
230
231 return ( it == m_data->symbolMap.constEnd() ) ? NULL : it.value();
232}
233
238{
239 qDeleteAll( m_data->symbolMap );
240 m_data->symbolMap.clear();
241}
242
264 int sampleIndex, int valueIndex ) const
265{
266 Q_UNUSED( sampleIndex );
267 Q_UNUSED( valueIndex );
268
269 return NULL;
270}
271
279{
280 if ( style != m_data->style )
281 {
282 m_data->style = style;
283
285 itemChanged();
286 }
287}
288
294{
295 return m_data->style;
296}
297
303{
304 const size_t numSamples = dataSize();
305
306 if ( numSamples == 0 )
308
309 const double baseLine = baseline();
310
311 QRectF rect;
312
313 if ( m_data->style != QwtPlotMultiBarChart::Stacked )
314 {
316
317 if ( rect.height() >= 0 )
318 {
319 if ( rect.bottom() < baseLine )
320 rect.setBottom( baseLine );
321 if ( rect.top() > baseLine )
322 rect.setTop( baseLine );
323 }
324 }
325 else
326 {
327 double xMin, xMax, yMin, yMax;
328
329 xMin = xMax = 0.0;
330 yMin = yMax = baseLine;
331
332 const QwtSeriesData< QwtSetSample >* series = data();
333
334 for ( size_t i = 0; i < numSamples; i++ )
335 {
336 const QwtSetSample sample = series->sample( i );
337 if ( i == 0 )
338 {
339 xMin = xMax = sample.value;
340 }
341 else
342 {
343 xMin = qwtMinF( xMin, sample.value );
344 xMax = qwtMaxF( xMax, sample.value );
345 }
346
347 const double y = baseLine + sample.added();
348
349 yMin = qwtMinF( yMin, y );
350 yMax = qwtMaxF( yMax, y );
351 }
352 rect.setRect( xMin, yMin, xMax - xMin, yMax - yMin );
353 }
354
355 if ( orientation() == Qt::Horizontal )
356 rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
357
358 return rect;
359}
360
374void QwtPlotMultiBarChart::drawSeries( QPainter* painter,
375 const QwtScaleMap& xMap, const QwtScaleMap& yMap,
376 const QRectF& canvasRect, int from, int to ) const
377{
378 if ( to < 0 )
379 to = dataSize() - 1;
380
381 if ( from < 0 )
382 from = 0;
383
384 if ( from > to )
385 return;
386
387
388 const QRectF br = data()->boundingRect();
389 const QwtInterval interval( br.left(), br.right() );
390
391 painter->save();
392
393 for ( int i = from; i <= to; i++ )
394 {
395 drawSample( painter, xMap, yMap,
396 canvasRect, interval, i, sample( i ) );
397 }
398
399 painter->restore();
400}
401
415void QwtPlotMultiBarChart::drawSample( QPainter* painter,
416 const QwtScaleMap& xMap, const QwtScaleMap& yMap,
417 const QRectF& canvasRect, const QwtInterval& boundingInterval,
418 int index, const QwtSetSample& sample ) const
419{
420 if ( sample.set.size() <= 0 )
421 return;
422
423 double sampleW;
424
425 if ( orientation() == Qt::Horizontal )
426 {
427 sampleW = sampleWidth( yMap, canvasRect.height(),
428 boundingInterval.width(), sample.value );
429 }
430 else
431 {
432 sampleW = sampleWidth( xMap, canvasRect.width(),
433 boundingInterval.width(), sample.value );
434 }
435
436 if ( m_data->style == Stacked )
437 {
438 drawStackedBars( painter, xMap, yMap,
439 canvasRect, index, sampleW, sample );
440 }
441 else
442 {
443 drawGroupedBars( painter, xMap, yMap,
444 canvasRect, index, sampleW, sample );
445 }
446}
447
462 const QwtScaleMap& xMap, const QwtScaleMap& yMap,
463 const QRectF& canvasRect, int index, double sampleWidth,
464 const QwtSetSample& sample ) const
465{
466 Q_UNUSED( canvasRect );
467
468 const int numBars = sample.set.size();
469 if ( numBars == 0 )
470 return;
471
472 if ( orientation() == Qt::Vertical )
473 {
474 const double barWidth = sampleWidth / numBars;
475
476 const double y1 = yMap.transform( baseline() );
477 const double x0 = xMap.transform( sample.value ) - 0.5 * sampleWidth;
478
479 for ( int i = 0; i < numBars; i++ )
480 {
481 const double x1 = x0 + i * barWidth;
482 const double x2 = x1 + barWidth;
483
484 const double y2 = yMap.transform( sample.set[i] );
485
486 QwtColumnRect barRect;
487 barRect.direction = ( y1 < y2 ) ?
489
490 barRect.hInterval = QwtInterval( x1, x2 ).normalized();
491 if ( i != 0 )
493
494 barRect.vInterval = QwtInterval( y1, y2 ).normalized();
495
496 drawBar( painter, index, i, barRect );
497 }
498 }
499 else
500 {
501 const double barHeight = sampleWidth / numBars;
502
503 const double x1 = xMap.transform( baseline() );
504 const double y0 = yMap.transform( sample.value ) - 0.5 * sampleWidth;
505
506 for ( int i = 0; i < numBars; i++ )
507 {
508 double y1 = y0 + i * barHeight;
509 double y2 = y1 + barHeight;
510
511 double x2 = xMap.transform( sample.set[i] );
512
513 QwtColumnRect barRect;
514 barRect.direction = x1 < x2 ?
516
517 barRect.hInterval = QwtInterval( x1, x2 ).normalized();
518
519 barRect.vInterval = QwtInterval( y1, y2 );
520 if ( i != 0 )
522
523 drawBar( painter, index, i, barRect );
524 }
525 }
526}
527
542 const QwtScaleMap& xMap, const QwtScaleMap& yMap,
543 const QRectF& canvasRect, int index,
544 double sampleWidth, const QwtSetSample& sample ) const
545{
546 Q_UNUSED( canvasRect ); // clipping the bars ?
547
548 const int numBars = sample.set.size();
549 if ( numBars == 0 )
550 return;
551
553
554 if ( orientation() == Qt::Vertical )
555 {
556 const double x1 = xMap.transform( sample.value ) - 0.5 * sampleWidth;
557 const double x2 = x1 + sampleWidth;
558
559 const bool increasing = qwtIsIncreasing( yMap, sample.set );
560
561 QwtColumnRect bar;
562 bar.direction = increasing ?
564
565 bar.hInterval = QwtInterval( x1, x2 ).normalized();
566
567 double sum = baseline();
568
569 for ( int i = 0; i < numBars; i++ )
570 {
571 const double si = sample.set[ i ];
572 if ( si == 0.0 )
573 continue;
574
575 const double y1 = yMap.transform( sum );
576 const double y2 = yMap.transform( sum + si );
577
578 if ( ( y2 > y1 ) != increasing )
579 {
580 // stacked bars need to be in the same direction
581 continue;
582 }
583
584 bar.vInterval = QwtInterval( y1, y2 ).normalized();
585 bar.vInterval.setBorderFlags( borderFlags );
586
587 drawBar( painter, index, i, bar );
588
589 sum += si;
590
591 if ( increasing )
592 borderFlags = QwtInterval::ExcludeMinimum;
593 else
594 borderFlags = QwtInterval::ExcludeMaximum;
595 }
596 }
597 else
598 {
599 const double y1 = yMap.transform( sample.value ) - 0.5 * sampleWidth;
600 const double y2 = y1 + sampleWidth;
601
602 const bool increasing = qwtIsIncreasing( xMap, sample.set );
603
604 QwtColumnRect bar;
605 bar.direction = increasing ?
607 bar.vInterval = QwtInterval( y1, y2 ).normalized();
608
609 double sum = baseline();
610
611 for ( int i = 0; i < sample.set.size(); i++ )
612 {
613 const double si = sample.set[ i ];
614 if ( si == 0.0 )
615 continue;
616
617 const double x1 = xMap.transform( sum );
618 const double x2 = xMap.transform( sum + si );
619
620 if ( ( x2 > x1 ) != increasing )
621 {
622 // stacked bars need to be in the same direction
623 continue;
624 }
625
626 bar.hInterval = QwtInterval( x1, x2 ).normalized();
627 bar.hInterval.setBorderFlags( borderFlags );
628
629 drawBar( painter, index, i, bar );
630
631 sum += si;
632
633 if ( increasing )
634 borderFlags = QwtInterval::ExcludeMinimum;
635 else
636 borderFlags = QwtInterval::ExcludeMaximum;
637 }
638 }
639}
640
652void QwtPlotMultiBarChart::drawBar( QPainter* painter,
653 int sampleIndex, int valueIndex, const QwtColumnRect& rect ) const
654{
655 const QwtColumnSymbol* specialSym = NULL;
656 if ( sampleIndex >= 0 )
657 specialSym = specialSymbol( sampleIndex, valueIndex );
658
659 const QwtColumnSymbol* sym = specialSym;
660 if ( sym == NULL )
661 sym = symbol( valueIndex );
662
663 if ( sym )
664 {
665 sym->draw( painter, rect );
666 }
667 else
668 {
669 // we build a temporary default symbol
671 columnSymbol.setLineWidth( 1 );
673 columnSymbol.draw( painter, rect );
674 }
675
676 delete specialSym;
677}
678
688{
690 list.reserve( m_data->barTitles.size() );
691
692 for ( int i = 0; i < m_data->barTitles.size(); i++ )
693 {
695
696 data.setValue( QwtLegendData::TitleRole,
697 QVariant::fromValue( m_data->barTitles[i] ) );
698
699 if ( !legendIconSize().isEmpty() )
700 {
701 data.setValue( QwtLegendData::IconRole,
702 QVariant::fromValue( legendIcon( i, legendIconSize() ) ) );
703 }
704
705 list += data;
706 }
707
708 return list;
709}
710
721 const QSizeF& size ) const
722{
723 QwtColumnRect column;
724 column.hInterval = QwtInterval( 0.0, size.width() - 1.0 );
725 column.vInterval = QwtInterval( 0.0, size.height() - 1.0 );
726
727 QwtGraphic icon;
728 icon.setDefaultSize( size );
730
731 QPainter painter( &icon );
732 painter.setRenderHint( QPainter::Antialiasing,
734
735 drawBar( &painter, -1, index, column );
736
737 return icon;
738}
739
Template class for data, that is organized as QVector.
Directed rectangle representing bounding rectangle and orientation of a column.
QwtInterval vInterval
Interval for the vertical coordinates.
QwtInterval hInterval
Interval for the horizontal coordinates.
@ LeftToRight
From left to right.
@ TopToBottom
From top to bottom.
@ BottomToTop
From bottom to top.
@ RightToLeft
From right to left.
Direction direction
Direction.
A drawing primitive for columns.
@ Plain
A plain frame style.
virtual void draw(QPainter *, const QwtColumnRect &) const
void setFrameStyle(FrameStyle)
void setLineWidth(int width)
A paint device for scalable graphics.
Definition qwt_graphic.h:76
@ RenderPensUnscaled
Definition qwt_graphic.h:96
void setRenderHint(RenderHint, bool on=true)
void setDefaultSize(const QSizeF &)
Set a default size.
A class representing an interval.
QwtInterval normalized() const
Normalize the limits of the interval.
double width() const
Return the width of an interval.
@ ExcludeMaximum
Max value is not included in the interval.
@ ExcludeMinimum
Min value is not included in the interval.
@ IncludeBorders
Min/Max values are inside the interval.
void setBorderFlags(BorderFlags)
Attributes of an entry on a legend.
Abstract base class for bar chart items.
double sampleWidth(const QwtScaleMap &map, double canvasSize, double boundingSize, double value) const
virtual void legendChanged()
@ Rtti_PlotMultiBarChart
For QwtPlotMultiBarChart.
@ RenderAntialiased
Enable antialiasing.
bool testRenderHint(RenderHint) const
virtual void itemChanged()
QSize legendIconSize() const
QwtPlotMultiBarChart displays a series of a samples that consist each of a set of values.
QList< QwtText > barTitles() const
virtual QwtGraphic legendIcon(int index, const QSizeF &) const override
virtual ~QwtPlotMultiBarChart()
Destructor.
virtual QwtColumnSymbol * specialSymbol(int sampleIndex, int valueIndex) const
Create a symbol for special values.
QwtPlotMultiBarChart(const QString &title=QString())
void setStyle(ChartStyle style)
virtual void drawSeries(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to) const override
virtual void drawSample(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, const QwtInterval &boundingInterval, int index, const QwtSetSample &) const
void drawStackedBars(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int index, double sampleWidth, const QwtSetSample &) const
void setSymbol(int valueIndex, QwtColumnSymbol *)
Add a symbol to the symbol map.
virtual QList< QwtLegendData > legendData() const override
void drawGroupedBars(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int index, double sampleWidth, const QwtSetSample &) const
virtual int rtti() const override
void setBarTitles(const QList< QwtText > &)
Set the titles for the bars.
virtual QRectF boundingRect() const override
@ Grouped
The bars of a set are displayed side by side.
const QwtColumnSymbol * symbol(int valueIndex) const
virtual void drawBar(QPainter *, int sampleIndex, int valueIndex, const QwtColumnRect &) const
void setSamples(const QVector< QwtSetSample > &)
Qt::Orientation orientation() const
virtual QRectF boundingRect() const override
A scale map.
bool isInverting() const
double transform(double s) const
virtual QRectF boundingRect() const
virtual T sample(size_t i) const =0
QwtSetSample sample(int index) const
virtual size_t dataSize() const override
QwtSeriesData< QwtSetSample > * data()
void setData(QwtSeriesData< QwtSetSample > *series)
A sample of the types (x1...xn, y) or (x, y1..yn)
Definition qwt_samples.h:74
double added() const
double value
value
Definition qwt_samples.h:85
QVector< double > set
Vector of values associated to value.
Definition qwt_samples.h:88
A class representing a text.
Definition qwt_text.h:52