diff --git a/examples/boxplotchart/main.cpp b/examples/boxplotchart/main.cpp index e20af3a..8518401 100644 --- a/examples/boxplotchart/main.cpp +++ b/examples/boxplotchart/main.cpp @@ -37,7 +37,7 @@ int main(int argc, char *argv[]) //![2] QBoxPlotSeries *series = new QBoxPlotSeries(); - series->setName("Box & Whiskers"); + series->setName("Cargotec"); //![2] QFile stockData(":stock"); @@ -55,14 +55,13 @@ int main(int argc, char *argv[]) //![3] QChart *chart = new QChart(); chart->addSeries(series); - chart->setTitle("Simple boxplotchart example"); + chart->setTitle("Cargotec's share deviation 2012") chart->setAnimationOptions(QChart::SeriesAnimations); //![3] //![4] - QBarCategoryAxis *axis = new QBarCategoryAxis(); chart->createDefaultAxes(); - chart->setAxisX(axis, series); + chart->axisY()->setMin(15.0); //![4] //![5] diff --git a/examples/boxplotchart/stock_data.txt b/examples/boxplotchart/stock_data.txt index bf32f81..18d7417 100644 --- a/examples/boxplotchart/stock_data.txt +++ b/examples/boxplotchart/stock_data.txt @@ -1,8 +1,24 @@ -Jan 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 +#Jan 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 #0 1 2 3 4 5 6 7 8 9 -Feb 4.3 5.1 3.9 4.5 4.4 4.9 5.0 4.7 4.1 4.6 4.4 4.3 4.8 4.4 4.2 4.5 4.4 -Mar 1.0 1.2 2.0 2.4 2.5 3.0 3.5 3.7 4.0 4.7 5.0 -Apr 4.6 4.7 5.2 7.3 8.4 8.8 9.1 8.3 7.4 6.4 5.3 -May 3.5 7.2 5.4 6.3 7.4 8.3 8.8 3.3 5.4 5.7 3.9 +#Feb 4.3 5.1 3.2 4.5 4.4 4.9 5.0 4.7 4.1 4.6 4.4 4.3 4.8 4.4 4.2 4.5 4.4 +#Mar 1.0 1.2 2.0 2.4 2.5 3.0 3.5 3.7 4.0 4.7 5.0 +#Apr 4.6 4.7 5.2 7.3 8.4 8.8 9.1 8.3 7.4 6.4 5.3 +#May 3.5 7.2 5.4 6.3 7.4 8.3 8.8 3.3 5.4 5.7 3.9 +#Jun 2.5 4.6 7.3 4.6 7.8 9.0 7.4 +#Jul 4.7 3.8 5.7 6.4 6.9 4.6 7.2 5.9 #0 1 2 3 4 5 6 7 8 9 10 # * * * +#Top 18.0 18.5 19.0 19.5 19.7 20.0 20.5 20.75 21.0 21.5 22.1 +#Tok 19.0 19.5 21.0 21.5 21.7 22.0 22.5 22.75 23.0 23.5 24.0 +Jan 27,74 27,28 27,86 28,05 28,64 27,47 28,30 28,22 28,72 26,50 26,62 26,50 26,15 26,47 26,41 25,78 24,82 24,89 24,88 24,60 23,85 +Feb 31,79 30,62 30,67 31,37 31,16 31,22 32,02 32,70 31,60 31,24 30,98 30,79 31,10 30,79 31,53 30,92 30,00 30,58 30,37 29,40 28,60 +Mar 28,64 28,34 29,13 29,43 30,75 29,77 29,72 30,52 31,12 33,05 32,51 32,69 31,83 32,47 31,41 31,39 31,78 30,08 29,46 31,58 31,39 31,41 +Apr 25,96 26,62 26,19 30,37 28,78 27,50 28,90 28,40 28,86 28,90 27,91 27,32 27,99 26,86 26,68 27,57 27,50 28,96 28,50 +May 20,85 21,08 21,98 21,61 21,45 21,73 21,71 22,27 21,14 20,65 21,95 22,23 23,17 24,26 24,17 22,97 23,53 24,49 24,51 25,46 25,65 +Jun 18,08 17,19 17,36 17,21 17,31 18,19 18,30 17,53 17,35 17,80 17,17 16,95 18,25 20,52 20,61 21,40 20,45 19,43 19,11 19,74 +Jul 17,75 18,24 17,57 16,53 15,98 16,06 16,64 17,69 17,91 18,00 18,03 18,14 18,10 17,86 18,12 18,53 18,43 18,30 19,03 18,76 18,79 18,33 +Aug 18,69 18,54 18,39 18,49 18,96 18,72 19,25 19,70 20,13 19,74 19,27 18,25 17,72 18,02 18,20 18,24 18,60 18,22 18,60 17,98 17,27 16,70 17,19 +Sep 18,35 18,82 18,96 19,96 19,75 20,55 20,68 21,19 21,14 21,48 21,45 20,74 20,97 20,18 19,66 19,54 18,89 18,39 18,26 18,86 +Oct 16,95 16,80 16,45 16,89 17,38 17,12 16,85 17,59 17,65 17,46 17,43 17,30 17,87 18,61 18,55 18,59 19,27 19,54 20,02 19,23 18,05 18,52 18,71 +Now 19,36 19,29 18,22 18,74 19,05 19,13 18,67 18,19 17,94 18,04 17,49 17,53 17,64 18,00 18,21 18,19 18,30 18,11 18,17 17,76 17,80 17,52 +Dec 19,95 20,19 20,15 20,42 20,39 20,65 20,39 19,86 19,48 19,70 19,94 19,82 20,25 20,21 19,63 19,55 diff --git a/examples/qmlboxplot/qml/qmlboxplot/box.qml b/examples/qmlboxplot/qml/qmlboxplot/box.qml new file mode 100644 index 0000000..09726a3 --- /dev/null +++ b/examples/qmlboxplot/qml/qmlboxplot/box.qml @@ -0,0 +1,31 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.1 +import QtCommercial.Chart 1.1 + +BoxSet { + id: myNewBox + label: "Foo" + values: [5, 6, 7, 8, 9] + Component.onCompleted: { + console.log("BoxSet completed") + } +} diff --git a/examples/qmlboxplot/qml/qmlboxplot/main.qml b/examples/qmlboxplot/qml/qmlboxplot/main.qml index d07c709..e492927 100644 --- a/examples/qmlboxplot/qml/qmlboxplot/main.qml +++ b/examples/qmlboxplot/qml/qmlboxplot/main.qml @@ -34,15 +34,45 @@ ChartView { BoxPlotSeries { id: plotSeries name: "Income" - axisX: BarCategoryAxis { categories: ["Jan", "Feb", "Mar", "Apr", "May"] } + //axisX: BarCategoryAxis { categories: ["Jan", "Feb", "Mar", "Apr", "May"] } BoxSet { values: [3, 4, 4.4, 6, 7] } - BoxSet { values: [5, 6, 7.5, 8, 12] } - BoxSet { values: [2, 5, 5.7, 8, 9] } - BoxSet { values: [5, 6, 6.8, 7, 8] } - BoxSet { values: [4, 5, 5.2, 6, 7] } + BoxSet { label: "Tok"; values: [5, 6, 7.5, 8, 12] } + BoxSet { label: "Kol"; values: [2, 5, 5.7, 8, 9] } + BoxSet { label: "Nel"; values: [5, 6, 6.8, 7, 8] } + BoxSet { label: "Vii"; values: [4, 5, 5.2, 6, 7] } } //![2] + Rectangle { + id: moreButton + width: 50 + height: 50 + color: "gray" + MouseArea { + anchors.fill: parent + onClicked: { + var com = Qt.createComponent("box.qml") + if (com.status == Component.Ready) { + var obj = com.createObject(moreButton) + obj.lowerExtreme = 1.2 + console.log("lowerExtreme = " + obj.lowerExtreme) + obj.lowerQuartile = 2.2 + console.log("lowerQuartile = " + obj.lowerQuartile) + obj.median = 3.2 + console.log("median = " + obj.median) + obj.upperQuartile = 4.2 + console.log("upperQuartile = " + obj.upperQuartile) + obj.upperExtreme = 5.2 + console.log("upperExtreme = " + obj.upperExtreme) + obj.label = "mik" + console.log("label = " + obj.label) + plotSeries.append(obj) + } else { + console.log(com.errorString()) + } + } + } + } //![3] } diff --git a/examples/qmlboxplot/qmlboxplot.pro b/examples/qmlboxplot/qmlboxplot.pro index 194aef3..d7ec0d5 100644 --- a/examples/qmlboxplot/qmlboxplot.pro +++ b/examples/qmlboxplot/qmlboxplot.pro @@ -8,4 +8,5 @@ SOURCES += main.cpp include(qmlapplicationviewer/qmlapplicationviewer.pri) OTHER_FILES += \ - qml/qmlboxplot/main.qml + qml/qmlboxplot/main.qml \ + qml/qmlboxplot/box.qml diff --git a/examples/qmlboxplot/resources.qrc b/examples/qmlboxplot/resources.qrc index 49a98f1..aabf72c 100644 --- a/examples/qmlboxplot/resources.qrc +++ b/examples/qmlboxplot/resources.qrc @@ -1,5 +1,6 @@ qml/qmlboxplot/main.qml + qml/qmlboxplot/box.qml diff --git a/plugins/declarative/declarativeboxplotseries.cpp b/plugins/declarative/declarativeboxplotseries.cpp index 195fed6..48097c8 100644 --- a/plugins/declarative/declarativeboxplotseries.cpp +++ b/plugins/declarative/declarativeboxplotseries.cpp @@ -21,16 +21,15 @@ #include "declarativebarseries.h" #include "declarativeboxplotseries.h" #include "qboxset.h" -#include "qvbarmodelmapper.h" -#include "qhbarmodelmapper.h" +#include "qvboxplotmodelmapper.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE -DeclarativeBoxSet::DeclarativeBoxSet(QObject *parent) - : QBoxSet("", parent) +DeclarativeBoxSet::DeclarativeBoxSet(const QString label, QObject *parent) + : QBoxSet(label, parent) { connect(this, SIGNAL(valuesAdded(int,int)), this, SLOT(handleCountChanged(int,int))); - connect(this, SIGNAL(valuesRemoved(int,int)), this, SLOT(handleCountChanged(int,int))); + //connect(this, SIGNAL(valuesRemoved(int,int)), this, SLOT(handleCountChanged(int,int))); } void DeclarativeBoxSet::handleCountChanged(int index, int count) @@ -56,6 +55,7 @@ void DeclarativeBoxSet::setValues(QVariantList values) } } +// Declarative box&whiskers series ===================================================== DeclarativeBoxPlotSeries::DeclarativeBoxPlotSeries(QDeclarativeItem *parent) : QBoxPlotSeries(parent), @@ -76,13 +76,13 @@ void DeclarativeBoxPlotSeries::componentComplete() foreach (QObject *child, children()) { if (qobject_cast(child)) { QBoxPlotSeries::append(qobject_cast(child)); - } else if (qobject_cast(child)) { - QVBarModelMapper *mapper = qobject_cast(child); + } else if (qobject_cast(child)) { + QVBoxPlotModelMapper *mapper = qobject_cast(child); + mapper->setSeries(this); + }// else if (qobject_cast(child)) { // TODO: Horisontal + //QHBarModelMapper *mapper = qobject_cast(child); //TODO //mapper->setSeries(this); - } else if (qobject_cast(child)) { - QHBarModelMapper *mapper = qobject_cast(child); - //mapper->setSeries(this); - } + //} } } @@ -100,6 +100,7 @@ void DeclarativeBoxPlotSeries::appendSeriesChildren(QDeclarativeListProperty setList = boxSets(); if (index >= 0 && index < setList.count()) return qobject_cast(setList[index]); @@ -107,9 +108,9 @@ DeclarativeBoxSet *DeclarativeBoxPlotSeries::at(int index) return 0; } -DeclarativeBoxSet *DeclarativeBoxPlotSeries::insert(int index, QVariantList values) +DeclarativeBoxSet *DeclarativeBoxPlotSeries::insert(int index, const QString label, QVariantList values) { - DeclarativeBoxSet *barset = new DeclarativeBoxSet(this); + DeclarativeBoxSet *barset = new DeclarativeBoxSet(label, this); barset->setValues(values); if (QBoxPlotSeries::insert(index, barset)) return barset; diff --git a/plugins/declarative/declarativeboxplotseries.h b/plugins/declarative/declarativeboxplotseries.h index 7fac07a..eed2ea1 100644 --- a/plugins/declarative/declarativeboxplotseries.h +++ b/plugins/declarative/declarativeboxplotseries.h @@ -33,10 +33,16 @@ class DeclarativeBoxSet : public QBoxSet { Q_OBJECT Q_PROPERTY(QVariantList values READ values WRITE setValues) + Q_PROPERTY(QString label READ label WRITE setLabel) Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_PROPERTY(qreal lowerExtreme READ lowerExtreme WRITE setLowerExtreme) + Q_PROPERTY(qreal lowerQuartile READ lowerQuartile WRITE setLowerQuartile) + Q_PROPERTY(qreal median READ median WRITE setMedian) + Q_PROPERTY(qreal upperQuartile READ upperQuartile WRITE setUpperQuartile) + Q_PROPERTY(qreal upperExtreme READ upperExtreme WRITE setUpperExtreme) public: - explicit DeclarativeBoxSet(QObject *parent = 0); + explicit DeclarativeBoxSet(const QString label = "", QObject *parent = 0); QVariantList values(); void setValues(QVariantList values); @@ -77,8 +83,9 @@ public: public: Q_INVOKABLE DeclarativeBoxSet *at(int index); - Q_INVOKABLE DeclarativeBoxSet *append(QVariantList values) { return insert(count(), values); } - Q_INVOKABLE DeclarativeBoxSet *insert(int index, QVariantList values); + Q_INVOKABLE DeclarativeBoxSet *append(const QString label, QVariantList values) { return insert(count(), label, values); } + Q_INVOKABLE void append(DeclarativeBoxSet *box) { QBoxPlotSeries::append(box); } + Q_INVOKABLE DeclarativeBoxSet *insert(int index, const QString label, QVariantList values); Q_INVOKABLE bool remove(QBoxSet *boxset) { return QBoxPlotSeries::remove(boxset); } Q_INVOKABLE void clear() { return QBoxPlotSeries::clear(); } diff --git a/src/boxplotchart/boxplotchartitem.cpp b/src/boxplotchart/boxplotchartitem.cpp index 7fb1531..b201dff 100644 --- a/src/boxplotchart/boxplotchartitem.cpp +++ b/src/boxplotchart/boxplotchartitem.cpp @@ -33,7 +33,9 @@ BoxPlotChartItem::BoxPlotChartItem(QBoxPlotSeries *series, QGraphicsItem* item) ChartItem(series->d_func(), item), m_series(series), m_animation(0), - m_animate(0) + m_animate(0), + m_domainMaxY(0.0), + m_domainMinY(0.0) { connect(series, SIGNAL(boxsetsRemoved(QList)), this, SLOT(handleBoxsetRemove(QList))); connect(series->d_func(), SIGNAL(restructuredBoxes()), this, SLOT(handleDataStructureChanged())); @@ -151,6 +153,12 @@ void BoxPlotChartItem::handleDomainUpdated() foreach (BoxWhiskers *item, m_boxTable.values()) { // Update the domain size for each BoxWhisker item item->setDomainSize(domain()->size()); + if (domain()->minY() != m_domainMinY || domain()->maxY() != m_domainMaxY) { + item->updateGeometry(); + m_domainMinY = domain()->minY(); + m_domainMaxY = domain()->maxY(); + qDebug() << "Updating"; + } // If the animation is set, start the animation for each BoxWhisker item if (m_animation) { diff --git a/src/boxplotchart/boxplotchartitem_p.h b/src/boxplotchart/boxplotchartitem_p.h index 5453036..7eefb67 100644 --- a/src/boxplotchart/boxplotchartitem_p.h +++ b/src/boxplotchart/boxplotchartitem_p.h @@ -76,6 +76,8 @@ protected: BoxPlotAnimation *m_animation; bool m_animate; + qreal m_domainMaxY; + qreal m_domainMinY; QRectF m_boundingRect; diff --git a/src/boxplotchart/boxwhiskers.cpp b/src/boxplotchart/boxwhiskers.cpp index 805657a..242ffb9 100644 --- a/src/boxplotchart/boxwhiskers.cpp +++ b/src/boxplotchart/boxwhiskers.cpp @@ -117,7 +117,8 @@ void BoxWhiskers::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio //painter->setClipRect(parentItem()->boundingRect()); painter->setPen(m_pen); painter->setBrush(m_brush); - qreal spanY = m_data.m_maxY - m_data.m_minY; + //qreal spanY = m_data.m_maxY - m_data.m_minY; + qreal spanY = m_domain->maxY() - m_domain->minY(); //painter->setClipRect(parentItem()->boundingRect()); painter->scale(m_domainSize.width() / m_data.m_boxItems, m_domainSize.height() / spanY); painter->drawPath(m_boxPath); @@ -134,55 +135,71 @@ void BoxWhiskers::updateGeometry() qreal left = 0.25 * columnWidth + columnWidth * m_data.m_seriesIndex; qreal right = 0.75 * columnWidth + columnWidth * m_data.m_seriesIndex; qreal middle = 0.5 * columnWidth + columnWidth * m_data.m_seriesIndex; + qreal domainMaxY = m_domain->maxY(); + qreal domainMinY = m_domain->minY(); + + qreal tmpUE = m_data.m_upperExtreme; + if (tmpUE > domainMaxY) tmpUE = domainMaxY; + if (tmpUE < domainMinY) tmpUE = domainMinY; + qreal tmpUQ = m_data.m_upperQuartile; + if (tmpUQ > domainMaxY) tmpUQ = domainMaxY; + if (tmpUQ < domainMinY) tmpUQ = domainMinY; + qreal tmpLQ = m_data.m_lowerQuartile; + if (tmpLQ > domainMaxY) tmpLQ = domainMaxY; + if (tmpLQ < domainMinY) tmpLQ = domainMinY; + qreal tmpLE = m_data.m_lowerExtreme; + if (tmpLE > domainMaxY) tmpLE = domainMaxY; + if (tmpLE < domainMinY) tmpLE = domainMinY; //whisker = 0.35 0.75 // Upper whisker - path.moveTo(left + m_data.m_index, m_data.m_maxY - m_data.m_upperExtreme); - path.lineTo(right + m_data.m_index, m_data.m_maxY - m_data.m_upperExtreme); - path.moveTo(middle + m_data.m_index, m_data.m_maxY - m_data.m_upperExtreme); - path.lineTo(middle + m_data.m_index, m_data.m_maxY - m_data.m_upperQuartile); - path.closeSubpath(); + if (m_data.m_upperExtreme <= domainMaxY && m_data.m_upperExtreme >= domainMinY) { + path.moveTo(left + m_data.m_index, domainMaxY - m_data.m_upperExtreme); + path.lineTo(right + m_data.m_index, domainMaxY - m_data.m_upperExtreme); + } + if ((tmpUE - tmpUQ) > 0.0) { + path.moveTo(middle + m_data.m_index, domainMaxY - tmpUE); + path.lineTo(middle + m_data.m_index, domainMaxY - tmpUQ); + path.closeSubpath(); + } // Middle Box - path.addRect(left + m_data.m_index, m_data.m_maxY - m_data.m_upperQuartile, - 0.5 * columnWidth, m_data.m_upperQuartile - m_data.m_lowerQuartile); + if ((tmpUQ - tmpLQ) > 0.0) + path.addRect(left + m_data.m_index, domainMaxY - tmpUQ, 0.5 * columnWidth, tmpUQ - tmpLQ); // Median/mean line - path.moveTo(left + m_data.m_index, m_data.m_maxY - m_data.m_median); - path.lineTo(right + m_data.m_index, m_data.m_maxY - m_data.m_median); + if (m_data.m_median < domainMaxY && m_data.m_median > domainMinY) { + path.moveTo(left + m_data.m_index, domainMaxY - m_data.m_median); + path.lineTo(right + m_data.m_index, domainMaxY - m_data.m_median); + } // Lower whisker - path.moveTo(left + m_data.m_index, m_data.m_maxY - m_data.m_lowerExtreme); - path.lineTo(right + m_data.m_index, m_data.m_maxY - m_data.m_lowerExtreme); - path.moveTo(middle + m_data.m_index, m_data.m_maxY - m_data.m_lowerExtreme); - path.lineTo(middle + m_data.m_index, m_data.m_maxY - m_data.m_lowerQuartile); + if (m_data.m_lowerExtreme <= domainMaxY && m_data.m_lowerExtreme >= domainMinY) { + path.moveTo(left + m_data.m_index, domainMaxY - m_data.m_lowerExtreme); + path.lineTo(right + m_data.m_index, domainMaxY - m_data.m_lowerExtreme); + } + if ((tmpLQ - tmpLE) > 0.0) { + path.moveTo(middle + m_data.m_index, domainMaxY - tmpLE); + path.lineTo(middle + m_data.m_index, domainMaxY - tmpLQ); + } + path.closeSubpath(); m_boxPath = path; updateBoundingRect(); - -// qreal scaleY = m_domainSize.height() / (m_data.m_maxY - m_data.m_minY); -// qreal scaleX = m_domainSize.width() / m_data.m_boxItems; -// QRectF br = path.boundingRect(); -// m_boundingRect = QRectF( br.x() * scaleX, br.y() * scaleY, br.width() * scaleX, br.height() * scaleY); - - if (m_data.m_index == 5) { - //qDebug() << "myValue = " << myValue; - //qDebug() << "m_data.m_upperExtreme" << m_data.m_upperExtreme; - //qDebug() << "m_boundingRect = " << m_boundingRect; -// qDebug() << "x = " << m_boundingRect.x() << ", y = " << m_boundingRect.y() << ", width = " -// << m_boundingRect.width() << ", height = " << m_boundingRect.height(); - } } void BoxWhiskers::updateBoundingRect() { - qreal scaleY = m_domainSize.height() / (m_data.m_maxY - m_data.m_minY); + //qreal scaleY = m_domainSize.height() / (m_data.m_maxY - m_data.m_minY); + qreal scaleY = m_domainSize.height() / (m_domain->maxY() - m_domain->minY()); qreal scaleX = m_domainSize.width() / m_data.m_boxItems; QRectF br = m_boxPath.boundingRect(); - m_boundingRect = QRectF( br.x() * scaleX, br.y() * scaleY, br.width() * scaleX, br.height() * scaleY); + + m_boundingRect = QRectF( br.x() * scaleX, br.y() * scaleY, + br.width() * scaleX, br.height() * scaleY); } #include "moc_boxwhiskers_p.cpp"