Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FEATURE] Allow selection of wanted stats for zonal stats (fix #4429)
  • Loading branch information
nyalldawson committed Apr 20, 2015
1 parent 634641a commit e01dca7
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 27 deletions.
63 changes: 41 additions & 22 deletions src/analysis/vector/qgszonalstatistics.cpp
Expand Up @@ -30,12 +30,13 @@
#define TO8F(x) QFile::encodeName( x ).constData()
#endif

QgsZonalStatistics::QgsZonalStatistics( QgsVectorLayer* polygonLayer, const QString& rasterFile, const QString& attributePrefix, int rasterBand )
QgsZonalStatistics::QgsZonalStatistics( QgsVectorLayer* polygonLayer, const QString& rasterFile, const QString& attributePrefix, int rasterBand , Statistics stats )
: mRasterFilePath( rasterFile )
, mRasterBand( rasterBand )
, mPolygonLayer( polygonLayer )
, mAttributePrefix( attributePrefix )
, mInputNodataValue( -1 )
, mStatistics( stats )
{

}
Expand All @@ -44,6 +45,7 @@ QgsZonalStatistics::QgsZonalStatistics()
: mRasterBand( 0 )
, mPolygonLayer( 0 )
, mInputNodataValue( -1 )
, mStatistics( QgsZonalStatistics::All )
{

}
Expand Down Expand Up @@ -110,26 +112,41 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
QgsRectangle rasterBBox( geoTransform[0], geoTransform[3] - ( nCellsYGDAL * cellsizeY ),
geoTransform[0] + ( nCellsXGDAL * cellsizeX ), geoTransform[3] );

//add the new count, sum, mean fields to the provider
//add the new fields to the provider
QList<QgsField> newFieldList;
QString countFieldName = getUniqueFieldName( mAttributePrefix + "count" );
QString sumFieldName = getUniqueFieldName( mAttributePrefix + "sum" );
QString meanFieldName = getUniqueFieldName( mAttributePrefix + "mean" );
QgsField countField( countFieldName, QVariant::Double, "double precision" );
QgsField sumField( sumFieldName, QVariant::Double, "double precision" );
QgsField meanField( meanFieldName, QVariant::Double, "double precision" );
newFieldList.push_back( countField );
newFieldList.push_back( sumField );
newFieldList.push_back( meanField );
QString countFieldName;
if ( mStatistics & QgsZonalStatistics::Count )
{
countFieldName = getUniqueFieldName( mAttributePrefix + "count" );
QgsField countField( countFieldName, QVariant::Double, "double precision" );
newFieldList.push_back( countField );
}
QString sumFieldName;
if ( mStatistics & QgsZonalStatistics::Sum )
{
sumFieldName = getUniqueFieldName( mAttributePrefix + "sum" );
QgsField sumField( sumFieldName, QVariant::Double, "double precision" );
newFieldList.push_back( sumField );
}
QString meanFieldName;
if ( mStatistics & QgsZonalStatistics::Mean )
{
meanFieldName = getUniqueFieldName( mAttributePrefix + "mean" );
QgsField meanField( meanFieldName, QVariant::Double, "double precision" );
newFieldList.push_back( meanField );
}
vectorProvider->addAttributes( newFieldList );

//index of the new fields
int countIndex = vectorProvider->fieldNameIndex( countFieldName );
int sumIndex = vectorProvider->fieldNameIndex( sumFieldName );
int meanIndex = vectorProvider->fieldNameIndex( meanFieldName );
int countIndex = mStatistics & QgsZonalStatistics::Count ? vectorProvider->fieldNameIndex( countFieldName ) : -1;
int sumIndex = mStatistics & QgsZonalStatistics::Sum ? vectorProvider->fieldNameIndex( sumFieldName ) : -1;
int meanIndex = mStatistics & QgsZonalStatistics::Mean ? vectorProvider->fieldNameIndex( meanFieldName ) : -1;

if ( countIndex == -1 || sumIndex == -1 || meanIndex == -1 )
if (( mStatistics & QgsZonalStatistics::Count && countIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Sum && sumIndex == -1 )
|| ( mStatistics & QgsZonalStatistics::Mean && meanIndex == -1 ) )
{
//failed to create a required field
return 8;
}

Expand Down Expand Up @@ -204,22 +221,24 @@ int QgsZonalStatistics::calculateStatistics( QProgressDialog* p )
rasterBBox, sum, count );
}


if ( count == 0 )
if ( mStatistics & QgsZonalStatistics::Mean && count > 0 )
{
mean = 0;
mean = sum / count;
}
else
{
mean = sum / count;
mean = 0;
}

//write the statistics value to the vector data provider
QgsChangedAttributesMap changeMap;
QgsAttributeMap changeAttributeMap;
changeAttributeMap.insert( countIndex, QVariant( count ) );
changeAttributeMap.insert( sumIndex, QVariant( sum ) );
changeAttributeMap.insert( meanIndex, QVariant( mean ) );
if ( mStatistics & QgsZonalStatistics::Count )
changeAttributeMap.insert( countIndex, QVariant( count ) );
if ( mStatistics & QgsZonalStatistics::Sum )
changeAttributeMap.insert( sumIndex, QVariant( sum ) );
if ( mStatistics & QgsZonalStatistics::Mean )
changeAttributeMap.insert( meanIndex, QVariant( mean ) );
changeMap.insert( f.id(), changeAttributeMap );
vectorProvider->changeAttributeValues( changeMap );

