mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-05 00:04:40 -05:00
Allow calculating aggregates using a subset of fids only
This commit is contained in:
parent
6c6c145590
commit
a02a4ede6e
@ -95,6 +95,16 @@ Sets a filter to limit the features used during the aggregate calculation.
|
||||
|
||||
:param filterExpression: expression for filtering features, or empty string to remove filter
|
||||
|
||||
.. seealso:: :py:func:`filter`
|
||||
%End
|
||||
|
||||
void setFidsFilter( const QgsFeatureIds &fids );
|
||||
%Docstring
|
||||
Sets a filter to limit the features used during the aggregate calculation.
|
||||
If an expression filter is set, it will override this filter.
|
||||
|
||||
:param fids: feature ids for feature filtering, and empty list will return no features.
|
||||
|
||||
.. seealso:: :py:func:`filter`
|
||||
%End
|
||||
|
||||
@ -154,7 +164,6 @@ Structured information for available aggregates.
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
|
||||
@ -206,7 +206,8 @@ matching is done in a case-insensitive manner.
|
||||
int index,
|
||||
const QgsAggregateCalculator::AggregateParameters ¶meters,
|
||||
QgsExpressionContext *context,
|
||||
bool &ok ) const;
|
||||
bool &ok,
|
||||
QgsFeatureIds *fids = 0 ) const;
|
||||
%Docstring
|
||||
Calculates an aggregated value from the layer's features. The base implementation does nothing,
|
||||
but subclasses can override this method to handoff calculation of aggregates to the provider.
|
||||
@ -216,6 +217,7 @@ but subclasses can override this method to handoff calculation of aggregates to
|
||||
:param parameters: parameters controlling aggregate calculation
|
||||
:param context: expression context for filter
|
||||
:param ok: will be set to ``True`` if calculation was successfully performed by the data provider
|
||||
:param fids: list of fids to filter, otherwise will use all fids
|
||||
|
||||
:return: calculated aggregate value
|
||||
|
||||
|
||||
@ -2101,15 +2101,18 @@ been changed inside the edit buffer then the previous saved value may be returne
|
||||
const QString &fieldOrExpression,
|
||||
const QgsAggregateCalculator::AggregateParameters ¶meters = QgsAggregateCalculator::AggregateParameters(),
|
||||
QgsExpressionContext *context = 0,
|
||||
bool *ok = 0 ) const;
|
||||
bool *ok = 0,
|
||||
QgsFeatureIds *fids = 0 ) const;
|
||||
%Docstring
|
||||
Calculates an aggregated value from the layer's features.
|
||||
Currently any filtering expression provided will override filters in the FeatureRequest.
|
||||
|
||||
:param aggregate: aggregate to calculate
|
||||
:param fieldOrExpression: source field or expression to use as basis for aggregated values.
|
||||
:param parameters: parameters controlling aggregate calculation
|
||||
:param context: expression context for expressions and filters
|
||||
:param ok: if specified, will be set to ``True`` if aggregate calculation was successful
|
||||
:param fids: list of fids to filter, otherwise will use all fids
|
||||
|
||||
:return: calculated aggregate value
|
||||
|
||||
|
||||
@ -42,13 +42,20 @@ void QgsAggregateCalculator::setParameters( const AggregateParameters ¶meter
|
||||
mOrderBy = parameters.orderBy;
|
||||
}
|
||||
|
||||
void QgsAggregateCalculator::setFidsFilter( const QgsFeatureIds &fids )
|
||||
{
|
||||
mFidsSet = true;
|
||||
mFidsFilter = fids;
|
||||
}
|
||||
|
||||
QVariant QgsAggregateCalculator::calculate( QgsAggregateCalculator::Aggregate aggregate,
|
||||
const QString &fieldOrExpression,
|
||||
QgsExpressionContext *context, bool *ok ) const
|
||||
const QString &fieldOrExpression, QgsExpressionContext *context, bool *ok ) const
|
||||
{
|
||||
if ( ok )
|
||||
*ok = false;
|
||||
|
||||
QgsFeatureRequest request = QgsFeatureRequest();
|
||||
|
||||
if ( !mLayer )
|
||||
return QVariant();
|
||||
|
||||
@ -67,9 +74,7 @@ QVariant QgsAggregateCalculator::calculate( QgsAggregateCalculator::Aggregate ag
|
||||
expression.reset( new QgsExpression( fieldOrExpression ) );
|
||||
|
||||
if ( expression->hasParserError() || !expression->prepare( context ) )
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QSet<QString> lst;
|
||||
@ -78,18 +83,21 @@ QVariant QgsAggregateCalculator::calculate( QgsAggregateCalculator::Aggregate ag
|
||||
else
|
||||
lst = expression->referencedColumns();
|
||||
|
||||
QgsFeatureRequest request = QgsFeatureRequest()
|
||||
.setFlags( ( expression && expression->needsGeometry() ) ?
|
||||
QgsFeatureRequest::NoFlags :
|
||||
QgsFeatureRequest::NoGeometry )
|
||||
.setSubsetOfAttributes( lst, mLayer->fields() );
|
||||
request.setFlags( ( expression && expression->needsGeometry() ) ?
|
||||
QgsFeatureRequest::NoFlags :
|
||||
QgsFeatureRequest::NoGeometry )
|
||||
.setSubsetOfAttributes( lst, mLayer->fields() );
|
||||
|
||||
if ( mFidsSet )
|
||||
request.setFilterFids( mFidsFilter );
|
||||
|
||||
if ( !mOrderBy.empty() )
|
||||
request.setOrderBy( mOrderBy );
|
||||
|
||||
if ( !mFilterExpression.isEmpty() )
|
||||
request.setFilterExpression( mFilterExpression );
|
||||
if ( context )
|
||||
request.setExpressionContext( *context );
|
||||
|
||||
//determine result type
|
||||
QVariant::Type resultType = QVariant::Double;
|
||||
if ( attrNum == -1 )
|
||||
@ -113,9 +121,7 @@ QVariant QgsAggregateCalculator::calculate( QgsAggregateCalculator::Aggregate ag
|
||||
resultType = v.type();
|
||||
}
|
||||
else
|
||||
{
|
||||
resultType = mLayer->fields().at( attrNum ).type();
|
||||
}
|
||||
|
||||
QgsFeatureIterator fit = mLayer->getFeatures( request );
|
||||
return calculate( aggregate, fit, resultType, attrNum, expression.get(), mDelimiter, context, ok );
|
||||
@ -846,3 +852,4 @@ QVariant QgsAggregateCalculator::calculateArrayAggregate( QgsFeatureIterator &fi
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "qgsstringstatisticalsummary.h"
|
||||
#include "qgsfeaturerequest.h"
|
||||
#include <QVariant>
|
||||
#include "qgsfeatureid.h"
|
||||
|
||||
|
||||
class QgsFeatureIterator;
|
||||
@ -136,6 +137,14 @@ class CORE_EXPORT QgsAggregateCalculator
|
||||
*/
|
||||
void setFilter( const QString &filterExpression ) { mFilterExpression = filterExpression; }
|
||||
|
||||
/**
|
||||
* Sets a filter to limit the features used during the aggregate calculation.
|
||||
* If an expression filter is set, it will override this filter.
|
||||
* \param fids feature ids for feature filtering, and empty list will return no features.
|
||||
* \see filter()
|
||||
*/
|
||||
void setFidsFilter( const QgsFeatureIds &fids );
|
||||
|
||||
/**
|
||||
* Returns the filter which limits the features used during the aggregate calculation.
|
||||
* \see setFilter()
|
||||
@ -196,6 +205,12 @@ class CORE_EXPORT QgsAggregateCalculator
|
||||
//! Delimiter to use for concatenate aggregate
|
||||
QString mDelimiter;
|
||||
|
||||
//!list of fids to filter
|
||||
QgsFeatureIds mFidsFilter;
|
||||
|
||||
//trigger variable
|
||||
bool mFidsSet = false;
|
||||
|
||||
static QgsStatisticalSummary::Statistic numericStatFromAggregate( Aggregate aggregate, bool *ok = nullptr );
|
||||
static QgsStringStatisticalSummary::Statistic stringStatFromAggregate( Aggregate aggregate, bool *ok = nullptr );
|
||||
static QgsDateTimeStatisticalSummary::Statistic dateTimeStatFromAggregate( Aggregate aggregate, bool *ok = nullptr );
|
||||
@ -224,4 +239,3 @@ class CORE_EXPORT QgsAggregateCalculator
|
||||
};
|
||||
|
||||
#endif //QGSAGGREGATECALCULATOR_H
|
||||
|
||||
|
||||
@ -466,13 +466,14 @@ QStringList QgsVectorDataProvider::uniqueStringsMatching( int index, const QStri
|
||||
}
|
||||
|
||||
QVariant QgsVectorDataProvider::aggregate( QgsAggregateCalculator::Aggregate aggregate, int index,
|
||||
const QgsAggregateCalculator::AggregateParameters ¶meters, QgsExpressionContext *context, bool &ok ) const
|
||||
const QgsAggregateCalculator::AggregateParameters ¶meters, QgsExpressionContext *context, bool &ok, QgsFeatureIds *fids ) const
|
||||
{
|
||||
//base implementation does nothing
|
||||
Q_UNUSED( aggregate )
|
||||
Q_UNUSED( index )
|
||||
Q_UNUSED( parameters )
|
||||
Q_UNUSED( context )
|
||||
Q_UNUSED( fids )
|
||||
|
||||
ok = false;
|
||||
return QVariant();
|
||||
|
||||
@ -239,6 +239,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
|
||||
* \param parameters parameters controlling aggregate calculation
|
||||
* \param context expression context for filter
|
||||
* \param ok will be set to TRUE if calculation was successfully performed by the data provider
|
||||
* \param fids list of fids to filter, otherwise will use all fids
|
||||
* \returns calculated aggregate value
|
||||
* \since QGIS 2.16
|
||||
*/
|
||||
@ -246,7 +247,8 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
|
||||
int index,
|
||||
const QgsAggregateCalculator::AggregateParameters ¶meters,
|
||||
QgsExpressionContext *context,
|
||||
bool &ok ) const;
|
||||
bool &ok,
|
||||
QgsFeatureIds *fids = nullptr ) const;
|
||||
|
||||
/**
|
||||
* Returns the possible enum values of an attribute. Returns an empty stringlist if a provider does not support enum types
|
||||
|
||||
@ -3912,7 +3912,8 @@ QVariant QgsVectorLayer::maximumValue( int index ) const
|
||||
}
|
||||
|
||||
QVariant QgsVectorLayer::aggregate( QgsAggregateCalculator::Aggregate aggregate, const QString &fieldOrExpression,
|
||||
const QgsAggregateCalculator::AggregateParameters ¶meters, QgsExpressionContext *context, bool *ok ) const
|
||||
const QgsAggregateCalculator::AggregateParameters ¶meters, QgsExpressionContext *context,
|
||||
bool *ok, QgsFeatureIds *fids ) const
|
||||
{
|
||||
if ( ok )
|
||||
*ok = false;
|
||||
@ -3932,7 +3933,7 @@ QVariant QgsVectorLayer::aggregate( QgsAggregateCalculator::Aggregate aggregate,
|
||||
if ( origin == QgsFields::OriginProvider )
|
||||
{
|
||||
bool providerOk = false;
|
||||
QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk );
|
||||
QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
|
||||
if ( providerOk )
|
||||
{
|
||||
// provider handled calculation
|
||||
@ -3945,6 +3946,8 @@ QVariant QgsVectorLayer::aggregate( QgsAggregateCalculator::Aggregate aggregate,
|
||||
|
||||
// fallback to using aggregate calculator to determine aggregate
|
||||
QgsAggregateCalculator c( this );
|
||||
if ( fids )
|
||||
c.setFidsFilter( *fids );
|
||||
c.setParameters( parameters );
|
||||
return c.calculate( aggregate, fieldOrExpression, context, ok );
|
||||
}
|
||||
|
||||
@ -1925,11 +1925,13 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
|
||||
|
||||
/**
|
||||
* Calculates an aggregated value from the layer's features.
|
||||
* Currently any filtering expression provided will override filters in the FeatureRequest.
|
||||
* \param aggregate aggregate to calculate
|
||||
* \param fieldOrExpression source field or expression to use as basis for aggregated values.
|
||||
* \param parameters parameters controlling aggregate calculation
|
||||
* \param context expression context for expressions and filters
|
||||
* \param ok if specified, will be set to TRUE if aggregate calculation was successful
|
||||
* \param fids list of fids to filter, otherwise will use all fids
|
||||
* \returns calculated aggregate value
|
||||
* \since QGIS 2.16
|
||||
*/
|
||||
@ -1937,7 +1939,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
|
||||
const QString &fieldOrExpression,
|
||||
const QgsAggregateCalculator::AggregateParameters ¶meters = QgsAggregateCalculator::AggregateParameters(),
|
||||
QgsExpressionContext *context = nullptr,
|
||||
bool *ok = nullptr ) const;
|
||||
bool *ok = nullptr,
|
||||
QgsFeatureIds *fids = nullptr ) const;
|
||||
|
||||
//! Sets the blending mode used for rendering each feature
|
||||
void setFeatureBlendMode( QPainter::CompositionMode blendMode );
|
||||
|
||||
@ -416,6 +416,19 @@ class TestQgsAggregateCalculator(unittest.TestCase):
|
||||
self.assertTrue(ok)
|
||||
self.assertEqual(val, 5)
|
||||
|
||||
# test with subset
|
||||
agg = QgsAggregateCalculator(layer) # reset to remove expression filter
|
||||
agg.setFidsFilter([1, 2])
|
||||
val, ok = agg.calculate(QgsAggregateCalculator.Sum, 'fldint')
|
||||
self.assertTrue(ok)
|
||||
self.assertEqual(val, 6.0)
|
||||
|
||||
# test with empty subset
|
||||
agg.setFidsFilter(list())
|
||||
val, ok = agg.calculate(QgsAggregateCalculator.Sum, 'fldint')
|
||||
self.assertTrue(ok)
|
||||
self.assertEqual(val, 0.0)
|
||||
|
||||
def testExpressionNoMatch(self):
|
||||
""" test aggregate calculation using an expression with no features """
|
||||
|
||||
|
||||
@ -2206,6 +2206,24 @@ class TestQgsVectorLayer(unittest.TestCase, FeatureSourceTestCase):
|
||||
vals = [f['virtual'] for f in layer.getFeatures()]
|
||||
self.assertEqual(vals, [48, 48, 48, 48, 48, 48, 48])
|
||||
|
||||
def testAggregateFilter(self):
|
||||
""" Test aggregate calculation """
|
||||
layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory")
|
||||
pr = layer.dataProvider()
|
||||
|
||||
int_values = [4, 2, 3, 2, 5, None, 8]
|
||||
features = []
|
||||
for i in int_values:
|
||||
f = QgsFeature()
|
||||
f.setFields(layer.fields())
|
||||
f.setAttributes([i])
|
||||
features.append(f)
|
||||
assert pr.addFeatures(features)
|
||||
|
||||
val, ok = layer.aggregate(QgsAggregateCalculator.Sum, 'fldint', fids=[1, 2])
|
||||
self.assertTrue(ok)
|
||||
self.assertEqual(val, 6.0)
|
||||
|
||||
def onLayerOpacityChanged(self, tr):
|
||||
self.opacityTest = tr
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user