mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
Merge pull request #5154 from nyalldawson/stats
[processing] Improve Stats by Categories algorithm, remove duplicate algs
This commit is contained in:
commit
7f5bd00cbf
248
python/plugins/processing/algs/qgis/StatisticsByCategories.py
Normal file → Executable file
248
python/plugins/processing/algs/qgis/StatisticsByCategories.py
Normal file → Executable file
@ -28,6 +28,8 @@ __revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import (QgsProcessingParameterFeatureSource,
|
||||
QgsStatisticalSummary,
|
||||
QgsDateTimeStatisticalSummary,
|
||||
QgsStringStatisticalSummary,
|
||||
QgsFeatureRequest,
|
||||
QgsProcessingParameterField,
|
||||
QgsProcessingParameterFeatureSink,
|
||||
@ -36,13 +38,16 @@ from qgis.core import (QgsProcessingParameterFeatureSource,
|
||||
QgsWkbTypes,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsFeature,
|
||||
QgsFeatureSink)
|
||||
QgsFeatureSink,
|
||||
QgsProcessing,
|
||||
NULL)
|
||||
from qgis.PyQt.QtCore import QVariant
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
class StatisticsByCategories(QgisAlgorithm):
|
||||
|
||||
INPUT = 'INPUT'
|
||||
VALUES_FIELD_NAME = 'VALUES_FIELD_NAME'
|
||||
CATEGORIES_FIELD_NAME = 'CATEGORIES_FIELD_NAME'
|
||||
@ -56,13 +61,16 @@ class StatisticsByCategories(QgisAlgorithm):
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
|
||||
self.tr('Input vector layer')))
|
||||
self.tr('Input vector layer'),
|
||||
types=[QgsProcessing.TypeVector]))
|
||||
self.addParameter(QgsProcessingParameterField(self.VALUES_FIELD_NAME,
|
||||
self.tr('Field to calculate statistics on'),
|
||||
parentLayerParameterName=self.INPUT, type=QgsProcessingParameterField.Numeric))
|
||||
self.tr(
|
||||
'Field to calculate statistics on (if empty, only count is calculated)'),
|
||||
parentLayerParameterName=self.INPUT, optional=True))
|
||||
self.addParameter(QgsProcessingParameterField(self.CATEGORIES_FIELD_NAME,
|
||||
self.tr('Field with categories'),
|
||||
parentLayerParameterName=self.INPUT, type=QgsProcessingParameterField.Any))
|
||||
self.tr('Field(s) with categories'),
|
||||
parentLayerParameterName=self.INPUT,
|
||||
type=QgsProcessingParameterField.Any, allowMultiple=True))
|
||||
|
||||
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Statistics by category')))
|
||||
|
||||
@ -75,49 +83,213 @@ class StatisticsByCategories(QgisAlgorithm):
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
source = self.parameterAsSource(parameters, self.INPUT, context)
|
||||
value_field_name = self.parameterAsString(parameters, self.VALUES_FIELD_NAME, context)
|
||||
category_field_name = self.parameterAsString(parameters, self.CATEGORIES_FIELD_NAME, context)
|
||||
category_field_names = self.parameterAsFields(parameters, self.CATEGORIES_FIELD_NAME, context)
|
||||
|
||||
value_field_index = source.fields().lookupField(value_field_name)
|
||||
category_field_index = source.fields().lookupField(category_field_name)
|
||||
if value_field_index >= 0:
|
||||
value_field = source.fields().at(value_field_index)
|
||||
else:
|
||||
value_field = None
|
||||
category_field_indexes = [source.fields().lookupField(n) for n in category_field_names]
|
||||
|
||||
features = source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry))
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
values = {}
|
||||
# generate output fields
|
||||
fields = QgsFields()
|
||||
for c in category_field_indexes:
|
||||
fields.append(source.fields().at(c))
|
||||
|
||||
def addField(name):
|
||||
"""
|
||||
Adds a field to the output, keeping the same data type as the value_field
|
||||
"""
|
||||
field = value_field
|
||||
field.setName(name)
|
||||
fields.append(field)
|
||||
|
||||
if value_field is None:
|
||||
field_type = 'none'
|
||||
fields.append(QgsField('count', QVariant.Int))
|
||||
elif value_field.isNumeric():
|
||||
field_type = 'numeric'
|
||||
fields.append(QgsField('count', QVariant.Int))
|
||||
fields.append(QgsField('unique', QVariant.Int))
|
||||
fields.append(QgsField('min', QVariant.Double))
|
||||
fields.append(QgsField('max', QVariant.Double))
|
||||
fields.append(QgsField('range', QVariant.Double))
|
||||
fields.append(QgsField('sum', QVariant.Double))
|
||||
fields.append(QgsField('mean', QVariant.Double))
|
||||
fields.append(QgsField('median', QVariant.Double))
|
||||
fields.append(QgsField('stddev', QVariant.Double))
|
||||
fields.append(QgsField('minority', QVariant.Double))
|
||||
fields.append(QgsField('majority', QVariant.Double))
|
||||
fields.append(QgsField('q1', QVariant.Double))
|
||||
fields.append(QgsField('q3', QVariant.Double))
|
||||
fields.append(QgsField('iqr', QVariant.Double))
|
||||
elif value_field.type() in (QVariant.Date, QVariant.Time, QVariant.DateTime):
|
||||
field_type = 'datetime'
|
||||
fields.append(QgsField('count', QVariant.Int))
|
||||
fields.append(QgsField('unique', QVariant.Int))
|
||||
fields.append(QgsField('empty', QVariant.Int))
|
||||
fields.append(QgsField('filled', QVariant.Int))
|
||||
# keep same data type for these fields
|
||||
addField('min')
|
||||
addField('max')
|
||||
else:
|
||||
field_type = 'string'
|
||||
fields.append(QgsField('count', QVariant.Int))
|
||||
fields.append(QgsField('unique', QVariant.Int))
|
||||
fields.append(QgsField('empty', QVariant.Int))
|
||||
fields.append(QgsField('filled', QVariant.Int))
|
||||
# keep same data type for these fields
|
||||
addField('min')
|
||||
addField('max')
|
||||
fields.append(QgsField('min_length', QVariant.Int))
|
||||
fields.append(QgsField('max_length', QVariant.Int))
|
||||
fields.append(QgsField('mean_length', QVariant.Double))
|
||||
|
||||
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
|
||||
if value_field is not None:
|
||||
attrs = [value_field_index]
|
||||
else:
|
||||
attrs = []
|
||||
attrs.extend(category_field_indexes)
|
||||
request.setSubsetOfAttributes(attrs)
|
||||
features = source.getFeatures(request)
|
||||
total = 50.0 / source.featureCount() if source.featureCount() else 0
|
||||
if field_type == 'none':
|
||||
values = defaultdict(lambda: 0)
|
||||
else:
|
||||
values = defaultdict(list)
|
||||
for current, feat in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
feedback.setProgress(int(current * total))
|
||||
attrs = feat.attributes()
|
||||
try:
|
||||
value = float(attrs[value_field_index])
|
||||
cat = attrs[category_field_index]
|
||||
if cat not in values:
|
||||
values[cat] = []
|
||||
values[cat].append(value)
|
||||
except:
|
||||
pass
|
||||
|
||||
fields = QgsFields()
|
||||
fields.append(source.fields().at(category_field_index))
|
||||
fields.append(QgsField('min', QVariant.Double))
|
||||
fields.append(QgsField('max', QVariant.Double))
|
||||
fields.append(QgsField('mean', QVariant.Double))
|
||||
fields.append(QgsField('stddev', QVariant.Double))
|
||||
fields.append(QgsField('sum', QVariant.Double))
|
||||
fields.append(QgsField('count', QVariant.Int))
|
||||
cat = tuple([attrs[c] for c in category_field_indexes])
|
||||
if field_type == 'none':
|
||||
values[cat] += 1
|
||||
continue
|
||||
if field_type == 'numeric':
|
||||
if attrs[value_field_index] == NULL:
|
||||
continue
|
||||
else:
|
||||
value = float(attrs[value_field_index])
|
||||
elif field_type == 'string':
|
||||
if attrs[value_field_index] == NULL:
|
||||
value = ''
|
||||
else:
|
||||
value = str(attrs[value_field_index])
|
||||
elif attrs[value_field_index] == NULL:
|
||||
value = NULL
|
||||
else:
|
||||
value = attrs[value_field_index]
|
||||
values[cat].append(value)
|
||||
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
|
||||
fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
|
||||
|
||||
stat = QgsStatisticalSummary(QgsStatisticalSummary.Min | QgsStatisticalSummary.Max |
|
||||
QgsStatisticalSummary.Mean | QgsStatisticalSummary.StDevSample |
|
||||
QgsStatisticalSummary.Sum | QgsStatisticalSummary.Count)
|
||||
|
||||
for (cat, v) in list(values.items()):
|
||||
stat.calculate(v)
|
||||
f = QgsFeature()
|
||||
f.setAttributes([cat, stat.min(), stat.max(), stat.mean(), stat.sampleStDev(), stat.sum(), stat.count()])
|
||||
sink.addFeature(f, QgsFeatureSink.FastInsert)
|
||||
if field_type == 'none':
|
||||
self.saveCounts(values, sink, feedback)
|
||||
elif field_type == 'numeric':
|
||||
self.calcNumericStats(values, sink, feedback)
|
||||
elif field_type == 'datetime':
|
||||
self.calcDateTimeStats(values, sink, feedback)
|
||||
else:
|
||||
self.calcStringStats(values, sink, feedback)
|
||||
|
||||
return {self.OUTPUT: dest_id}
|
||||
|
||||
def saveCounts(self, values, sink, feedback):
|
||||
total = 50.0 / len(values) if values else 0
|
||||
current = 0
|
||||
for cat, v in values.items():
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
feedback.setProgress(int(current * total) + 50)
|
||||
f = QgsFeature()
|
||||
f.setAttributes(list(cat) + [v])
|
||||
sink.addFeature(f, QgsFeatureSink.FastInsert)
|
||||
current += 1
|
||||
|
||||
def calcNumericStats(self, values, sink, feedback):
|
||||
stat = QgsStatisticalSummary()
|
||||
|
||||
total = 50.0 / len(values) if values else 0
|
||||
current = 0
|
||||
for cat, v in values.items():
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
feedback.setProgress(int(current * total) + 50)
|
||||
|
||||
stat.calculate(v)
|
||||
f = QgsFeature()
|
||||
f.setAttributes(list(cat) + [stat.count(),
|
||||
stat.variety(),
|
||||
stat.min(),
|
||||
stat.max(),
|
||||
stat.range(),
|
||||
stat.sum(),
|
||||
stat.mean(),
|
||||
stat.median(),
|
||||
stat.stDev(),
|
||||
stat.minority(),
|
||||
stat.majority(),
|
||||
stat.firstQuartile(),
|
||||
stat.thirdQuartile(),
|
||||
stat.interQuartileRange()])
|
||||
|
||||
sink.addFeature(f, QgsFeatureSink.FastInsert)
|
||||
current += 1
|
||||
|
||||
def calcDateTimeStats(self, values, sink, feedback):
|
||||
stat = QgsDateTimeStatisticalSummary()
|
||||
|
||||
total = 50.0 / len(values) if values else 0
|
||||
current = 0
|
||||
for cat, v in values.items():
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
feedback.setProgress(int(current * total) + 50)
|
||||
|
||||
stat.calculate(v)
|
||||
f = QgsFeature()
|
||||
f.setAttributes(list(cat) + [stat.count(),
|
||||
stat.countDistinct(),
|
||||
stat.countMissing(),
|
||||
stat.count() - stat.countMissing(),
|
||||
stat.statistic(QgsDateTimeStatisticalSummary.Min),
|
||||
stat.statistic(QgsDateTimeStatisticalSummary.Max)
|
||||
])
|
||||
|
||||
sink.addFeature(f, QgsFeatureSink.FastInsert)
|
||||
current += 1
|
||||
|
||||
def calcStringStats(self, values, sink, feedback):
|
||||
stat = QgsStringStatisticalSummary()
|
||||
|
||||
total = 50.0 / len(values) if values else 0
|
||||
current = 0
|
||||
for cat, v in values.items():
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
feedback.setProgress(int(current * total) + 50)
|
||||
|
||||
stat.calculate(v)
|
||||
f = QgsFeature()
|
||||
f.setAttributes(list(cat) + [stat.count(),
|
||||
stat.countDistinct(),
|
||||
stat.countMissing(),
|
||||
stat.count() - stat.countMissing(),
|
||||
stat.min(),
|
||||
stat.max(),
|
||||
stat.minLength(),
|
||||
stat.maxLength(),
|
||||
stat.meanLength()
|
||||
])
|
||||
|
||||
sink.addFeature(f, QgsFeatureSink.FastInsert)
|
||||
current += 1
|
||||
|
@ -1,47 +0,0 @@
|
||||
##Vector analysis=group
|
||||
|
||||
#inputs
|
||||
|
||||
##Input=source
|
||||
##Fields=field multiple Input
|
||||
##Frequency=sink table
|
||||
|
||||
|
||||
from processing.tools.vector import TableWriter
|
||||
from collections import defaultdict
|
||||
from qgis.core import QgsProcessingUtils, QgsFields, QgsField, QgsWkbTypes, QgsFeature
|
||||
from qgis.PyQt.QtCore import QVariant
|
||||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
|
||||
|
||||
inputFields = Input.fields()
|
||||
fieldIdxs = []
|
||||
out_fields = QgsFields()
|
||||
for f in Fields:
|
||||
idx = inputFields.indexFromName(f)
|
||||
if idx == -1:
|
||||
raise GeoAlgorithmExecutionException('Field not found:' + f)
|
||||
fieldIdxs.append(idx)
|
||||
out_fields.append(inputFields.at(idx))
|
||||
|
||||
out_fields.append(QgsField('FREQ', QVariant.Int))
|
||||
|
||||
(sink, Frequency) = self.parameterAsSink(parameters, 'Frequency', context,
|
||||
out_fields)
|
||||
|
||||
counts = {}
|
||||
feats = Input.getFeatures()
|
||||
nFeats = Input.featureCount()
|
||||
counts = defaultdict(int)
|
||||
for i, feat in enumerate(feats):
|
||||
feedback.setProgress(int(100 * i / nFeats))
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
attrs = feat.attributes()
|
||||
clazz = tuple([attrs[i] for i in fieldIdxs])
|
||||
counts[clazz] += 1
|
||||
|
||||
for c in counts:
|
||||
f = QgsFeature()
|
||||
f.setAttributes(list(c) + [counts[c]])
|
||||
sink.addFeature(f)
|
@ -1,52 +0,0 @@
|
||||
##Vector analysis=group
|
||||
|
||||
# inputs
|
||||
|
||||
|
||||
##input=source
|
||||
##class_field=field input
|
||||
##value_field=field input
|
||||
##N_unique_values=sink
|
||||
|
||||
|
||||
from qgis.PyQt.QtCore import QVariant
|
||||
from qgis.core import QgsFeature, QgsField, QgsProcessingUtils
|
||||
|
||||
fields = input.fields()
|
||||
fields.append(QgsField('UNIQ_COUNT', QVariant.Int))
|
||||
|
||||
(sink, N_unique_values) = self.parameterAsSink(parameters, 'N_unique_values', context,
|
||||
fields, input.wkbType(), input.sourceCrs())
|
||||
|
||||
|
||||
class_field_index = input.fields().lookupField(class_field)
|
||||
value_field_index = input.fields().lookupField(value_field)
|
||||
|
||||
outFeat = QgsFeature()
|
||||
classes = {}
|
||||
feats = input.getFeatures()
|
||||
nFeat = input.featureCount()
|
||||
for n, inFeat in enumerate(feats):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
feedback.setProgress(int(100 * n / nFeat))
|
||||
attrs = inFeat.attributes()
|
||||
clazz = attrs[class_field_index]
|
||||
value = attrs[value_field_index]
|
||||
if clazz not in classes:
|
||||
classes[clazz] = []
|
||||
if value not in classes[clazz]:
|
||||
classes[clazz].append(value)
|
||||
|
||||
feats = input.getFeatures()
|
||||
for n, inFeat in enumerate(feats):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
feedback.setProgress(int(100 * n / nFeat))
|
||||
inGeom = inFeat.geometry()
|
||||
outFeat.setGeometry(inGeom)
|
||||
attrs = inFeat.attributes()
|
||||
clazz = attrs[class_field_index]
|
||||
attrs.append(len(classes[clazz]))
|
||||
outFeat.setAttributes(attrs)
|
||||
sink.addFeature(outFeat)
|
48
python/plugins/processing/tests/testdata/expected/stats_by_cat_date.gfs
vendored
Normal file
48
python/plugins/processing/tests/testdata/expected/stats_by_cat_date.gfs
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<GMLFeatureClassList>
|
||||
<GMLFeatureClass>
|
||||
<Name>stats_by_cat_date</Name>
|
||||
<ElementPath>stats_by_cat_date</ElementPath>
|
||||
<GeometryType>100</GeometryType>
|
||||
<DatasetSpecificInfo>
|
||||
<FeatureCount>4</FeatureCount>
|
||||
</DatasetSpecificInfo>
|
||||
<PropertyDefn>
|
||||
<Name>date</Name>
|
||||
<ElementPath>date</ElementPath>
|
||||
<Type>String</Type>
|
||||
<Width>10</Width>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>count</Name>
|
||||
<ElementPath>count</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>unique</Name>
|
||||
<ElementPath>unique</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>empty</Name>
|
||||
<ElementPath>empty</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>filled</Name>
|
||||
<ElementPath>filled</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>min</Name>
|
||||
<ElementPath>min</ElementPath>
|
||||
<Type>String</Type>
|
||||
<Width>10</Width>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>max</Name>
|
||||
<ElementPath>max</ElementPath>
|
||||
<Type>String</Type>
|
||||
<Width>10</Width>
|
||||
</PropertyDefn>
|
||||
</GMLFeatureClass>
|
||||
</GMLFeatureClassList>
|
50
python/plugins/processing/tests/testdata/expected/stats_by_cat_date.gml
vendored
Normal file
50
python/plugins/processing/tests/testdata/expected/stats_by_cat_date.gml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation=""
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_date fid="stats_by_cat_date.0">
|
||||
<ogr:date>2016/11/30</ogr:date>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:empty>0</ogr:empty>
|
||||
<ogr:filled>1</ogr:filled>
|
||||
<ogr:min>2016/11/30</ogr:min>
|
||||
<ogr:max>2016/11/30</ogr:max>
|
||||
</ogr:stats_by_cat_date>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_date fid="stats_by_cat_date.1">
|
||||
<ogr:date>2016/11/10</ogr:date>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:empty>0</ogr:empty>
|
||||
<ogr:filled>1</ogr:filled>
|
||||
<ogr:min>2016/11/10</ogr:min>
|
||||
<ogr:max>2016/11/10</ogr:max>
|
||||
</ogr:stats_by_cat_date>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_date fid="stats_by_cat_date.2">
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>0</ogr:unique>
|
||||
<ogr:empty>1</ogr:empty>
|
||||
<ogr:filled>0</ogr:filled>
|
||||
</ogr:stats_by_cat_date>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_date fid="stats_by_cat_date.3">
|
||||
<ogr:date>2014/11/30</ogr:date>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:empty>0</ogr:empty>
|
||||
<ogr:filled>1</ogr:filled>
|
||||
<ogr:min>2014/11/30</ogr:min>
|
||||
<ogr:max>2014/11/30</ogr:max>
|
||||
</ogr:stats_by_cat_date>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
86
python/plugins/processing/tests/testdata/expected/stats_by_cat_float.gfs
vendored
Normal file
86
python/plugins/processing/tests/testdata/expected/stats_by_cat_float.gfs
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
<GMLFeatureClassList>
|
||||
<GMLFeatureClass>
|
||||
<Name>stats_by_cat_float</Name>
|
||||
<ElementPath>stats_by_cat_float</ElementPath>
|
||||
<GeometryType>100</GeometryType>
|
||||
<DatasetSpecificInfo>
|
||||
<FeatureCount>5</FeatureCount>
|
||||
</DatasetSpecificInfo>
|
||||
<PropertyDefn>
|
||||
<Name>name</Name>
|
||||
<ElementPath>name</ElementPath>
|
||||
<Type>String</Type>
|
||||
<Width>2</Width>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>count</Name>
|
||||
<ElementPath>count</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>unique</Name>
|
||||
<ElementPath>unique</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>min</Name>
|
||||
<ElementPath>min</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>max</Name>
|
||||
<ElementPath>max</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>range</Name>
|
||||
<ElementPath>range</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>sum</Name>
|
||||
<ElementPath>sum</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>mean</Name>
|
||||
<ElementPath>mean</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>median</Name>
|
||||
<ElementPath>median</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>stddev</Name>
|
||||
<ElementPath>stddev</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>minority</Name>
|
||||
<ElementPath>minority</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>majority</Name>
|
||||
<ElementPath>majority</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>q1</Name>
|
||||
<ElementPath>q1</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>q3</Name>
|
||||
<ElementPath>q3</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>iqr</Name>
|
||||
<ElementPath>iqr</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
</GMLFeatureClass>
|
||||
</GMLFeatureClassList>
|
103
python/plugins/processing/tests/testdata/expected/stats_by_cat_float.gml
vendored
Normal file
103
python/plugins/processing/tests/testdata/expected/stats_by_cat_float.gml
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation=""
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_float fid="stats_by_cat_float.0">
|
||||
<ogr:name>aa</ogr:name>
|
||||
<ogr:count>2</ogr:count>
|
||||
<ogr:unique>2</ogr:unique>
|
||||
<ogr:min>3.33</ogr:min>
|
||||
<ogr:max>44.123456</ogr:max>
|
||||
<ogr:range>40.793456</ogr:range>
|
||||
<ogr:sum>47.453456</ogr:sum>
|
||||
<ogr:mean>23.726728</ogr:mean>
|
||||
<ogr:median>23.726728</ogr:median>
|
||||
<ogr:stddev>20.396728</ogr:stddev>
|
||||
<ogr:minority>3.33</ogr:minority>
|
||||
<ogr:majority>3.33</ogr:majority>
|
||||
<ogr:q1>3.33</ogr:q1>
|
||||
<ogr:q3>44.123456</ogr:q3>
|
||||
<ogr:iqr>40.793456</ogr:iqr>
|
||||
</ogr:stats_by_cat_float>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_float fid="stats_by_cat_float.1">
|
||||
<ogr:name>dd</ogr:name>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:min>0</ogr:min>
|
||||
<ogr:max>0</ogr:max>
|
||||
<ogr:range>0</ogr:range>
|
||||
<ogr:sum>0</ogr:sum>
|
||||
<ogr:mean>0</ogr:mean>
|
||||
<ogr:median>0</ogr:median>
|
||||
<ogr:stddev>0</ogr:stddev>
|
||||
<ogr:minority>0</ogr:minority>
|
||||
<ogr:majority>0</ogr:majority>
|
||||
<ogr:q1>0</ogr:q1>
|
||||
<ogr:q3>0</ogr:q3>
|
||||
<ogr:iqr>0</ogr:iqr>
|
||||
</ogr:stats_by_cat_float>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_float fid="stats_by_cat_float.2">
|
||||
<ogr:name>bb</ogr:name>
|
||||
<ogr:count>4</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:min>0.123</ogr:min>
|
||||
<ogr:max>0.123</ogr:max>
|
||||
<ogr:range>0</ogr:range>
|
||||
<ogr:sum>0.492</ogr:sum>
|
||||
<ogr:mean>0.123</ogr:mean>
|
||||
<ogr:median>0.123</ogr:median>
|
||||
<ogr:stddev>0</ogr:stddev>
|
||||
<ogr:minority>0.123</ogr:minority>
|
||||
<ogr:majority>0.123</ogr:majority>
|
||||
<ogr:q1>0.123</ogr:q1>
|
||||
<ogr:q3>0.123</ogr:q3>
|
||||
<ogr:iqr>0</ogr:iqr>
|
||||
</ogr:stats_by_cat_float>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_float fid="stats_by_cat_float.3">
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:min>-100291.43213</ogr:min>
|
||||
<ogr:max>-100291.43213</ogr:max>
|
||||
<ogr:range>0</ogr:range>
|
||||
<ogr:sum>-100291.43213</ogr:sum>
|
||||
<ogr:mean>-100291.43213</ogr:mean>
|
||||
<ogr:median>-100291.43213</ogr:median>
|
||||
<ogr:stddev>0</ogr:stddev>
|
||||
<ogr:minority>-100291.43213</ogr:minority>
|
||||
<ogr:majority>-100291.43213</ogr:majority>
|
||||
<ogr:q1>-100291.43213</ogr:q1>
|
||||
<ogr:q3>-100291.43213</ogr:q3>
|
||||
<ogr:iqr>0</ogr:iqr>
|
||||
</ogr:stats_by_cat_float>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_float fid="stats_by_cat_float.4">
|
||||
<ogr:name>cc</ogr:name>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:min>0.123</ogr:min>
|
||||
<ogr:max>0.123</ogr:max>
|
||||
<ogr:range>0</ogr:range>
|
||||
<ogr:sum>0.123</ogr:sum>
|
||||
<ogr:mean>0.123</ogr:mean>
|
||||
<ogr:median>0.123</ogr:median>
|
||||
<ogr:stddev>0</ogr:stddev>
|
||||
<ogr:minority>0.123</ogr:minority>
|
||||
<ogr:majority>0.123</ogr:majority>
|
||||
<ogr:q1>0.123</ogr:q1>
|
||||
<ogr:q3>0.123</ogr:q3>
|
||||
<ogr:iqr>0</ogr:iqr>
|
||||
</ogr:stats_by_cat_float>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
26
python/plugins/processing/tests/testdata/expected/stats_by_cat_no_value.gfs
vendored
Normal file
26
python/plugins/processing/tests/testdata/expected/stats_by_cat_no_value.gfs
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<GMLFeatureClassList>
|
||||
<GMLFeatureClass>
|
||||
<Name>stats_by_cat_no_value</Name>
|
||||
<ElementPath>stats_by_cat_no_value</ElementPath>
|
||||
<GeometryType>100</GeometryType>
|
||||
<DatasetSpecificInfo>
|
||||
<FeatureCount>6</FeatureCount>
|
||||
</DatasetSpecificInfo>
|
||||
<PropertyDefn>
|
||||
<Name>intval</Name>
|
||||
<ElementPath>intval</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>name</Name>
|
||||
<ElementPath>name</ElementPath>
|
||||
<Type>String</Type>
|
||||
<Width>2</Width>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>count</Name>
|
||||
<ElementPath>count</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
</GMLFeatureClass>
|
||||
</GMLFeatureClassList>
|
48
python/plugins/processing/tests/testdata/expected/stats_by_cat_no_value.gml
vendored
Normal file
48
python/plugins/processing/tests/testdata/expected/stats_by_cat_no_value.gml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation=""
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_no_value fid="stats_by_cat_no_value.0">
|
||||
<ogr:intval>1</ogr:intval>
|
||||
<ogr:name>aa</ogr:name>
|
||||
<ogr:count>2</ogr:count>
|
||||
</ogr:stats_by_cat_no_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_no_value fid="stats_by_cat_no_value.1">
|
||||
<ogr:name>dd</ogr:name>
|
||||
<ogr:count>2</ogr:count>
|
||||
</ogr:stats_by_cat_no_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_no_value fid="stats_by_cat_no_value.2">
|
||||
<ogr:intval>1</ogr:intval>
|
||||
<ogr:name>bb</ogr:name>
|
||||
<ogr:count>3</ogr:count>
|
||||
</ogr:stats_by_cat_no_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_no_value fid="stats_by_cat_no_value.3">
|
||||
<ogr:intval>120</ogr:intval>
|
||||
<ogr:count>1</ogr:count>
|
||||
</ogr:stats_by_cat_no_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_no_value fid="stats_by_cat_no_value.4">
|
||||
<ogr:name>cc</ogr:name>
|
||||
<ogr:count>1</ogr:count>
|
||||
</ogr:stats_by_cat_no_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_no_value fid="stats_by_cat_no_value.5">
|
||||
<ogr:intval>2</ogr:intval>
|
||||
<ogr:name>bb</ogr:name>
|
||||
<ogr:count>1</ogr:count>
|
||||
</ogr:stats_by_cat_no_value>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
62
python/plugins/processing/tests/testdata/expected/stats_by_cat_string.gfs
vendored
Normal file
62
python/plugins/processing/tests/testdata/expected/stats_by_cat_string.gfs
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
<GMLFeatureClassList>
|
||||
<GMLFeatureClass>
|
||||
<Name>stats_by_cat_string</Name>
|
||||
<ElementPath>stats_by_cat_string</ElementPath>
|
||||
<GeometryType>100</GeometryType>
|
||||
<DatasetSpecificInfo>
|
||||
<FeatureCount>4</FeatureCount>
|
||||
</DatasetSpecificInfo>
|
||||
<PropertyDefn>
|
||||
<Name>intval</Name>
|
||||
<ElementPath>intval</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>count</Name>
|
||||
<ElementPath>count</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>unique</Name>
|
||||
<ElementPath>unique</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>empty</Name>
|
||||
<ElementPath>empty</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>filled</Name>
|
||||
<ElementPath>filled</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>min</Name>
|
||||
<ElementPath>min</ElementPath>
|
||||
<Type>String</Type>
|
||||
<Width>2</Width>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>max</Name>
|
||||
<ElementPath>max</ElementPath>
|
||||
<Type>String</Type>
|
||||
<Width>2</Width>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>min_length</Name>
|
||||
<ElementPath>min_length</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>max_length</Name>
|
||||
<ElementPath>max_length</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>mean_length</Name>
|
||||
<ElementPath>mean_length</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
</GMLFeatureClass>
|
||||
</GMLFeatureClassList>
|
64
python/plugins/processing/tests/testdata/expected/stats_by_cat_string.gml
vendored
Normal file
64
python/plugins/processing/tests/testdata/expected/stats_by_cat_string.gml
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation=""
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_string fid="stats_by_cat_string.0">
|
||||
<ogr:intval>1</ogr:intval>
|
||||
<ogr:count>5</ogr:count>
|
||||
<ogr:unique>2</ogr:unique>
|
||||
<ogr:empty>0</ogr:empty>
|
||||
<ogr:filled>5</ogr:filled>
|
||||
<ogr:min>aa</ogr:min>
|
||||
<ogr:max>bb</ogr:max>
|
||||
<ogr:min_length>2</ogr:min_length>
|
||||
<ogr:max_length>2</ogr:max_length>
|
||||
<ogr:mean_length>2</ogr:mean_length>
|
||||
</ogr:stats_by_cat_string>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_string fid="stats_by_cat_string.1">
|
||||
<ogr:count>3</ogr:count>
|
||||
<ogr:unique>2</ogr:unique>
|
||||
<ogr:empty>0</ogr:empty>
|
||||
<ogr:filled>3</ogr:filled>
|
||||
<ogr:min>cc</ogr:min>
|
||||
<ogr:max>dd</ogr:max>
|
||||
<ogr:min_length>2</ogr:min_length>
|
||||
<ogr:max_length>2</ogr:max_length>
|
||||
<ogr:mean_length>2</ogr:mean_length>
|
||||
</ogr:stats_by_cat_string>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_string fid="stats_by_cat_string.2">
|
||||
<ogr:intval>120</ogr:intval>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:empty>1</ogr:empty>
|
||||
<ogr:filled>0</ogr:filled>
|
||||
<ogr:min></ogr:min>
|
||||
<ogr:max></ogr:max>
|
||||
<ogr:min_length>0</ogr:min_length>
|
||||
<ogr:max_length>0</ogr:max_length>
|
||||
<ogr:mean_length>0</ogr:mean_length>
|
||||
</ogr:stats_by_cat_string>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_string fid="stats_by_cat_string.3">
|
||||
<ogr:intval>2</ogr:intval>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:empty>0</ogr:empty>
|
||||
<ogr:filled>1</ogr:filled>
|
||||
<ogr:min>bb</ogr:min>
|
||||
<ogr:max>bb</ogr:max>
|
||||
<ogr:min_length>2</ogr:min_length>
|
||||
<ogr:max_length>2</ogr:max_length>
|
||||
<ogr:mean_length>2</ogr:mean_length>
|
||||
</ogr:stats_by_cat_string>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
91
python/plugins/processing/tests/testdata/expected/stats_by_cat_two_fields.gfs
vendored
Normal file
91
python/plugins/processing/tests/testdata/expected/stats_by_cat_two_fields.gfs
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
<GMLFeatureClassList>
|
||||
<GMLFeatureClass>
|
||||
<Name>stats_by_cat_two_fields</Name>
|
||||
<ElementPath>stats_by_cat_two_fields</ElementPath>
|
||||
<GeometryType>100</GeometryType>
|
||||
<DatasetSpecificInfo>
|
||||
<FeatureCount>6</FeatureCount>
|
||||
</DatasetSpecificInfo>
|
||||
<PropertyDefn>
|
||||
<Name>intval</Name>
|
||||
<ElementPath>intval</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>name</Name>
|
||||
<ElementPath>name</ElementPath>
|
||||
<Type>String</Type>
|
||||
<Width>2</Width>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>count</Name>
|
||||
<ElementPath>count</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>unique</Name>
|
||||
<ElementPath>unique</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>min</Name>
|
||||
<ElementPath>min</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>max</Name>
|
||||
<ElementPath>max</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>range</Name>
|
||||
<ElementPath>range</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>sum</Name>
|
||||
<ElementPath>sum</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>mean</Name>
|
||||
<ElementPath>mean</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>median</Name>
|
||||
<ElementPath>median</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>stddev</Name>
|
||||
<ElementPath>stddev</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>minority</Name>
|
||||
<ElementPath>minority</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>majority</Name>
|
||||
<ElementPath>majority</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>q1</Name>
|
||||
<ElementPath>q1</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>q3</Name>
|
||||
<ElementPath>q3</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>iqr</Name>
|
||||
<ElementPath>iqr</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
</GMLFeatureClass>
|
||||
</GMLFeatureClassList>
|
126
python/plugins/processing/tests/testdata/expected/stats_by_cat_two_fields.gml
vendored
Normal file
126
python/plugins/processing/tests/testdata/expected/stats_by_cat_two_fields.gml
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation=""
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_two_fields fid="stats_by_cat_two_fields.0">
|
||||
<ogr:intval>1</ogr:intval>
|
||||
<ogr:name>aa</ogr:name>
|
||||
<ogr:count>2</ogr:count>
|
||||
<ogr:unique>2</ogr:unique>
|
||||
<ogr:min>3.33</ogr:min>
|
||||
<ogr:max>44.123456</ogr:max>
|
||||
<ogr:range>40.793456</ogr:range>
|
||||
<ogr:sum>47.453456</ogr:sum>
|
||||
<ogr:mean>23.726728</ogr:mean>
|
||||
<ogr:median>23.726728</ogr:median>
|
||||
<ogr:stddev>20.396728</ogr:stddev>
|
||||
<ogr:minority>3.33</ogr:minority>
|
||||
<ogr:majority>3.33</ogr:majority>
|
||||
<ogr:q1>3.33</ogr:q1>
|
||||
<ogr:q3>44.123456</ogr:q3>
|
||||
<ogr:iqr>40.793456</ogr:iqr>
|
||||
</ogr:stats_by_cat_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_two_fields fid="stats_by_cat_two_fields.1">
|
||||
<ogr:name>dd</ogr:name>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:min>0</ogr:min>
|
||||
<ogr:max>0</ogr:max>
|
||||
<ogr:range>0</ogr:range>
|
||||
<ogr:sum>0</ogr:sum>
|
||||
<ogr:mean>0</ogr:mean>
|
||||
<ogr:median>0</ogr:median>
|
||||
<ogr:stddev>0</ogr:stddev>
|
||||
<ogr:minority>0</ogr:minority>
|
||||
<ogr:majority>0</ogr:majority>
|
||||
<ogr:q1>0</ogr:q1>
|
||||
<ogr:q3>0</ogr:q3>
|
||||
<ogr:iqr>0</ogr:iqr>
|
||||
</ogr:stats_by_cat_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_two_fields fid="stats_by_cat_two_fields.2">
|
||||
<ogr:intval>1</ogr:intval>
|
||||
<ogr:name>bb</ogr:name>
|
||||
<ogr:count>3</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:min>0.123</ogr:min>
|
||||
<ogr:max>0.123</ogr:max>
|
||||
<ogr:range>0</ogr:range>
|
||||
<ogr:sum>0.369</ogr:sum>
|
||||
<ogr:mean>0.123</ogr:mean>
|
||||
<ogr:median>0.123</ogr:median>
|
||||
<ogr:stddev>0</ogr:stddev>
|
||||
<ogr:minority>0.123</ogr:minority>
|
||||
<ogr:majority>0.123</ogr:majority>
|
||||
<ogr:q1>0.123</ogr:q1>
|
||||
<ogr:q3>0.123</ogr:q3>
|
||||
<ogr:iqr>0</ogr:iqr>
|
||||
</ogr:stats_by_cat_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_two_fields fid="stats_by_cat_two_fields.3">
|
||||
<ogr:intval>120</ogr:intval>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:min>-100291.43213</ogr:min>
|
||||
<ogr:max>-100291.43213</ogr:max>
|
||||
<ogr:range>0</ogr:range>
|
||||
<ogr:sum>-100291.43213</ogr:sum>
|
||||
<ogr:mean>-100291.43213</ogr:mean>
|
||||
<ogr:median>-100291.43213</ogr:median>
|
||||
<ogr:stddev>0</ogr:stddev>
|
||||
<ogr:minority>-100291.43213</ogr:minority>
|
||||
<ogr:majority>-100291.43213</ogr:majority>
|
||||
<ogr:q1>-100291.43213</ogr:q1>
|
||||
<ogr:q3>-100291.43213</ogr:q3>
|
||||
<ogr:iqr>0</ogr:iqr>
|
||||
</ogr:stats_by_cat_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_two_fields fid="stats_by_cat_two_fields.4">
|
||||
<ogr:name>cc</ogr:name>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:min>0.123</ogr:min>
|
||||
<ogr:max>0.123</ogr:max>
|
||||
<ogr:range>0</ogr:range>
|
||||
<ogr:sum>0.123</ogr:sum>
|
||||
<ogr:mean>0.123</ogr:mean>
|
||||
<ogr:median>0.123</ogr:median>
|
||||
<ogr:stddev>0</ogr:stddev>
|
||||
<ogr:minority>0.123</ogr:minority>
|
||||
<ogr:majority>0.123</ogr:majority>
|
||||
<ogr:q1>0.123</ogr:q1>
|
||||
<ogr:q3>0.123</ogr:q3>
|
||||
<ogr:iqr>0</ogr:iqr>
|
||||
</ogr:stats_by_cat_two_fields>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_cat_two_fields fid="stats_by_cat_two_fields.5">
|
||||
<ogr:intval>2</ogr:intval>
|
||||
<ogr:name>bb</ogr:name>
|
||||
<ogr:count>1</ogr:count>
|
||||
<ogr:unique>1</ogr:unique>
|
||||
<ogr:min>0.123</ogr:min>
|
||||
<ogr:max>0.123</ogr:max>
|
||||
<ogr:range>0</ogr:range>
|
||||
<ogr:sum>0.123</ogr:sum>
|
||||
<ogr:mean>0.123</ogr:mean>
|
||||
<ogr:median>0.123</ogr:median>
|
||||
<ogr:stddev>0</ogr:stddev>
|
||||
<ogr:minority>0.123</ogr:minority>
|
||||
<ogr:majority>0.123</ogr:majority>
|
||||
<ogr:q1>0.123</ogr:q1>
|
||||
<ogr:q3>0.123</ogr:q3>
|
||||
<ogr:iqr>0</ogr:iqr>
|
||||
</ogr:stats_by_cat_two_fields>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
@ -11,6 +11,16 @@
|
||||
<ElementPath>id2</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>count</Name>
|
||||
<ElementPath>count</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>unique</Name>
|
||||
<ElementPath>unique</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>min</Name>
|
||||
<ElementPath>min</ElementPath>
|
||||
@ -21,24 +31,54 @@
|
||||
<ElementPath>max</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>range</Name>
|
||||
<ElementPath>range</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>sum</Name>
|
||||
<ElementPath>sum</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>mean</Name>
|
||||
<ElementPath>mean</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>median</Name>
|
||||
<ElementPath>median</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>stddev</Name>
|
||||
<ElementPath>stddev</ElementPath>
|
||||
<Type>Real</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>sum</Name>
|
||||
<ElementPath>sum</ElementPath>
|
||||
<Name>minority</Name>
|
||||
<ElementPath>minority</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>count</Name>
|
||||
<ElementPath>count</ElementPath>
|
||||
<Name>majority</Name>
|
||||
<ElementPath>majority</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>q1</Name>
|
||||
<ElementPath>q1</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>q3</Name>
|
||||
<ElementPath>q3</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
<PropertyDefn>
|
||||
<Name>iqr</Name>
|
||||
<ElementPath>iqr</ElementPath>
|
||||
<Type>Integer</Type>
|
||||
</PropertyDefn>
|
||||
</GMLFeatureClass>
|
||||
|
@ -9,34 +9,58 @@
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_category fid="stats_by_category.0">
|
||||
<ogr:id2>2</ogr:id2>
|
||||
<ogr:count>2</ogr:count>
|
||||
<ogr:unique>2</ogr:unique>
|
||||
<ogr:min>1</ogr:min>
|
||||
<ogr:max>4</ogr:max>
|
||||
<ogr:mean>2.5</ogr:mean>
|
||||
<ogr:stddev>2.12132034355964</ogr:stddev>
|
||||
<ogr:range>3</ogr:range>
|
||||
<ogr:sum>5</ogr:sum>
|
||||
<ogr:count>2</ogr:count>
|
||||
<ogr:mean>2.5</ogr:mean>
|
||||
<ogr:median>2.5</ogr:median>
|
||||
<ogr:stddev>1.5</ogr:stddev>
|
||||
<ogr:minority>1</ogr:minority>
|
||||
<ogr:majority>1</ogr:majority>
|
||||
<ogr:q1>1</ogr:q1>
|
||||
<ogr:q3>4</ogr:q3>
|
||||
<ogr:iqr>3</ogr:iqr>
|
||||
</ogr:stats_by_category>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_category fid="stats_by_category.1">
|
||||
<ogr:id2>1</ogr:id2>
|
||||
<ogr:count>2</ogr:count>
|
||||
<ogr:unique>2</ogr:unique>
|
||||
<ogr:min>2</ogr:min>
|
||||
<ogr:max>5</ogr:max>
|
||||
<ogr:mean>3.5</ogr:mean>
|
||||
<ogr:stddev>2.12132034355964</ogr:stddev>
|
||||
<ogr:range>3</ogr:range>
|
||||
<ogr:sum>7</ogr:sum>
|
||||
<ogr:count>2</ogr:count>
|
||||
<ogr:mean>3.5</ogr:mean>
|
||||
<ogr:median>3.5</ogr:median>
|
||||
<ogr:stddev>1.5</ogr:stddev>
|
||||
<ogr:minority>2</ogr:minority>
|
||||
<ogr:majority>2</ogr:majority>
|
||||
<ogr:q1>2</ogr:q1>
|
||||
<ogr:q3>5</ogr:q3>
|
||||
<ogr:iqr>3</ogr:iqr>
|
||||
</ogr:stats_by_category>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:stats_by_category fid="stats_by_category.2">
|
||||
<ogr:id2>0</ogr:id2>
|
||||
<ogr:count>5</ogr:count>
|
||||
<ogr:unique>5</ogr:unique>
|
||||
<ogr:min>3</ogr:min>
|
||||
<ogr:max>9</ogr:max>
|
||||
<ogr:mean>6.6</ogr:mean>
|
||||
<ogr:stddev>2.30217288664427</ogr:stddev>
|
||||
<ogr:range>6</ogr:range>
|
||||
<ogr:sum>33</ogr:sum>
|
||||
<ogr:count>5</ogr:count>
|
||||
<ogr:mean>6.6</ogr:mean>
|
||||
<ogr:median>7</ogr:median>
|
||||
<ogr:stddev>2.0591260281974</ogr:stddev>
|
||||
<ogr:minority>3</ogr:minority>
|
||||
<ogr:majority>3</ogr:majority>
|
||||
<ogr:q1>6</ogr:q1>
|
||||
<ogr:q3>8</ogr:q3>
|
||||
<ogr:iqr>2</ogr:iqr>
|
||||
</ogr:stats_by_category>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
||||
|
@ -3476,3 +3476,98 @@ tests:
|
||||
name: expected/collect_two_fields.gml
|
||||
type: vector
|
||||
|
||||
|
||||
- algorithm: qgis:statisticsbycategories
|
||||
name: Stats by cat (float field)
|
||||
params:
|
||||
CATEGORIES_FIELD_NAME:
|
||||
- name
|
||||
INPUT:
|
||||
name: dissolve_polys.gml
|
||||
type: vector
|
||||
VALUES_FIELD_NAME: floatval
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/stats_by_cat_float.gml
|
||||
type: vector
|
||||
pk: name
|
||||
compare:
|
||||
fields:
|
||||
fid: skip
|
||||
|
||||
- algorithm: qgis:statisticsbycategories
|
||||
name: Stats by cat (string field)
|
||||
params:
|
||||
CATEGORIES_FIELD_NAME:
|
||||
- intval
|
||||
INPUT:
|
||||
name: dissolve_polys.gml
|
||||
type: vector
|
||||
VALUES_FIELD_NAME: name
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/stats_by_cat_string.gml
|
||||
type: vector
|
||||
pk: intval
|
||||
compare:
|
||||
fields:
|
||||
fid: skip
|
||||
|
||||
- algorithm: qgis:statisticsbycategories
|
||||
name: Stats by cat (two category fields)
|
||||
params:
|
||||
CATEGORIES_FIELD_NAME:
|
||||
- intval
|
||||
- name
|
||||
INPUT:
|
||||
name: dissolve_polys.gml
|
||||
type: vector
|
||||
VALUES_FIELD_NAME: floatval
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/stats_by_cat_two_fields.gml
|
||||
type: vector
|
||||
pk:
|
||||
- intval
|
||||
- name
|
||||
compare:
|
||||
fields:
|
||||
fid: skip
|
||||
|
||||
- algorithm: qgis:statisticsbycategories
|
||||
name: Stats by cat (no value field)
|
||||
params:
|
||||
CATEGORIES_FIELD_NAME:
|
||||
- intval
|
||||
- name
|
||||
INPUT:
|
||||
name: dissolve_polys.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/stats_by_cat_no_value.gml
|
||||
type: vector
|
||||
pk:
|
||||
- intval
|
||||
- name
|
||||
compare:
|
||||
fields:
|
||||
fid: skip
|
||||
|
||||
- algorithm: qgis:statisticsbycategories
|
||||
name: Stats by cat (date field)
|
||||
params:
|
||||
CATEGORIES_FIELD_NAME:
|
||||
- date
|
||||
INPUT:
|
||||
name: custom/datetimes.tab
|
||||
type: vector
|
||||
VALUES_FIELD_NAME: date
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/stats_by_cat_date.gml
|
||||
type: vector
|
||||
pk: date
|
||||
compare:
|
||||
fields:
|
||||
fid: skip
|
@ -105,7 +105,11 @@ class TestCase(_TestCase):
|
||||
|
||||
def sort_by_pk_or_fid(f):
|
||||
if 'pk' in kwargs and kwargs['pk'] is not None:
|
||||
return f[kwargs['pk']]
|
||||
key = kwargs['pk']
|
||||
if isinstance(key, list) or isinstance(key, tuple):
|
||||
return [f[k] for k in key]
|
||||
else:
|
||||
return f[kwargs['pk']]
|
||||
else:
|
||||
return f.id()
|
||||
|
||||
|
@ -2301,6 +2301,9 @@ bool QgsProcessingParameterField::checkValueIsAcceptable( const QVariant &input,
|
||||
{
|
||||
if ( !mAllowMultiple )
|
||||
return false;
|
||||
|
||||
if ( input.toList().isEmpty() && !( mFlags & FlagOptional ) )
|
||||
return false;
|
||||
}
|
||||
else if ( input.type() == QVariant::String )
|
||||
{
|
||||
|
@ -2258,6 +2258,8 @@ void TestQgsProcessing::parameterLayerList()
|
||||
QVERIFY( !def->checkValueIsAcceptable( true ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( 5 ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "layer12312312" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QVariantList() ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QStringList() ) );
|
||||
QVERIFY( def->checkValueIsAcceptable( QStringList() << "layer12312312" << "layerB" ) );
|
||||
QVERIFY( def->checkValueIsAcceptable( QVariantList() << "layer12312312" << "layerB" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "" ) );
|
||||
@ -3183,6 +3185,8 @@ void TestQgsProcessing::parameterField()
|
||||
QVERIFY( def->checkValueIsAcceptable( QVariantList() << "a" << "b" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QStringList() ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QVariantList() ) );
|
||||
|
||||
params.insert( "non_optional", QString( "a;b" ) );
|
||||
fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context );
|
||||
|
Loading…
x
Reference in New Issue
Block a user