Skip to content

Commit 83c38b0

Browse files
committedDec 6, 2016
[FEATURE][processing] Port heatmap plugin to processing algorithm
1 parent f212746 commit 83c38b0

File tree

4 files changed

+155
-1
lines changed

4 files changed

+155
-1
lines changed
 
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
***************************************************************************
5+
Heatmap.py
6+
---------------------
7+
Date : November 2016
8+
Copyright : (C) 2016 by Nyall Dawson
9+
Email : nyall dot dawson at gmail dot com
10+
***************************************************************************
11+
* *
12+
* This program is free software; you can redistribute it and/or modify *
13+
* it under the terms of the GNU General Public License as published by *
14+
* the Free Software Foundation; either version 2 of the License, or *
15+
* (at your option) any later version. *
16+
* *
17+
***************************************************************************
18+
"""
19+
20+
__author__ = 'Nyall Dawson'
21+
__date__ = 'November 2016'
22+
__copyright__ = '(C) 2016, Nyall Dawson'
23+
24+
# This will get replaced with a git SHA1 when you do a git archive
25+
26+
__revision__ = '$Format:%H$'
27+
28+
import os
29+
30+
from qgis.PyQt.QtGui import QIcon
31+
32+
from qgis.core import QgsFeatureRequest
33+
from qgis.analysis import QgsKernelDensityEstimation
34+
35+
from processing.core.GeoAlgorithm import GeoAlgorithm
36+
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
37+
from processing.core.parameters import ParameterVector
38+
from processing.core.parameters import ParameterNumber
39+
from processing.core.parameters import ParameterExtent
40+
from processing.core.parameters import ParameterSelection
41+
from processing.core.parameters import ParameterTableField
42+
from processing.core.outputs import OutputRaster
43+
from processing.tools import dataobjects, vector, raster
44+
45+
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
46+
47+
48+
class Heatmap(GeoAlgorithm):
49+
50+
INPUT_LAYER = 'INPUT_LAYER'
51+
RADIUS = 'RADIUS'
52+
RADIUS_FIELD = 'RADIUS_FIELD'
53+
WEIGHT_FIELD = 'WEIGHT_FIELD'
54+
PIXEL_SIZE = 'PIXEL_SIZE'
55+
56+
KERNELS = ['Quartic',
57+
'Triangular',
58+
'Uniform',
59+
'Triweight',
60+
'Epanechnikov'
61+
]
62+
KERNEL = 'KERNEL'
63+
DECAY = 'DECAY'
64+
OUTPUT_VALUES = ['Raw',
65+
'Scaled'
66+
]
67+
OUTPUT_VALUE = 'OUTPUT_VALUE'
68+
OUTPUT_LAYER = 'OUTPUT_LAYER'
69+
70+
def getIcon(self):
71+
return QIcon(os.path.join(pluginPath, 'images', 'heatmap.png'))
72+
73+
def defineCharacteristics(self):
74+
self.name, self.i18n_name = self.trAlgorithm('Heatmap (Kernel Density Estimation)')
75+
self.group, self.i18n_group = self.trAlgorithm('Interpolation')
76+
self.tags = self.tr('heatmap,kde,hotspot')
77+
78+
self.addParameter(ParameterVector(self.INPUT_LAYER,
79+
self.tr('Point layer'), [dataobjects.TYPE_VECTOR_POINT]))
80+
self.addParameter(ParameterNumber(self.RADIUS,
81+
self.tr('Radius (layer units)'),
82+
0.0, 9999999999, 100.0))
83+
self.addParameter(ParameterNumber(self.PIXEL_SIZE,
84+
self.tr('Output pixel size (layer units)'),
85+
0.0, 9999999999, 0.1))
86+
self.addParameter(ParameterTableField(self.RADIUS_FIELD,
87+
self.tr('Radius from field'), self.INPUT_LAYER, optional=True, datatype=ParameterTableField.DATA_TYPE_NUMBER))
88+
self.addParameter(ParameterTableField(self.WEIGHT_FIELD,
89+
self.tr('Weight from field'), self.INPUT_LAYER, optional=True, datatype=ParameterTableField.DATA_TYPE_NUMBER))
90+
self.addParameter(ParameterSelection(self.KERNEL,
91+
self.tr('Kernel shape'), self.KERNELS))
92+
self.addParameter(ParameterNumber(self.DECAY,
93+
self.tr('Decay ratio (Triangular kernels only)'),
94+
-100.0, 100.0, 0.0))
95+
self.addParameter(ParameterSelection(self.OUTPUT_VALUE,
96+
self.tr('Output value scaling'), self.OUTPUT_VALUES))
97+
self.addOutput(OutputRaster(self.OUTPUT_LAYER,
98+
self.tr('Heatmap')))
99+
100+
def processAlgorithm(self, progress):
101+
layer = dataobjects.getObjectFromUri(
102+
self.getParameterValue(self.INPUT_LAYER))
103+
104+
radius = self.getParameterValue(self.RADIUS)
105+
kernel_shape = self.getParameterValue(self.KERNEL)
106+
pixel_size = self.getParameterValue(self.PIXEL_SIZE)
107+
decay = self.getParameterValue(self.DECAY)
108+
output_values = self.getParameterValue(self.OUTPUT_VALUE)
109+
output = self.getOutputValue(self.OUTPUT_LAYER)
110+
output_format = raster.formatShortNameFromFileName(output)
111+
weight_field = self.getParameterValue(self.WEIGHT_FIELD)
112+
radius_field = self.getParameterValue(self.RADIUS_FIELD)
113+
114+
attrs = []
115+
116+
kde_params = QgsKernelDensityEstimation.Parameters()
117+
kde_params.vectorLayer = layer
118+
kde_params.radius = radius
119+
kde_params.pixelSize = pixel_size
120+
# radius field
121+
if radius_field:
122+
kde_params.radiusField = radius_field
123+
attrs.append(layer.fields().lookupField(radius_field))
124+
# weight field
125+
if weight_field:
126+
kde_params.weightField = weight_field
127+
attrs.append(layer.fields().lookupField(weight_field))
128+
129+
kde_params.shape = kernel_shape
130+
kde_params.decayRatio = decay
131+
kde_params.outputValues = output_values
132+
133+
kde = QgsKernelDensityEstimation(kde_params, output, output_format)
134+
135+
if kde.prepare() != QgsKernelDensityEstimation.Success:
136+
raise GeoAlgorithmExecutionException(
137+
self.tr('Could not create destination layer'))
138+
139+
request = QgsFeatureRequest()
140+
request.setSubsetOfAttributes(attrs)
141+
features = vector.features(layer, request)
142+
total = 100.0 / len(features)
143+
for current, f in enumerate(features):
144+
if kde.addFeature(f) != QgsKernelDensityEstimation.Success:
145+
raise GeoAlgorithmExecutionException(
146+
self.tr('Error adding feature to heatmap'))
147+
148+
progress.setPercentage(int(current * total))
149+
150+
if kde.finalise() != QgsKernelDensityEstimation.Success:
151+
raise GeoAlgorithmExecutionException(
152+
self.tr('Could not save destination layer'))

‎python/plugins/processing/algs/qgis/IdwInterpolationZValue.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
)
3737

3838
from processing.core.GeoAlgorithm import GeoAlgorithm
39+
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
3940
from processing.core.parameters import ParameterVector
4041
from processing.core.parameters import ParameterSelection
4142
from processing.core.parameters import ParameterNumber

‎python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@
182182
from .CreateAttributeIndex import CreateAttributeIndex
183183
from .DropGeometry import DropGeometry
184184
from .BasicStatistics import BasicStatisticsForField
185+
from .Heatmap import Heatmap
185186

186187
pluginPath = os.path.normpath(os.path.join(
187188
os.path.split(os.path.dirname(__file__))[0], os.pardir))
@@ -246,7 +247,7 @@ def __init__(self):
246247
RemoveNullGeometry(), ExtractByExpression(), ExtendLines(),
247248
ExtractSpecificNodes(), GeometryByExpression(), SnapGeometriesToLayer(),
248249
PoleOfInaccessibility(), CreateAttributeIndex(), DropGeometry(),
249-
BasicStatisticsForField(), RasterCalculator()
250+
BasicStatisticsForField(), RasterCalculator(), Heatmap()
250251
]
251252

252253
if hasMatplotlib:
1.24 KB
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.