Skip to content

Commit

Permalink
[zonal statistics] add variance statistic
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn committed Jun 29, 2017
1 parent 8379f9b commit 58f6f93
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 5 deletions.
1 change: 1 addition & 0 deletions python/analysis/vector/qgszonalstatistics.sip
Expand Up @@ -36,6 +36,7 @@ class QgsZonalStatistics
Minority,
Majority,
Variety,
Variance,
All
};
typedef QFlags<QgsZonalStatistics::Statistic> Statistics;
Expand Down
24 changes: 20 additions & 4 deletions src/analysis/vector/qgszonalstatistics.cpp
Expand Up @@ -158,6 +158,13 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
QgsField varietyField( varietyFieldName, QVariant::Int, QStringLiteral( "int" ) );
newFieldList.push_back( varietyField );
}
QString varianceFieldName;
if ( mStatistics & QgsZonalStatistics::Variance )
{
varianceFieldName = getUniqueFieldName( mAttributePrefix + "variance", newFieldList );
QgsField varianceField( varianceFieldName, QVariant::Double, QStringLiteral( "double precision" ) );
newFieldList.push_back( varianceField );
}
vectorProvider->addAttributes( newFieldList );

//index of the new fields
Expand All @@ -172,6 +179,7 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
int minorityIndex = mStatistics & QgsZonalStatistics::Minority ? vectorProvider->fieldNameIndex( minorityFieldName ) : -1;
int majorityIndex = mStatistics & QgsZonalStatistics::Majority ? vectorProvider->fieldNameIndex( majorityFieldName ) : -1;
int varietyIndex = mStatistics & QgsZonalStatistics::Variety ? vectorProvider->fieldNameIndex( varietyFieldName ) : -1;
int varianceIndex = mStatistics & QgsZonalStatistics::Variance ? vectorProvider->fieldNameIndex( varianceFieldName ) : -1;

if ( ( mStatistics & QgsZonalStatistics::Count && countIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Sum && sumIndex == -1 )
Expand All @@ -184,6 +192,7 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
|| ( mStatistics & QgsZonalStatistics::Minority && minorityIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Majority && majorityIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Variety && varietyIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Variance && varianceIndex == -1 )
)
{
//failed to create a required field
Expand All @@ -200,7 +209,8 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
QgsFeature f;

bool statsStoreValues = ( mStatistics & QgsZonalStatistics::Median ) ||
( mStatistics & QgsZonalStatistics::StDev );
( mStatistics & QgsZonalStatistics::StDev ) ||
( mStatistics & QgsZonalStatistics::Variance );
bool statsStoreValueCount = ( mStatistics & QgsZonalStatistics::Minority ) ||
( mStatistics & QgsZonalStatistics::Majority );

Expand Down Expand Up @@ -288,16 +298,22 @@ int QgsZonalStatistics::calculateStatistics( QgsFeedback *feedback )
}
changeAttributeMap.insert( medianIndex, QVariant( medianValue ) );
}
if ( mStatistics & QgsZonalStatistics::StDev )
if ( mStatistics & QgsZonalStatistics::StDev || mStatistics & QgsZonalStatistics::Variance )
{
double sumSquared = 0;
for ( int i = 0; i < featureStats.values.count(); ++i )
{
double diff = featureStats.values.at( i ) - mean;
sumSquared += diff * diff;
}
double stdev = qPow( sumSquared / featureStats.values.count(), 0.5 );
changeAttributeMap.insert( stdevIndex, QVariant( stdev ) );
double variance = sumSquared / featureStats.values.count();
if ( mStatistics & QgsZonalStatistics::StDev )
{
double stdev = qPow( variance, 0.5 );
changeAttributeMap.insert( stdevIndex, QVariant( stdev ) );
}
if ( mStatistics & QgsZonalStatistics::Variance )
changeAttributeMap.insert( varianceIndex, QVariant( variance ) );
}
if ( mStatistics & QgsZonalStatistics::Min )
changeAttributeMap.insert( minIndex, QVariant( featureStats.min ) );
Expand Down
3 changes: 2 additions & 1 deletion src/analysis/vector/qgszonalstatistics.h
Expand Up @@ -55,7 +55,8 @@ class ANALYSIS_EXPORT QgsZonalStatistics
Minority = 256, //!< Minority of pixel values
Majority = 512, //!< Majority of pixel values
Variety = 1024, //!< Variety (count of distinct) pixel values
All = Count | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety
Variance = 2048, //!< Variance of pixel values
All = Count | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety | Variance
};
Q_DECLARE_FLAGS( Statistics, Statistic )

Expand Down
6 changes: 6 additions & 0 deletions tests/src/analysis/testqgszonalstatistics.cpp
Expand Up @@ -94,6 +94,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "minority" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "majority" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "variety" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "variance" ).toDouble(), 0.222222222222222 );

request.setFilterFid( 1 );
fetched = mVectorLayer->getFeatures( request ).nextFeature( f );
Expand All @@ -109,6 +110,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "minority" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "majority" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "variety" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "variance" ).toDouble(), 0.24691358024691 );

request.setFilterFid( 2 );
fetched = mVectorLayer->getFeatures( request ).nextFeature( f );
Expand All @@ -124,6 +126,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "minority" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "majority" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "variety" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "variance" ).toDouble(), 0.13888888888889 );

// same with long prefix to ensure that field name truncation handled correctly
QgsZonalStatistics zsl( mVectorLayer, mRasterLayer, QStringLiteral( "myqgis2_" ), 1, QgsZonalStatistics::All );
Expand All @@ -143,6 +146,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "myqgis2__2" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "myqgis2__3" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "myqgis2_va" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "myqgis2__4" ).toDouble(), 0.222222222222222 );

request.setFilterFid( 1 );
fetched = mVectorLayer->getFeatures( request ).nextFeature( f );
Expand All @@ -158,6 +162,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "myqgis2__2" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "myqgis2__3" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "myqgis2_va" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "myqgis2__4" ).toDouble(), 0.24691358024691 );

request.setFilterFid( 2 );
fetched = mVectorLayer->getFeatures( request ).nextFeature( f );
Expand All @@ -173,6 +178,7 @@ void TestQgsZonalStatistics::testStatistics()
QCOMPARE( f.attribute( "myqgis2__2" ).toDouble(), 0.0 );
QCOMPARE( f.attribute( "myqgis2__3" ).toDouble(), 1.0 );
QCOMPARE( f.attribute( "myqgis2_va" ).toDouble(), 2.0 );
QCOMPARE( f.attribute( "myqgis2__4" ).toDouble(), 0.13888888888889 );
}

QGSTEST_MAIN( TestQgsZonalStatistics )
Expand Down

0 comments on commit 58f6f93

Please sign in to comment.