Expand Down
18 changes: 16 additions & 2 deletions src/analysis/vector/qgszonalstatistics.h
Expand Up @@ -29,7 +29,19 @@ class QProgressDialog;
class ANALYSIS_EXPORT QgsZonalStatistics
{
public:
QgsZonalStatistics( QgsVectorLayer* polygonLayer, const QString& rasterFile, const QString& attributePrefix = "", int rasterBand = 1 );

//! Enumeration of flags that specify statistics to be calculated
enum Statistic
{
Count = 0x01, //!< Pixel count
Sum = 0x02, //!< Sum of pixel values
Mean = 0x04, //!< Mean of pixel values
All = Count | Sum | Mean
};
Q_DECLARE_FLAGS( Statistics, Statistic )

QgsZonalStatistics( QgsVectorLayer* polygonLayer, const QString& rasterFile, const QString& attributePrefix = "", int rasterBand = 1,
Statistics stats = Statistic::All );
~QgsZonalStatistics();

/**Starts the calculation
Expand Down Expand Up @@ -66,7 +78,9 @@ class ANALYSIS_EXPORT QgsZonalStatistics
QString mAttributePrefix;
/**The nodata value of the input layer*/
float mInputNodataValue;

Statistics mStatistics;
};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsZonalStatistics::Statistics )

#endif // QGSZONALSTATISTICS_H
31 changes: 31 additions & 0 deletions src/plugins/zonal_statistics/qgszonalstatisticsdialog.cpp
Expand Up @@ -23,11 +23,28 @@
#include "qgisinterface.h"

#include <QSettings>
#include <QListWidgetItem>

QgsZonalStatisticsDialog::QgsZonalStatisticsDialog( QgisInterface* iface ): QDialog( iface->mainWindow() ), mIface( iface )
{
setupUi( this );

QListWidgetItem* countItem = new QListWidgetItem( tr( "Count" ), mStatsListWidget );
countItem->setFlags( countItem->flags() | Qt::ItemIsUserCheckable );
countItem->setCheckState( Qt::Checked );
countItem->setData( Qt::UserRole, QgsZonalStatistics::Count );
mStatsListWidget->addItem( countItem );
QListWidgetItem* sumItem = new QListWidgetItem( tr( "Sum" ), mStatsListWidget );
sumItem->setFlags( sumItem->flags() | Qt::ItemIsUserCheckable );
sumItem->setCheckState( Qt::Checked );
sumItem->setData( Qt::UserRole, QgsZonalStatistics::Sum );
mStatsListWidget->addItem( sumItem );
QListWidgetItem* meanItem = new QListWidgetItem( tr( "Mean" ), mStatsListWidget );
meanItem->setFlags( meanItem->flags() | Qt::ItemIsUserCheckable );
meanItem->setCheckState( Qt::Checked );
meanItem->setData( Qt::UserRole, QgsZonalStatistics::Mean );
mStatsListWidget->addItem( meanItem );

QSettings settings;
restoreGeometry( settings.value( "Plugin-ZonalStatistics/geometry" ).toByteArray() );

Expand Down Expand Up @@ -107,6 +124,20 @@ QString QgsZonalStatisticsDialog::attributePrefix() const
return mColumnPrefixLineEdit->text();
}

QgsZonalStatistics::Statistics QgsZonalStatisticsDialog::selectedStats() const
{
QgsZonalStatistics::Statistics stats = 0;
for ( int i = 0; i < mStatsListWidget->count(); ++i )
{
QListWidgetItem* item = mStatsListWidget->item( i );
if ( item->checkState() == Qt::Checked )
{
stats |= ( QgsZonalStatistics::Statistic )( item->data( Qt::UserRole ).toInt() );
}
}
return stats;
}

QString QgsZonalStatisticsDialog::proposeAttributePrefix() const
{
if ( !polygonLayer() )
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/zonal_statistics/qgszonalstatisticsdialog.h
Expand Up @@ -19,6 +19,7 @@
#define QGSZONALSTATISTICSDIALOG_H

#include "ui_qgszonalstatisticsdialogbase.h"
#include "qgszonalstatistics.h"

class QgisInterface;
class QgsVectorLayer;
Expand All @@ -34,6 +35,7 @@ class QgsZonalStatisticsDialog: public QDialog, private Ui::QgsZonalStatisticsDi
int rasterBand() const {return 1;} //todo: expose that in the GUI
QgsVectorLayer* polygonLayer() const;
QString attributePrefix() const;
QgsZonalStatistics::Statistics selectedStats() const;

private:
QgsZonalStatisticsDialog();
Expand Down
14 changes: 12 additions & 2 deletions src/plugins/zonal_statistics/qgszonalstatisticsdialogbase.ui
Expand Up @@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>240</width>
<height>193</height>
<width>254</width>
<height>320</height>
</rect>
</property>
<property name="windowTitle">
Expand Down Expand Up @@ -48,6 +48,16 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Statistics to calculate:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="mStatsListWidget"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/zonal_statistics/qgszonalstatisticsplugin.cpp
Expand Up @@ -72,7 +72,7 @@ void QgsZonalStatisticsPlugin::run()
return;
}

QgsZonalStatistics zs( vl, rasterFile, d.attributePrefix(), 1 ); //atm hardcode first band
QgsZonalStatistics zs( vl, rasterFile, d.attributePrefix(), 1, d.selectedStats() ); //atm hardcode first band
QProgressDialog p( tr( "Calculating zonal statistics..." ), tr( "Abort..." ), 0, 0 );
p.setWindowModality( Qt::WindowModal );
zs.calculateStatistics( &p );
Expand Down

0 comments on commit e01dca7

Please sign in to comment.