Skip to content

Commit

Permalink
Allow QgsStatisticalSummary to calculate first/last value
Browse files Browse the repository at this point in the history
Trivial, but simplifies other code which desires to expose
a choice between first/last/min/max/mean/etc...
  • Loading branch information
nyalldawson committed Jan 3, 2019
1 parent 5586352 commit 5f817b4
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 18 deletions.
20 changes: 20 additions & 0 deletions python/core/auto_generated/qgsstatisticalsummary.sip.in
Expand Up @@ -46,6 +46,8 @@ specifying the statistic in the constructor or via setStatistics().
FirstQuartile,
ThirdQuartile,
InterQuartileRange,
First,
Last,
All
};
typedef QFlags<QgsStatisticalSummary::Statistic> Statistics;
Expand Down Expand Up @@ -214,6 +216,24 @@ be calculated.
%Docstring
Returns calculated range (difference between maximum and minimum values). A NaN value may be returned if the range cannot
be calculated.
%End

double first() const;
%Docstring
Returns the first value obtained. A NaN value may be returned if no values were encountered.

.. seealso:: :py:func:`last`

.. versionadded:: 3.6
%End

double last() const;
%Docstring
Returns the last value obtained. A NaN value may be returned if no values were encountered.

.. seealso:: :py:func:`first`

.. versionadded:: 3.6
%End

double stDev() const;
Expand Down
17 changes: 16 additions & 1 deletion src/core/qgsstatisticalsummary.cpp
Expand Up @@ -32,6 +32,8 @@ QgsStatisticalSummary::QgsStatisticalSummary( Statistics stats )

