Skip to content

Commit 3086619

Browse files
committed
[FEATURE] Allow multiple category fields in 'stats by category'
1 parent 4e78e03 commit 3086619

File tree

1 file changed

+45
-44
lines changed

1 file changed

+45
-44
lines changed

python/plugins/processing/algs/qgis/StatisticsByCategories.py

+45-44
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ def initAlgorithm(self, config=None):
6767
self.tr('Field to calculate statistics on'),
6868
parentLayerParameterName=self.INPUT))
6969
self.addParameter(QgsProcessingParameterField(self.CATEGORIES_FIELD_NAME,
70-
self.tr('Field with categories'),
70+
self.tr('Field(s) with categories'),
7171
parentLayerParameterName=self.INPUT,
72-
type=QgsProcessingParameterField.Any))
72+
type=QgsProcessingParameterField.Any, allowMultiple=True))
7373

7474
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Statistics by category')))
7575

@@ -82,15 +82,16 @@ def displayName(self):
8282
def processAlgorithm(self, parameters, context, feedback):
8383
source = self.parameterAsSource(parameters, self.INPUT, context)
8484
value_field_name = self.parameterAsString(parameters, self.VALUES_FIELD_NAME, context)
85-
category_field_name = self.parameterAsString(parameters, self.CATEGORIES_FIELD_NAME, context)
85+
category_field_names = self.parameterAsFields(parameters, self.CATEGORIES_FIELD_NAME, context)
8686

8787
value_field_index = source.fields().lookupField(value_field_name)
8888
value_field = source.fields().at(value_field_index)
89-
category_field_index = source.fields().lookupField(category_field_name)
89+
category_field_indexes = [source.fields().lookupField(n) for n in category_field_names]
9090

9191
# generate output fields
9292
fields = QgsFields()
93-
fields.append(source.fields().at(category_field_index))
93+
for c in category_field_indexes:
94+
fields.append(source.fields().at(c))
9495

9596
def addField(name):
9697
"""
@@ -138,8 +139,11 @@ def addField(name):
138139
fields.append(QgsField('max_length', QVariant.Int))
139140
fields.append(QgsField('mean_length', QVariant.Double))
140141

141-
features = source.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes(
142-
[value_field_index, category_field_index]))
142+
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
143+
attrs = [value_field_index]
144+
attrs.extend(category_field_indexes)
145+
request.setSubsetOfAttributes(attrs)
146+
features = source.getFeatures(request)
143147
total = 50.0 / source.featureCount() if source.featureCount() else 0
144148
values = defaultdict(list)
145149
for current, feat in enumerate(features):
@@ -148,7 +152,7 @@ def addField(name):
148152

149153
feedback.setProgress(int(current * total))
150154
attrs = feat.attributes()
151-
try:
155+
if True:
152156
if field_type == 'numeric':
153157
if attrs[value_field_index] == NULL:
154158
continue
@@ -160,9 +164,9 @@ def addField(name):
160164
value = str(attrs[value_field_index])
161165
else:
162166
value = attrs[value_field_index]
163-
cat = attrs[category_field_index]
167+
cat = tuple([attrs[c] for c in category_field_indexes])
164168
values[cat].append(value)
165-
except:
169+
else:
166170
pass
167171

168172
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
@@ -190,21 +194,20 @@ def calcNumericStats(self, values, sink, feedback):
190194

191195
stat.calculate(v)
192196
f = QgsFeature()
193-
f.setAttributes([cat,
194-
stat.count(),
195-
stat.variety(),
196-
stat.min(),
197-
stat.max(),
198-
stat.range(),
199-
stat.sum(),
200-
stat.mean(),
201-
stat.median(),
202-
stat.stDev(),
203-
stat.minority(),
204-
stat.majority(),
205-
stat.firstQuartile(),
206-
stat.thirdQuartile(),
207-
stat.interQuartileRange()])
197+
f.setAttributes(list(cat) + [stat.count(),
198+
stat.variety(),
199+
stat.min(),
200+
stat.max(),
201+
stat.range(),
202+
stat.sum(),
203+
stat.mean(),
204+
stat.median(),
205+
stat.stDev(),
206+
stat.minority(),
207+
stat.majority(),
208+
stat.firstQuartile(),
209+
stat.thirdQuartile(),
210+
stat.interQuartileRange()])
208211

209212
sink.addFeature(f, QgsFeatureSink.FastInsert)
210213
current += 1
@@ -222,14 +225,13 @@ def calcDateTimeStats(self, values, sink, feedback):
222225

223226
stat.calculate(v)
224227
f = QgsFeature()
225-
f.setAttributes([cat,
226-
stat.count(),
227-
stat.countDistinct(),
228-
stat.countMissing(),
229-
stat.count() - stat.countMissing(),
230-
stat.statistic(QgsDateTimeStatisticalSummary.Min),
231-
stat.statistic(QgsDateTimeStatisticalSummary.Max)
232-
])
228+
f.setAttributes(list(cat) + [stat.count(),
229+
stat.countDistinct(),
230+
stat.countMissing(),
231+
stat.count() - stat.countMissing(),
232+
stat.statistic(QgsDateTimeStatisticalSummary.Min),
233+
stat.statistic(QgsDateTimeStatisticalSummary.Max)
234+
])
233235

234236
sink.addFeature(f, QgsFeatureSink.FastInsert)
235237
current += 1
@@ -247,17 +249,16 @@ def calcStringStats(self, values, sink, feedback):
247249

248250
stat.calculate(v)
249251
f = QgsFeature()
250-
f.setAttributes([cat,
251-
stat.count(),
252-
stat.countDistinct(),
253-
stat.countMissing(),
254-
stat.count() - stat.countMissing(),
255-
stat.min(),
256-
stat.max(),
257-
stat.minLength(),
258-
stat.maxLength(),
259-
stat.meanLength()
260-
])
252+
f.setAttributes(list(cat) + [stat.count(),
253+
stat.countDistinct(),
254+
stat.countMissing(),
255+
stat.count() - stat.countMissing(),
256+
stat.min(),
257+
stat.max(),
258+
stat.minLength(),
259+
stat.maxLength(),
260+
stat.meanLength()
261+
])
261262

262263
sink.addFeature(f, QgsFeatureSink.FastInsert)
263264
current += 1

0 commit comments

Comments
 (0)