@@ -67,9 +67,9 @@ def initAlgorithm(self, config=None):
67
67
self .tr ('Field to calculate statistics on' ),
68
68
parentLayerParameterName = self .INPUT ))
69
69
self .addParameter (QgsProcessingParameterField (self .CATEGORIES_FIELD_NAME ,
70
- self .tr ('Field with categories' ),
70
+ self .tr ('Field(s) with categories' ),
71
71
parentLayerParameterName = self .INPUT ,
72
- type = QgsProcessingParameterField .Any ))
72
+ type = QgsProcessingParameterField .Any , allowMultiple = True ))
73
73
74
74
self .addParameter (QgsProcessingParameterFeatureSink (self .OUTPUT , self .tr ('Statistics by category' )))
75
75
@@ -82,15 +82,16 @@ def displayName(self):
82
82
def processAlgorithm (self , parameters , context , feedback ):
83
83
source = self .parameterAsSource (parameters , self .INPUT , context )
84
84
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 )
86
86
87
87
value_field_index = source .fields ().lookupField (value_field_name )
88
88
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 ]
90
90
91
91
# generate output fields
92
92
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 ))
94
95
95
96
def addField (name ):
96
97
"""
@@ -138,8 +139,11 @@ def addField(name):
138
139
fields .append (QgsField ('max_length' , QVariant .Int ))
139
140
fields .append (QgsField ('mean_length' , QVariant .Double ))
140
141
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 )
143
147
total = 50.0 / source .featureCount () if source .featureCount () else 0
144
148
values = defaultdict (list )
145
149
for current , feat in enumerate (features ):
@@ -148,7 +152,7 @@ def addField(name):
148
152
149
153
feedback .setProgress (int (current * total ))
150
154
attrs = feat .attributes ()
151
- try :
155
+ if True :
152
156
if field_type == 'numeric' :
153
157
if attrs [value_field_index ] == NULL :
154
158
continue
@@ -160,9 +164,9 @@ def addField(name):
160
164
value = str (attrs [value_field_index ])
161
165
else :
162
166
value = attrs [value_field_index ]
163
- cat = attrs [category_field_index ]
167
+ cat = tuple ([ attrs [c ] for c in category_field_indexes ])
164
168
values [cat ].append (value )
165
- except :
169
+ else :
166
170
pass
167
171
168
172
(sink , dest_id ) = self .parameterAsSink (parameters , self .OUTPUT , context ,
@@ -190,21 +194,20 @@ def calcNumericStats(self, values, sink, feedback):
190
194
191
195
stat .calculate (v )
192
196
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 ()])
208
211
209
212
sink .addFeature (f , QgsFeatureSink .FastInsert )
210
213
current += 1
@@ -222,14 +225,13 @@ def calcDateTimeStats(self, values, sink, feedback):
222
225
223
226
stat .calculate (v )
224
227
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
+ ])
233
235
234
236
sink .addFeature (f , QgsFeatureSink .FastInsert )
235
237
current += 1
@@ -247,17 +249,16 @@ def calcStringStats(self, values, sink, feedback):
247
249
248
250
stat .calculate (v )
249
251
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
+ ])
261
262
262
263
sink .addFeature (f , QgsFeatureSink .FastInsert )
263
264
current += 1
0 commit comments