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