2626__revision__ = '$Format:%H$'
2727
2828import os
29+ from collections import OrderedDict
2930
3031from qgis .PyQt .QtGui import QIcon
3132
3233from 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+
3643from qgis .analysis import QgsKernelDensityEstimation
3744
3845from 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
4747
4848pluginPath = os .path .split (os .path .split (os .path .dirname (__file__ ))[0 ])[0 ]
4949
@@ -55,18 +55,8 @@ class Heatmap(QgisAlgorithm):
5555 RADIUS_FIELD = 'RADIUS_FIELD'
5656 WEIGHT_FIELD = 'WEIGHT_FIELD'
5757 PIXEL_SIZE = 'PIXEL_SIZE'
58-
59- KERNELS = ['Quartic' ,
60- 'Triangular' ,
61- 'Uniform' ,
62- 'Triweight' ,
63- 'Epanechnikov'
64- ]
6558 KERNEL = 'KERNEL'
6659 DECAY = 'DECAY'
67- OUTPUT_VALUES = ['Raw' ,
68- 'Scaled'
69- ]
7060 OUTPUT_VALUE = 'OUTPUT_VALUE'
7161 OUTPUT_LAYER = 'OUTPUT_LAYER'
7262
@@ -79,74 +69,115 @@ def tags(self):
7969 def group (self ):
8070 return self .tr ('Interpolation' )
8171
72+ def name (self ):
73+ return 'heatmapkerneldensityestimation'
74+
75+ def displayName (self ):
76+ return self .tr ('Heatmap (Kernel Density Estimation)' )
77+
8278 def __init__ (self ):
8379 super ().__init__ ()
8480
8581 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+ )
94107 radius_field_param .setFlags (radius_field_param .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
95108 self .addParameter (radius_field_param )
96109
97- class ParameterHeatmapPixelSize (ParameterNumber ):
110+ class ParameterHeatmapPixelSize (QgsProcessingParameterNumber ):
98111
99112 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 )
102115 self .parent_layer = parent_layer
103116 self .radius_param = radius_param
104117 self .radius_field_param = radius_field_param
105118
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+ )
114139 weight_field_param .setFlags (weight_field_param .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
115140 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 )
118148 kernel_shape_param .setFlags (kernel_shape_param .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
119149 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 )
123155 decay_ratio .setFlags (decay_ratio .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
124156 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 )
127164 output_scaling .setFlags (output_scaling .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
128165 self .addParameter (output_scaling )
129- self .addOutput (OutputRaster (self .OUTPUT_LAYER ,
130- self .tr ('Heatmap' )))
131166
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' )))
137168
138169 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 )
150181
151182 attrs = []
152183
@@ -167,22 +198,27 @@ def processAlgorithm(self, parameters, context, feedback):
167198 kde_params .decayRatio = decay
168199 kde_params .outputValues = output_values
169200
170- kde = QgsKernelDensityEstimation (kde_params , output , output_format )
201+ kde = QgsKernelDensityEstimation (kde_params , outputFile , output_format )
171202
172203 if kde .prepare () != QgsKernelDensityEstimation .Success :
173- raise GeoAlgorithmExecutionException (
204+ raise QgsProcessingException (
174205 self .tr ('Could not create destination layer' ))
175206
176207 request = QgsFeatureRequest ()
177208 request .setSubsetOfAttributes (attrs )
178- features = QgsProcessingUtils .getFeatures (layer , context , request )
209+ features = layer .getFeatures (request )
179210 total = 100.0 / layer .featureCount () if layer .featureCount () else 0
180211 for current , f in enumerate (features ):
212+ if feedback .isCanceled ():
213+ break
214+
181215 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 )
183217
184218 feedback .setProgress (int (current * total ))
185219
186220 if kde .finalise () != QgsKernelDensityEstimation .Success :
187- raise GeoAlgorithmExecutionException (
221+ raise QgsProcessingException (
188222 self .tr ('Could not save destination layer' ))
223+
224+ return {self .OUTPUT_LAYER : outputFile }
0 commit comments