@@ -33,9 +33,7 BoxPlotChartItem::BoxPlotChartItem(QBoxPlotSeries *series, QGraphicsItem *item) | |||
|
33 | 33 | ChartItem(series->d_func(), item), |
|
34 | 34 | m_series(series), |
|
35 | 35 | m_animation(0), |
|
36 |
m_animate(0) |
|
|
37 | m_domainMaxY(0.0), | |
|
38 | m_domainMinY(0.0) | |
|
36 | m_animate(0) | |
|
39 | 37 | { |
|
40 | 38 | connect(series, SIGNAL(boxsetsRemoved(QList<QBoxSet *>)), this, SLOT(handleBoxsetRemove(QList<QBoxSet *>))); |
|
41 | 39 | connect(series->d_func(), SIGNAL(restructuredBoxes()), this, SLOT(handleDataStructureChanged())); |
@@ -90,7 +88,7 void BoxPlotChartItem::handleDataStructureChanged() | |||
|
90 | 88 | } |
|
91 | 89 | updateBoxGeometry(box, s); |
|
92 | 90 | |
|
93 | box->updateGeometry(); | |
|
91 | box->updateGeometry(domain()); | |
|
94 | 92 | |
|
95 | 93 | if (m_animation) |
|
96 | 94 | m_animation->addBox(box); |
@@ -128,17 +126,12 void BoxPlotChartItem::handleDomainUpdated() | |||
|
128 | 126 | if ((domain()->size().width() <= 0) || (domain()->size().height() <= 0)) |
|
129 | 127 | return; |
|
130 | 128 | |
|
131 | // Set my bounding rect to same as domain size | |
|
132 | m_boundingRect.setRect(0.0, 0.0, domain()->size().width(), domain()->size().height()); | |
|
129 | // Set my bounding rect to same as domain size. Add one pixel at the top (-1.0) and the bottom as 0.0 would | |
|
130 | // snip a bit off from the whisker at the grid line | |
|
131 | m_boundingRect.setRect(0.0, -1.0, domain()->size().width(), domain()->size().height() + 1.0); | |
|
133 | 132 | |
|
134 | 133 | foreach (BoxWhiskers *item, m_boxTable.values()) { |
|
135 | // Update the domain size for each BoxWhisker item | |
|
136 | item->setDomainSize(domain()->size()); | |
|
137 | if (domain()->minY() != m_domainMinY || domain()->maxY() != m_domainMaxY) { | |
|
138 | item->updateGeometry(); | |
|
139 | m_domainMinY = domain()->minY(); | |
|
140 | m_domainMaxY = domain()->maxY(); | |
|
141 | } | |
|
134 | item->updateGeometry(domain()); | |
|
142 | 135 | |
|
143 | 136 | // If the animation is set, start the animation for each BoxWhisker item |
|
144 | 137 | if (m_animation) |
@@ -156,7 +149,7 void BoxPlotChartItem::handleLayoutChanged() | |||
|
156 | 149 | if (dirty && m_animation) |
|
157 | 150 | presenter()->startAnimation(m_animation->boxChangeAnimation(item)); |
|
158 | 151 | else |
|
159 | item->updateGeometry(); | |
|
152 | item->updateGeometry(domain()); | |
|
160 | 153 | } |
|
161 | 154 | } |
|
162 | 155 |
@@ -76,8 +76,6 protected: | |||
|
76 | 76 | |
|
77 | 77 | BoxPlotAnimation *m_animation; |
|
78 | 78 | bool m_animate; |
|
79 | qreal m_domainMaxY; | |
|
80 | qreal m_domainMinY; | |
|
81 | 79 | |
|
82 | 80 | QRectF m_boundingRect; |
|
83 | 81 | }; |
@@ -71,11 +71,10 void BoxWhiskers::setLayout(const BoxWhiskersData &data) | |||
|
71 | 71 | { |
|
72 | 72 | m_data = data; |
|
73 | 73 | |
|
74 | updateGeometry(); | |
|
74 | updateGeometry(m_domain); | |
|
75 | 75 | update(); |
|
76 | 76 | } |
|
77 | 77 | |
|
78 | ||
|
79 | 78 | QSizeF BoxWhiskers::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const |
|
80 | 79 | { |
|
81 | 80 | Q_UNUSED(which) |
@@ -89,13 +88,6 void BoxWhiskers::setGeometry(const QRectF &rect) | |||
|
89 | 88 | Q_UNUSED(rect) |
|
90 | 89 | } |
|
91 | 90 | |
|
92 | void BoxWhiskers::setDomainSize(const QSizeF &size) | |
|
93 | { | |
|
94 | m_domainSize = size; | |
|
95 | ||
|
96 | updateBoundingRect(); | |
|
97 | } | |
|
98 | ||
|
99 | 91 | QRectF BoxWhiskers::boundingRect() const |
|
100 | 92 | { |
|
101 | 93 | return m_boundingRect; |
@@ -109,57 +101,69 void BoxWhiskers::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio | |||
|
109 | 101 | painter->setPen(m_pen); |
|
110 | 102 | painter->setBrush(m_brush); |
|
111 | 103 | painter->setClipRect(parentItem()->boundingRect()); |
|
112 | painter->scale(m_domainSize.width() / m_data.m_boxItems, m_domainSize.height() / m_domain->spanY()); | |
|
113 | 104 | painter->drawPath(m_boxPath); |
|
114 | 105 | } |
|
115 | 106 | |
|
116 | void BoxWhiskers::updateGeometry() | |
|
107 | void BoxWhiskers::updateGeometry(AbstractDomain *domain) | |
|
117 | 108 | { |
|
109 | m_domain = domain; | |
|
110 | ||
|
118 | 111 | prepareGeometryChange(); |
|
119 | 112 | |
|
120 | 113 | QPainterPath path; |
|
114 | m_boxPath = path; | |
|
115 | m_boundingRect = m_boxPath.boundingRect(); | |
|
121 | 116 | |
|
122 | 117 | qreal columnWidth = 1.0 / m_data.m_seriesCount; |
|
123 | qreal left = 0.25 * columnWidth + columnWidth * m_data.m_seriesIndex; | |
|
124 | qreal right = 0.75 * columnWidth + columnWidth * m_data.m_seriesIndex; | |
|
125 | qreal middle = 0.5 * columnWidth + columnWidth * m_data.m_seriesIndex; | |
|
126 | qreal domainMaxY = m_domain->maxY(); | |
|
118 | qreal left = 0.25 * columnWidth + columnWidth * m_data.m_seriesIndex + m_data.m_index - 0.5; | |
|
119 | qreal barWidth = columnWidth / 2.0; | |
|
120 | ||
|
121 | QPointF geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_upperExtreme), m_validData); | |
|
122 | if (!m_validData) | |
|
123 | return; | |
|
124 | qreal geometryLeft = geometryPoint.x(); | |
|
125 | qreal geometryUpperExtreme = geometryPoint.y(); | |
|
126 | geometryPoint = m_domain->calculateGeometryPoint(QPointF(left + barWidth, m_data.m_upperQuartile), m_validData); | |
|
127 | if (!m_validData) | |
|
128 | return; | |
|
129 | qreal geometryRight = geometryPoint.x(); | |
|
130 | qreal geometryUpperQuartile = geometryPoint.y(); | |
|
131 | geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_lowerQuartile), m_validData); | |
|
132 | if (!m_validData) | |
|
133 | return; | |
|
134 | qreal geometryLowerQuartile = geometryPoint.y(); | |
|
135 | geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_lowerExtreme), m_validData); | |
|
136 | if (!m_validData) | |
|
137 | return; | |
|
138 | qreal geometryLowerExtreme = geometryPoint.y(); | |
|
139 | geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_median), m_validData); | |
|
140 | if (!m_validData) | |
|
141 | return; | |
|
142 | qreal geometryMedian = geometryPoint.y(); | |
|
127 | 143 | |
|
128 | 144 | // Upper whisker |
|
129 | path.moveTo(left + m_data.m_index, domainMaxY - m_data.m_upperExtreme); | |
|
130 |
path.lineTo(right |
|
|
131 | path.moveTo(middle + m_data.m_index, domainMaxY - m_data.m_upperExtreme); | |
|
132 | path.lineTo(middle + m_data.m_index, domainMaxY - m_data.m_upperQuartile); | |
|
145 | path.moveTo(geometryLeft, geometryUpperExtreme); | |
|
146 | path.lineTo(geometryRight, geometryUpperExtreme); | |
|
147 | path.moveTo((geometryLeft + geometryRight) / 2.0, geometryUpperExtreme); | |
|
148 | path.lineTo((geometryLeft + geometryRight) / 2.0, geometryUpperQuartile); | |
|
133 | 149 | |
|
134 | 150 | // Middle Box |
|
135 | path.addRect(left + m_data.m_index, domainMaxY - m_data.m_upperQuartile, | |
|
136 | 0.5 * columnWidth, m_data.m_upperQuartile - m_data.m_lowerQuartile); | |
|
151 | path.addRect(geometryLeft, geometryUpperQuartile, geometryRight - geometryLeft, geometryLowerQuartile - geometryUpperQuartile); | |
|
137 | 152 | |
|
138 |
// Median |
|
|
139 | path.moveTo(left + m_data.m_index, domainMaxY - m_data.m_median); | |
|
140 | path.lineTo(right + m_data.m_index, domainMaxY - m_data.m_median); | |
|
153 | // Median line | |
|
154 | path.moveTo(geometryLeft, geometryMedian); | |
|
155 | path.lineTo(geometryRight, geometryMedian); | |
|
141 | 156 | |
|
142 | 157 | // Lower whisker |
|
143 | path.moveTo(left + m_data.m_index, domainMaxY - m_data.m_lowerExtreme); | |
|
144 |
path.lineTo(right |
|
|
145 | path.moveTo(middle + m_data.m_index, domainMaxY - m_data.m_lowerExtreme); | |
|
146 | path.lineTo(middle + m_data.m_index, domainMaxY - m_data.m_lowerQuartile); | |
|
158 | path.moveTo(geometryLeft, geometryLowerExtreme); | |
|
159 | path.lineTo(geometryRight, geometryLowerExtreme); | |
|
160 | path.moveTo((geometryLeft + geometryRight) / 2.0, geometryLowerQuartile); | |
|
161 | path.lineTo((geometryLeft + geometryRight) / 2.0, geometryLowerExtreme); | |
|
147 | 162 | |
|
148 | 163 | path.closeSubpath(); |
|
149 | 164 | |
|
150 | 165 | m_boxPath = path; |
|
151 | ||
|
152 | updateBoundingRect(); | |
|
153 | } | |
|
154 | ||
|
155 | void BoxWhiskers::updateBoundingRect() | |
|
156 | { | |
|
157 | qreal scaleY = m_domainSize.height() / (m_domain->maxY() - m_domain->minY()); | |
|
158 | qreal scaleX = m_domainSize.width() / m_data.m_boxItems; | |
|
159 | QRectF br = m_boxPath.boundingRect(); | |
|
160 | ||
|
161 | m_boundingRect = QRectF(br.x() * scaleX, br.y() * scaleY, | |
|
162 | br.width() * scaleX, br.height() * scaleY); | |
|
166 | m_boundingRect = m_boxPath.boundingRect(); | |
|
163 | 167 | } |
|
164 | 168 | |
|
165 | 169 | #include "moc_boxwhiskers_p.cpp" |
@@ -54,7 +54,6 public: | |||
|
54 | 54 | void setBrush(const QBrush &brush); |
|
55 | 55 | void setPen(const QPen &pen); |
|
56 | 56 | void setLayout(const BoxWhiskersData &data); |
|
57 | void setDomainSize(const QSizeF &size); | |
|
58 | 57 | |
|
59 | 58 | void mousePressEvent(QGraphicsSceneMouseEvent *event); |
|
60 | 59 | void hoverEnterEvent(QGraphicsSceneHoverEvent *event); |
@@ -63,14 +62,11 public: | |||
|
63 | 62 | QRectF boundingRect() const; |
|
64 | 63 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); |
|
65 | 64 | |
|
66 | void updateGeometry(); | |
|
65 | void updateGeometry(AbstractDomain *domain); | |
|
67 | 66 | protected: |
|
68 | 67 | QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const; |
|
69 | 68 | void setGeometry(const QRectF &rect); |
|
70 | 69 | |
|
71 | private: | |
|
72 | void updateBoundingRect(); | |
|
73 | ||
|
74 | 70 | Q_SIGNALS: |
|
75 | 71 | void clicked(QBoxSet *boxset); |
|
76 | 72 | void hovered(bool status, QBoxSet *boxset); |
@@ -382,9 +382,9 void QBoxPlotSeriesPrivate::initializeDomain() | |||
|
382 | 382 | qreal maxY(domain()->maxY()); |
|
383 | 383 | |
|
384 | 384 | qreal x = m_boxSets.count(); |
|
385 |
minX = qMin(minX, - |
|
|
385 | minX = qMin(minX, qreal(-0.5)); | |
|
386 | 386 | minY = qMin(minY, min()); |
|
387 |
maxX = qMax(maxX, x - ( |
|
|
387 | maxX = qMax(maxX, x - qreal(0.5)); | |
|
388 | 388 | maxY = qMax(maxY, max()); |
|
389 | 389 | |
|
390 | 390 | domain()->setRange(minX, maxX, minY, maxY); |
@@ -43,15 +43,17 | |||
|
43 | 43 | #include <QDebug> |
|
44 | 44 | #include <QStandardItemModel> |
|
45 | 45 | #include <QBarCategoryAxis> |
|
46 | ||
|
46 | #include <QLogValueAxis> | |
|
47 | 47 | |
|
48 | 48 | QTCOMMERCIALCHART_USE_NAMESPACE |
|
49 | 49 | |
|
50 | 50 | QString addCategories[] = {"Jul", "Aug", "Sep", "Nov", "Dec"}; |
|
51 | static const int maxAddCategories = 5; | |
|
51 | 52 | |
|
52 | 53 | MainWidget::MainWidget(QWidget *parent) : |
|
53 | 54 | QWidget(parent), |
|
54 | 55 | m_chart(0), |
|
56 | m_axis(0), | |
|
55 | 57 | rowPos(0), |
|
56 | 58 | nSeries(0), |
|
57 | 59 | nNewBoxes(0) |
@@ -124,7 +126,6 MainWidget::MainWidget(QWidget *parent) : | |||
|
124 | 126 | |
|
125 | 127 | // Create chart view with the chart |
|
126 | 128 | m_chartView = new QChartView(m_chart, this); |
|
127 | //m_chartView->setRubberBand(QChartView::HorizonalRubberBand); | |
|
128 | 129 | |
|
129 | 130 | // Another grid layout as a main layout |
|
130 | 131 | QGridLayout *mainLayout = new QGridLayout(); |
@@ -187,7 +188,6 void MainWidget::addSeries() | |||
|
187 | 188 | return; |
|
188 | 189 | |
|
189 | 190 | // Initial data |
|
190 | //![1] | |
|
191 | 191 | QBoxSet *set0 = new QBoxSet(); |
|
192 | 192 | QBoxSet *set1 = new QBoxSet(); |
|
193 | 193 | QBoxSet *set2 = new QBoxSet(); |
@@ -196,7 +196,7 void MainWidget::addSeries() | |||
|
196 | 196 | QBoxSet *set5 = new QBoxSet(); |
|
197 | 197 | |
|
198 | 198 | // low bot med top upp |
|
199 |
*set0 << 1 << 2 << 4 |
|
|
199 | *set0 << -1 << 2 << 4 << 13 << 15; | |
|
200 | 200 | *set1 << 5 << 6 << 7.5 << 8 << 12; |
|
201 | 201 | *set2 << 3 << 5 << 5.7 << 8 << 9; |
|
202 | 202 | *set3 << 5 << 6 << 6.8 << 7 << 8; |
@@ -219,14 +219,14 void MainWidget::addSeries() | |||
|
219 | 219 | |
|
220 | 220 | m_chart->addSeries(m_series[nSeries]); |
|
221 | 221 | |
|
222 |
if ( |
|
|
222 | if (!m_axis) { | |
|
223 | 223 | QStringList categories; |
|
224 | 224 | categories << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "Jun"; |
|
225 | 225 | m_axis = new QBarCategoryAxis(); |
|
226 | 226 | m_axis->append(categories); |
|
227 | 227 | m_chart->createDefaultAxes(); |
|
228 | m_chart->setAxisX(m_axis, m_series[nSeries]); | |
|
229 | 228 | } |
|
229 | m_chart->setAxisX(m_axis, m_series[nSeries]); | |
|
230 | 230 | |
|
231 | 231 | nSeries++; |
|
232 | 232 | } |
@@ -248,7 +248,7 void MainWidget::addBox() | |||
|
248 | 248 | { |
|
249 | 249 | qDebug() << "BoxPlotTester::MainWidget::addBox()"; |
|
250 | 250 | |
|
251 | if (nSeries > 0) { | |
|
251 | if (nSeries > 0 && nNewBoxes < maxAddCategories) { | |
|
252 | 252 | QBoxSet *newSet = new QBoxSet(); |
|
253 | 253 | newSet->setValue(QBoxSet::LowerExtreme, 5.0); |
|
254 | 254 | newSet->setValue(QBoxSet::LowerQuartile, 6.0); |
@@ -256,8 +256,7 void MainWidget::addBox() | |||
|
256 | 256 | newSet->setValue(QBoxSet::UpperQuartile, 7.0); |
|
257 | 257 | newSet->setValue(QBoxSet::UpperExtreme, 8.0); |
|
258 | 258 | |
|
259 | for (int i = 0; i < nSeries; i++) | |
|
260 | m_series[i]->append(newSet); | |
|
259 | m_series[0]->append(newSet); | |
|
261 | 260 | |
|
262 | 261 | m_axis->append(addCategories[nNewBoxes]); |
|
263 | 262 | |
@@ -288,10 +287,14 void MainWidget::removeBox() | |||
|
288 | 287 | |
|
289 | 288 | if (nSeries > 0) { |
|
290 | 289 | for (int i = 0; i < nSeries; i++) { |
|
290 | qDebug() << "m_series[i]->count() = " << m_series[i]->count(); | |
|
291 | if (m_series[i]->count() > 3) { | |
|
291 | 292 | QList<QBoxSet *> sets = m_series[i]->boxSets(); |
|
292 | 293 | m_series[i]->remove(sets.at(m_series[i]->count() - 3)); |
|
293 | 294 | } |
|
295 | } | |
|
294 | 296 | |
|
297 | if (m_axis->count() > 3) | |
|
295 | 298 | m_axis->remove(m_axis->at(1)); |
|
296 | 299 | } else { |
|
297 | 300 | qDebug() << "Create a series first"; |
General Comments 0
You need to be logged in to leave comments.
Login now