void QgsStatisticalSummary::reset()
{
mFirst = std::numeric_limits<double>::quiet_NaN();
mLast = std::numeric_limits<double>::quiet_NaN();
mCount = 0;
mMissing = 0;
mSum = 0;
Expand Down Expand Up @@ -59,7 +61,7 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
{
reset();

Q_FOREACH ( double value, values )
for ( double value : values )
{
addValue( value );
}
Expand All @@ -69,10 +71,13 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )

void QgsStatisticalSummary::addValue( double value )
{
if ( mCount == 0 )
mFirst = value;
mCount++;
mSum += value;
mMin = std::min( mMin, value );
mMax = std::max( mMax, value );
mLast = value;

if ( mStatistics & QgsStatisticalSummary::Majority || mStatistics & QgsStatisticalSummary::Minority || mStatistics & QgsStatisticalSummary::Variety )
mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );
Expand Down Expand Up @@ -102,6 +107,8 @@ void QgsStatisticalSummary::finalize()
{
if ( mCount == 0 )
{
mFirst = std::numeric_limits<double>::quiet_NaN();
mLast = std::numeric_limits<double>::quiet_NaN();
mMin = std::numeric_limits<double>::quiet_NaN();
mMax = std::numeric_limits<double>::quiet_NaN();
mMean = std::numeric_limits<double>::quiet_NaN();
Expand Down Expand Up @@ -266,6 +273,10 @@ double QgsStatisticalSummary::statistic( QgsStatisticalSummary::Statistic stat )
return mThirdQuartile;
case InterQuartileRange:
return mThirdQuartile - mFirstQuartile;
case First:
return mFirst;
case Last:
return mLast;
case All:
return 0;
}
Expand Down Expand Up @@ -308,6 +319,10 @@ QString QgsStatisticalSummary::displayName( QgsStatisticalSummary::Statistic sta
return QObject::tr( "Q3" );
case InterQuartileRange:
return QObject::tr( "IQR" );
case First:
return QObject::tr( "First" );
case Last:
return QObject::tr( "Last" );
case All:
return QString();
}
Expand Down
54 changes: 37 additions & 17 deletions src/core/qgsstatisticalsummary.h
Expand Up @@ -47,23 +47,25 @@ class CORE_EXPORT QgsStatisticalSummary
//! Enumeration of flags that specify statistics to be calculated
enum Statistic
{
Count = 1, //!< Count
CountMissing = 32770, //!< Number of missing (null) values
Sum = 2, //!< Sum of values
Mean = 4, //!< Mean of values
Median = 8, //!< Median of values
StDev = 16, //!< Standard deviation of values
StDevSample = 32, //!< Sample standard deviation of values
Min = 64, //!< Min of values
Max = 128, //!< Max of values
Range = 256, //!< Range of values (max - min)
Minority = 512, //!< Minority of values
Majority = 1024, //!< Majority of values
Variety = 2048, //!< Variety (count of distinct) values
FirstQuartile = 4096, //!< First quartile
ThirdQuartile = 8192, //!< Third quartile
InterQuartileRange = 16384, //!< Inter quartile range (IQR)
All = Count | CountMissing | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety | FirstQuartile | ThirdQuartile | InterQuartileRange
Count = 1 << 0, //!< Count
CountMissing = 1 << 15, //!< Number of missing (null) values
Sum = 1 << 1, //!< Sum of values
Mean = 1 << 2, //!< Mean of values
Median = 1 << 3, //!< Median of values
StDev = 1 << 4, //!< Standard deviation of values
StDevSample = 1 << 5, //!< Sample standard deviation of values
Min = 1 << 6, //!< Min of values
Max = 1 << 7, //!< Max of values
Range = 1 << 8, //!< Range of values (max - min)
Minority = 1 << 9, //!< Minority of values
Majority = 1 << 10, //!< Majority of values
Variety = 1 << 11, //!< Variety (count of distinct) values
FirstQuartile = 1 << 12, //!< First quartile
ThirdQuartile = 1 << 13, //!< Third quartile
InterQuartileRange = 1 << 14, //!< Inter quartile range (IQR)
First = 1 << 16, //!< First value (since QGIS 3.6)
Last = 1 << 17, //!< Last value (since QGIS 3.6)
All = Count | CountMissing | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety | FirstQuartile | ThirdQuartile | InterQuartileRange | First | Last
};
Q_DECLARE_FLAGS( Statistics, Statistic )

Expand Down Expand Up @@ -199,6 +201,22 @@ class CORE_EXPORT QgsStatisticalSummary
*/
double range() const { return std::isnan( mMax ) || std::isnan( mMin ) ? std::numeric_limits<double>::quiet_NaN() : mMax - mMin; }

/**
* Returns the first value obtained. A NaN value may be returned if no values were encountered.
*
* \see last()
* \since QGIS 3.6
*/
double first() const { return mFirst; }

/**
* Returns the last value obtained. A NaN value may be returned if no values were encountered.
*
* \see first()
* \since QGIS 3.6
*/
double last() const { return mLast; }

/**
* Returns population standard deviation. This is only calculated if Statistic::StDev has
* been specified in the constructor or via setStatistics. A NaN value may be returned if the standard deviation cannot
Expand Down Expand Up @@ -290,6 +308,8 @@ class CORE_EXPORT QgsStatisticalSummary
double mMajority;
double mFirstQuartile;
double mThirdQuartile;
double mFirst;
double mLast;
QMap< double, int > mValueCount;
QList< double > mValues;
};
Expand Down
10 changes: 10 additions & 0 deletions tests/src/core/testqgsstatisticalsummary.cpp
Expand Up @@ -85,6 +85,10 @@ void TestQgsStatisticSummary::stats()
QCOMPARE( s2.sum(), 24.0 );
QCOMPARE( s.mean(), 4.0 );
QCOMPARE( s2.mean(), 4.0 );
QCOMPARE( s.first(), 4.0 );
QCOMPARE( s2.first(), 4.0 );
QCOMPARE( s.last(), 8.0 );
QCOMPARE( s2.last(), 8.0 );
QGSCOMPARENEAR( s.stDev(), 2.0816, 0.0001 );
QGSCOMPARENEAR( s2.stDev(), 2.0816, 0.0001 );
QGSCOMPARENEAR( s.sampleStDev(), 2.2803, 0.0001 );
Expand Down Expand Up @@ -227,6 +231,8 @@ void TestQgsStatisticSummary::individualStatCalculations_data()
QTest::newRow( "third_quartile" ) << ( int )QgsStatisticalSummary::ThirdQuartile << 5.0;
QTest::newRow( "iqr" ) << ( int )QgsStatisticalSummary::InterQuartileRange << 2.0;
QTest::newRow( "missing" ) << ( int )QgsStatisticalSummary::CountMissing << 0.0;
QTest::newRow( "first" ) << static_cast< int >( QgsStatisticalSummary::First ) << 4.0;
QTest::newRow( "last" ) << static_cast< int >( QgsStatisticalSummary::Last ) << 8.0;
}

void TestQgsStatisticSummary::individualStatCalculations()
Expand Down Expand Up @@ -311,6 +317,10 @@ void TestQgsStatisticSummary::noValues()
QCOMPARE( s.statistic( QgsStatisticalSummary::CountMissing ), 0.0 );
QCOMPARE( s.sum(), 0.0 );
QCOMPARE( s.statistic( QgsStatisticalSummary::Sum ), 0.0 );
QVERIFY( std::isnan( s.first() ) );
QVERIFY( std::isnan( s.statistic( QgsStatisticalSummary::First ) ) );
QVERIFY( std::isnan( s.last() ) );
QVERIFY( std::isnan( s.statistic( QgsStatisticalSummary::Last ) ) );
QVERIFY( std::isnan( s.mean() ) );
QVERIFY( std::isnan( s.statistic( QgsStatisticalSummary::Mean ) ) );
QVERIFY( std::isnan( s.median() ) );
Expand Down

0 comments on commit 5f817b4

Please sign in to comment.