##// END OF EJS Templates
Changed BoxPlot to use domain for calculating geometry points....
Mika Salmela -
r2554:93cea193b2c2
parent child
Show More
@@ -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 + m_data.m_index, domainMaxY - m_data.m_upperExtreme);
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/mean line
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 + m_data.m_index, domainMaxY - m_data.m_lowerExtreme);
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, - (qreal)0.5);
385 minX = qMin(minX, qreal(-0.5));
386 386 minY = qMin(minY, min());
387 maxX = qMax(maxX, x - (qreal)0.5);
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.4 << 13 << 15;
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 (nSeries == 0) {
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