@@ -64,8 +64,9 @@ def initAlgorithm(self, config=None):
64
64
self .tr ('Input vector layer' ),
65
65
types = [QgsProcessing .TypeVector ]))
66
66
self .addParameter (QgsProcessingParameterField (self .VALUES_FIELD_NAME ,
67
- self .tr ('Field to calculate statistics on' ),
68
- parentLayerParameterName = self .INPUT ))
67
+ self .tr (
68
+ 'Field to calculate statistics on (if empty, only count is calculated)' ),
69
+ parentLayerParameterName = self .INPUT , optional = True ))
69
70
self .addParameter (QgsProcessingParameterField (self .CATEGORIES_FIELD_NAME ,
70
71
self .tr ('Field(s) with categories' ),
71
72
parentLayerParameterName = self .INPUT ,
@@ -85,7 +86,10 @@ def processAlgorithm(self, parameters, context, feedback):
85
86
category_field_names = self .parameterAsFields (parameters , self .CATEGORIES_FIELD_NAME , context )
86
87
87
88
value_field_index = source .fields ().lookupField (value_field_name )
88
- value_field = source .fields ().at (value_field_index )
89
+ if value_field_index >= 0 :
90
+ value_field = source .fields ().at (value_field_index )
91
+ else :
92
+ value_field = None
89
93
category_field_indexes = [source .fields ().lookupField (n ) for n in category_field_names ]
90
94
91
95
# generate output fields
@@ -101,7 +105,10 @@ def addField(name):
101
105
field .setName (name )
102
106
fields .append (field )
103
107
104
- if value_field .isNumeric ():
108
+ if value_field is None :
109
+ field_type = 'none'
110
+ fields .append (QgsField ('count' , QVariant .Int ))
111
+ elif value_field .isNumeric ():
105
112
field_type = 'numeric'
106
113
fields .append (QgsField ('count' , QVariant .Int ))
107
114
fields .append (QgsField ('unique' , QVariant .Int ))
@@ -140,42 +147,50 @@ def addField(name):
140
147
fields .append (QgsField ('mean_length' , QVariant .Double ))
141
148
142
149
request = QgsFeatureRequest ().setFlags (QgsFeatureRequest .NoGeometry )
143
- attrs = [value_field_index ]
150
+ if value_field is not None :
151
+ attrs = [value_field_index ]
152
+ else :
153
+ attrs = []
144
154
attrs .extend (category_field_indexes )
145
155
request .setSubsetOfAttributes (attrs )
146
156
features = source .getFeatures (request )
147
157
total = 50.0 / source .featureCount () if source .featureCount () else 0
148
- values = defaultdict (list )
158
+ if field_type == 'none' :
159
+ values = defaultdict (lambda : 0 )
160
+ else :
161
+ values = defaultdict (list )
149
162
for current , feat in enumerate (features ):
150
163
if feedback .isCanceled ():
151
164
break
152
165
153
166
feedback .setProgress (int (current * total ))
154
167
attrs = feat .attributes ()
155
- if True :
156
- if field_type == 'numeric' :
157
- if attrs [value_field_index ] == NULL :
158
- continue
159
- else :
160
- value = float (attrs [value_field_index ])
161
- elif field_type == 'string' :
162
- if attrs [value_field_index ] == NULL :
163
- value = ''
164
- else :
165
- value = str (attrs [value_field_index ])
166
- elif attrs [value_field_index ] == NULL :
167
- value = NULL
168
+ cat = tuple ([attrs [c ] for c in category_field_indexes ])
169
+ if field_type == 'none' :
170
+ values [cat ] += 1
171
+ continue
172
+ if field_type == 'numeric' :
173
+ if attrs [value_field_index ] == NULL :
174
+ continue
168
175
else :
169
- value = attrs [value_field_index ]
170
- cat = tuple ([attrs [c ] for c in category_field_indexes ])
171
- values [cat ].append (value )
176
+ value = float (attrs [value_field_index ])
177
+ elif field_type == 'string' :
178
+ if attrs [value_field_index ] == NULL :
179
+ value = ''
180
+ else :
181
+ value = str (attrs [value_field_index ])
182
+ elif attrs [value_field_index ] == NULL :
183
+ value = NULL
172
184
else :
173
- pass
185
+ value = attrs [value_field_index ]
186
+ values [cat ].append (value )
174
187
175
188
(sink , dest_id ) = self .parameterAsSink (parameters , self .OUTPUT , context ,
176
189
fields , QgsWkbTypes .NoGeometry , QgsCoordinateReferenceSystem ())
177
190
178
- if field_type == 'numeric' :
191
+ if field_type == 'none' :
192
+ self .saveCounts (values , sink , feedback )
193
+ elif field_type == 'numeric' :
179
194
self .calcNumericStats (values , sink , feedback )
180
195
elif field_type == 'datetime' :
181
196
self .calcDateTimeStats (values , sink , feedback )
@@ -184,6 +199,19 @@ def addField(name):
184
199
185
200
return {self .OUTPUT : dest_id }
186
201
202
+ def saveCounts (self , values , sink , feedback ):
203
+ total = 50.0 / len (values ) if values else 0
204
+ current = 0
205
+ for cat , v in values .items ():
206
+ if feedback .isCanceled ():
207
+ break
208
+
209
+ feedback .setProgress (int (current * total ) + 50 )
210
+ f = QgsFeature ()
211
+ f .setAttributes (list (cat ) + [v ])
212
+ sink .addFeature (f , QgsFeatureSink .FastInsert )
213
+ current += 1
214
+
187
215
def calcNumericStats (self , values , sink , feedback ):
188
216
stat = QgsStatisticalSummary ()
189
217
0 commit comments