26
26
__revision__ = '$Format:%H$'
27
27
28
28
import os
29
+ from collections import OrderedDict
29
30
30
31
from qgis .PyQt .QtGui import QIcon
31
32
32
33
from qgis .core import (QgsFeatureRequest ,
33
- QgsMessageLog ,
34
- QgsProcessingUtils ,
35
- QgsProcessingParameterDefinition )
34
+ QgsProcessing ,
35
+ QgsProcessingException ,
36
+ QgsProcessingParameterVectorLayer ,
37
+ QgsProcessingParameterNumber ,
38
+ QgsProcessingParameterField ,
39
+ QgsProcessingParameterEnum ,
40
+ QgsProcessingParameterDefinition ,
41
+ QgsProcessingParameterRasterDestination )
42
+
36
43
from qgis .analysis import QgsKernelDensityEstimation
37
44
38
45
from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
39
- from processing .core .GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
40
- from processing .core .parameters import ParameterVector
41
- from processing .core .parameters import ParameterNumber
42
- from processing .core .parameters import ParameterSelection
43
- from processing .core .parameters import ParameterTableField
44
- from processing .core .outputs import OutputRaster
45
- from processing .tools import dataobjects , raster
46
- from processing .algs .qgis .ui .HeatmapWidgets import HeatmapPixelSizeWidgetWrapper
46
+ from processing .tools import raster
47
47
48
48
pluginPath = os .path .split (os .path .split (os .path .dirname (__file__ ))[0 ])[0 ]
49
49
@@ -55,18 +55,8 @@ class Heatmap(QgisAlgorithm):
55
55
RADIUS_FIELD = 'RADIUS_FIELD'
56
56
WEIGHT_FIELD = 'WEIGHT_FIELD'
57
57
PIXEL_SIZE = 'PIXEL_SIZE'
58
-
59
- KERNELS = ['Quartic' ,
60
- 'Triangular' ,
61
- 'Uniform' ,
62
- 'Triweight' ,
63
- 'Epanechnikov'
64
- ]
65
58
KERNEL = 'KERNEL'
66
59
DECAY = 'DECAY'
67
- OUTPUT_VALUES = ['Raw' ,
68
- 'Scaled'
69
- ]
70
60
OUTPUT_VALUE = 'OUTPUT_VALUE'
71
61
OUTPUT_LAYER = 'OUTPUT_LAYER'
72
62
@@ -79,74 +69,115 @@ def tags(self):
79
69
def group (self ):
80
70
return self .tr ('Interpolation' )
81
71
72
+ def name (self ):
73
+ return 'heatmapkerneldensityestimation'
74
+
75
+ def displayName (self ):
76
+ return self .tr ('Heatmap (Kernel Density Estimation)' )
77
+
82
78
def __init__ (self ):
83
79
super ().__init__ ()
84
80
85
81
def initAlgorithm (self , config = None ):
86
- self .addParameter (ParameterVector (self .INPUT_LAYER ,
87
- self .tr ('Point layer' ), [dataobjects .TYPE_VECTOR_POINT ]))
88
- self .addParameter (ParameterNumber (self .RADIUS ,
89
- self .tr ('Radius (layer units)' ),
90
- 0.0 , 9999999999 , 100.0 ))
91
-
92
- radius_field_param = ParameterTableField (self .RADIUS_FIELD ,
93
- self .tr ('Radius from field' ), self .INPUT_LAYER , optional = True , datatype = ParameterTableField .DATA_TYPE_NUMBER )
82
+ self .KERNELS = OrderedDict ([(self .tr ('Quartic' ), QgsKernelDensityEstimation .KernelQuartic ),
83
+ (self .tr ('Triangular' ), QgsKernelDensityEstimation .KernelTriangular ),
84
+ (self .tr ('Uniform' ), QgsKernelDensityEstimation .KernelUniform ),
85
+ (self .tr ('Triweight' ), QgsKernelDensityEstimation .KernelTriweight ),
86
+ (self .tr ('Epanechnikov' ), QgsKernelDensityEstimation .KernelEpanechnikov )])
87
+
88
+ self .OUTPUT_VALUES = OrderedDict ([(self .tr ('Raw' ), QgsKernelDensityEstimation .OutputRaw ),
89
+ (self .tr ('Scaled' ), QgsKernelDensityEstimation .OutputScaled )])
90
+
91
+ self .addParameter (QgsProcessingParameterVectorLayer (self .INPUT_LAYER ,
92
+ self .tr ('Point layer' ),
93
+ [QgsProcessing .TypeVectorPoint ]))
94
+
95
+ self .addParameter (QgsProcessingParameterNumber (self .RADIUS ,
96
+ self .tr ('Radius (layer units)' ),
97
+ QgsProcessingParameterNumber .Double ,
98
+ 100.0 , False , 0.0 , 9999999999.99 ))
99
+
100
+ radius_field_param = QgsProcessingParameterField (self .RADIUS_FIELD ,
101
+ self .tr ('Radius from field' ),
102
+ None ,
103
+ self .INPUT_LAYER ,
104
+ QgsProcessingParameterField .Numeric ,
105
+ optional = True
106
+ )
94
107
radius_field_param .setFlags (radius_field_param .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
95
108
self .addParameter (radius_field_param )
96
109
97
- class ParameterHeatmapPixelSize (ParameterNumber ):
110
+ class ParameterHeatmapPixelSize (QgsProcessingParameterNumber ):
98
111
99
112
def __init__ (self , name = '' , description = '' , parent_layer = None , radius_param = None , radius_field_param = None , minValue = None , maxValue = None ,
100
- default = None , optional = False , metadata = {} ):
101
- ParameterNumber .__init__ (self , name , description , minValue , maxValue , default , optional , metadata )
113
+ default = None , optional = False ):
114
+ QgsProcessingParameterNumber .__init__ (self , name , description , QgsProcessingParameterNumber . Double , default , optional , minValue , maxValue )
102
115
self .parent_layer = parent_layer
103
116
self .radius_param = radius_param
104
117
self .radius_field_param = radius_field_param
105
118
106
- self .addParameter (ParameterHeatmapPixelSize (self .PIXEL_SIZE ,
107
- self .tr ('Output raster size' ), parent_layer = self .INPUT_LAYER , radius_param = self .RADIUS ,
108
- radius_field_param = self .RADIUS_FIELD ,
109
- minValue = 0.0 , maxValue = 9999999999 , default = 0.1 ,
110
- metadata = {'widget_wrapper' : HeatmapPixelSizeWidgetWrapper }))
111
-
112
- weight_field_param = ParameterTableField (self .WEIGHT_FIELD ,
113
- self .tr ('Weight from field' ), self .INPUT_LAYER , optional = True , datatype = ParameterTableField .DATA_TYPE_NUMBER )
119
+ pixel_size_param = ParameterHeatmapPixelSize (self .PIXEL_SIZE ,
120
+ self .tr ('Output raster size' ),
121
+ parent_layer = self .INPUT_LAYER ,
122
+ radius_param = self .RADIUS ,
123
+ radius_field_param = self .RADIUS_FIELD ,
124
+ minValue = 0.0 ,
125
+ maxValue = 9999999999 ,
126
+ default = 0.1 )
127
+ pixel_size_param .setMetadata ({
128
+ 'widget_wrapper' : {
129
+ 'class' : 'processing.algs.qgis.ui.HeatmapWidgets.HeatmapPixelSizeWidgetWrapper' }})
130
+ self .addParameter (pixel_size_param )
131
+
132
+ weight_field_param = QgsProcessingParameterField (self .WEIGHT_FIELD ,
133
+ self .tr ('Weight from field' ),
134
+ None ,
135
+ self .INPUT_LAYER ,
136
+ QgsProcessingParameterField .Numeric ,
137
+ optional = True
138
+ )
114
139
weight_field_param .setFlags (weight_field_param .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
115
140
self .addParameter (weight_field_param )
116
- kernel_shape_param = ParameterSelection (self .KERNEL ,
117
- self .tr ('Kernel shape' ), self .KERNELS )
141
+
142
+ keys = list (self .KERNELS .keys ())
143
+ kernel_shape_param = QgsProcessingParameterEnum (self .KERNEL ,
144
+ self .tr ('Kernel shape' ),
145
+ keys ,
146
+ allowMultiple = False ,
147
+ defaultValue = 0 )
118
148
kernel_shape_param .setFlags (kernel_shape_param .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
119
149
self .addParameter (kernel_shape_param )
120
- decay_ratio = ParameterNumber (self .DECAY ,
121
- self .tr ('Decay ratio (Triangular kernels only)' ),
122
- - 100.0 , 100.0 , 0.0 )
150
+
151
+ decay_ratio = QgsProcessingParameterNumber (self .DECAY ,
152
+ self .tr ('Decay ratio (Triangular kernels only)' ),
153
+ QgsProcessingParameterNumber .Double ,
154
+ 0.0 , True , - 100.0 , 100.0 )
123
155
decay_ratio .setFlags (decay_ratio .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
124
156
self .addParameter (decay_ratio )
125
- output_scaling = ParameterSelection (self .OUTPUT_VALUE ,
126
- self .tr ('Output value scaling' ), self .OUTPUT_VALUES )
157
+
158
+ keys = list (self .OUTPUT_VALUES .keys ())
159
+ output_scaling = QgsProcessingParameterEnum (self .OUTPUT_VALUE ,
160
+ self .tr ('Output value scaling' ),
161
+ keys ,
162
+ allowMultiple = False ,
163
+ defaultValue = 0 )
127
164
output_scaling .setFlags (output_scaling .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
128
165
self .addParameter (output_scaling )
129
- self .addOutput (OutputRaster (self .OUTPUT_LAYER ,
130
- self .tr ('Heatmap' )))
131
166
132
- def name (self ):
133
- return 'heatmapkerneldensityestimation'
134
-
135
- def displayName (self ):
136
- return self .tr ('Heatmap (Kernel Density Estimation)' )
167
+ self .addParameter (QgsProcessingParameterRasterDestination (self .OUTPUT_LAYER , self .tr ('Heatmap' )))
137
168
138
169
def processAlgorithm (self , parameters , context , feedback ):
139
- layer = QgsProcessingUtils . mapLayerFromString ( self .getParameterValue ( self .INPUT_LAYER ) , context )
140
-
141
- radius = self .getParameterValue ( self .RADIUS )
142
- kernel_shape = self .getParameterValue ( self .KERNEL )
143
- pixel_size = self .getParameterValue ( self .PIXEL_SIZE )
144
- decay = self .getParameterValue ( self .DECAY )
145
- output_values = self .getParameterValue ( self .OUTPUT_VALUE )
146
- output = self .getOutputValue ( self .OUTPUT_LAYER )
147
- output_format = raster .formatShortNameFromFileName (output )
148
- weight_field = self .getParameterValue ( self .WEIGHT_FIELD )
149
- radius_field = self .getParameterValue ( self .RADIUS_FIELD )
170
+ layer = self .parameterAsVectorLayer ( parameters , self .INPUT_LAYER , context )
171
+
172
+ radius = self .parameterAsDouble ( parameters , self .RADIUS , context )
173
+ kernel_shape = self .parameterAsEnum ( parameters , self .KERNEL , context )
174
+ pixel_size = self .parameterAsDouble ( parameters , self .PIXEL_SIZE , context )
175
+ decay = self .parameterAsDouble ( parameters , self .DECAY , context )
176
+ output_values = self .parameterAsEnum ( parameters , self .OUTPUT_VALUE , context )
177
+ outputFile = self .parameterAsOutputLayer ( parameters , self .OUTPUT_LAYER , context )
178
+ output_format = raster .formatShortNameFromFileName (outputFile )
179
+ weight_field = self .parameterAsString ( parameters , self .WEIGHT_FIELD , context )
180
+ radius_field = self .parameterAsString ( parameters , self .RADIUS_FIELD , context )
150
181
151
182
attrs = []
152
183
@@ -167,22 +198,27 @@ def processAlgorithm(self, parameters, context, feedback):
167
198
kde_params .decayRatio = decay
168
199
kde_params .outputValues = output_values
169
200
170
- kde = QgsKernelDensityEstimation (kde_params , output , output_format )
201
+ kde = QgsKernelDensityEstimation (kde_params , outputFile , output_format )
171
202
172
203
if kde .prepare () != QgsKernelDensityEstimation .Success :
173
- raise GeoAlgorithmExecutionException (
204
+ raise QgsProcessingException (
174
205
self .tr ('Could not create destination layer' ))
175
206
176
207
request = QgsFeatureRequest ()
177
208
request .setSubsetOfAttributes (attrs )
178
- features = QgsProcessingUtils .getFeatures (layer , context , request )
209
+ features = layer .getFeatures (request )
179
210
total = 100.0 / layer .featureCount () if layer .featureCount () else 0
180
211
for current , f in enumerate (features ):
212
+ if feedback .isCanceled ():
213
+ break
214
+
181
215
if kde .addFeature (f ) != QgsKernelDensityEstimation .Success :
182
- QgsMessageLog . logMessage (self .tr ('Error adding feature with ID {} to heatmap' ).format (f .id ()), self .tr ('Processing' ), QgsMessageLog .CRITICAL )
216
+ feedback . reportError (self .tr ('Error adding feature with ID {} to heatmap' ).format (f .id ()), self .tr ('Processing' ), QgsMessageLog .CRITICAL )
183
217
184
218
feedback .setProgress (int (current * total ))
185
219
186
220
if kde .finalise () != QgsKernelDensityEstimation .Success :
187
- raise GeoAlgorithmExecutionException (
221
+ raise QgsProcessingException (
188
222
self .tr ('Could not save destination layer' ))
223
+
224
+ return {self .OUTPUT_LAYER : outputFile }
0 commit comments