Skip to content

Commit b441a4f

Browse files
committedJul 15, 2017
Port nearest neighbour analysis algorithm to new API
1 parent 8af7318 commit b441a4f

File tree

2 files changed

+59
-45
lines changed

2 files changed

+59
-45
lines changed
 

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

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,25 @@
3333

3434
from qgis.PyQt.QtGui import QIcon
3535

36-
from qgis.core import QgsFeatureRequest, QgsFeature, QgsDistanceArea, QgsProcessingUtils
36+
from qgis.core import (QgsFeatureRequest,
37+
QgsDistanceArea,
38+
QgsProject,
39+
QgsProcessing,
40+
QgsProcessingParameterFeatureSource,
41+
QgsProcessingParameterFileDestination,
42+
QgsProcessingOutputHtml,
43+
QgsProcessingOutputNumber,
44+
QgsSpatialIndex)
3745

3846
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
39-
from processing.core.parameters import ParameterVector
40-
from processing.core.outputs import OutputHTML
41-
from processing.core.outputs import OutputNumber
42-
from processing.tools import dataobjects
4347

4448
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4549

4650

4751
class NearestNeighbourAnalysis(QgisAlgorithm):
4852

49-
POINTS = 'POINTS'
50-
OUTPUT = 'OUTPUT'
53+
INPUT = 'INPUT'
54+
OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE'
5155
OBSERVED_MD = 'OBSERVED_MD'
5256
EXPECTED_MD = 'EXPECTED_MD'
5357
NN_INDEX = 'NN_INDEX'
@@ -64,20 +68,21 @@ def __init__(self):
6468
super().__init__()
6569

6670
def initAlgorithm(self, config=None):
67-
self.addParameter(ParameterVector(self.POINTS,
68-
self.tr('Points'), [dataobjects.TYPE_VECTOR_POINT]))
69-
70-
self.addOutput(OutputHTML(self.OUTPUT, self.tr('Nearest neighbour')))
71-
72-
self.addOutput(OutputNumber(self.OBSERVED_MD,
73-
self.tr('Observed mean distance')))
74-
self.addOutput(OutputNumber(self.EXPECTED_MD,
75-
self.tr('Expected mean distance')))
76-
self.addOutput(OutputNumber(self.NN_INDEX,
77-
self.tr('Nearest neighbour index')))
78-
self.addOutput(OutputNumber(self.POINT_COUNT,
79-
self.tr('Number of points')))
80-
self.addOutput(OutputNumber(self.Z_SCORE, self.tr('Z-Score')))
71+
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
72+
self.tr('Input layer'), [QgsProcessing.TypeVectorPoint]))
73+
74+
self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT_HTML_FILE, self.tr('Nearest neighbour'), self.tr('HTML files (*.html)'), None, True))
75+
self.addOutput(QgsProcessingOutputHtml(self.OUTPUT_HTML_FILE, self.tr('Nearest neighbour')))
76+
77+
self.addOutput(QgsProcessingOutputNumber(self.OBSERVED_MD,
78+
self.tr('Observed mean distance')))
79+
self.addOutput(QgsProcessingOutputNumber(self.EXPECTED_MD,
80+
self.tr('Expected mean distance')))
81+
self.addOutput(QgsProcessingOutputNumber(self.NN_INDEX,
82+
self.tr('Nearest neighbour index')))
83+
self.addOutput(QgsProcessingOutputNumber(self.POINT_COUNT,
84+
self.tr('Number of points')))
85+
self.addOutput(QgsProcessingOutputNumber(self.Z_SCORE, self.tr('Z-Score')))
8186

8287
def name(self):
8388
return 'nearestneighbouranalysis'
@@ -86,26 +91,30 @@ def displayName(self):
8691
return self.tr('Nearest neighbour analysis')
8792

8893
def processAlgorithm(self, parameters, context, feedback):
89-
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POINTS), context)
90-
output = self.getOutputValue(self.OUTPUT)
94+
source = self.parameterAsSource(parameters, self.INPUT, context)
95+
output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
9196

92-
spatialIndex = QgsProcessingUtils.createSpatialIndex(layer, context)
97+
spatialIndex = QgsSpatialIndex(source)
9398

94-
neighbour = QgsFeature()
9599
distance = QgsDistanceArea()
100+
distance.setSourceCrs(source.sourceCrs())
101+
distance.setEllipsoid(QgsProject.instance().ellipsoid())
96102

97103
sumDist = 0.00
98-
A = layer.extent()
104+
A = source.sourceExtent()
99105
A = float(A.width() * A.height())
100106

101-
features = QgsProcessingUtils.getFeatures(layer, context)
102-
count = QgsProcessingUtils.featureCount(layer, context)
107+
features = source.getFeatures()
108+
count = source.featureCount()
103109
total = 100.0 / count if count else 1
104110
for current, feat in enumerate(features):
111+
if feedback.isCanceled():
112+
break
113+
105114
neighbourID = spatialIndex.nearestNeighbor(
106115
feat.geometry().asPoint(), 2)[1]
107116
request = QgsFeatureRequest().setFilterFid(neighbourID).setSubsetOfAttributes([])
108-
neighbour = next(layer.getFeatures(request))
117+
neighbour = next(source.getFeatures(request))
109118
sumDist += distance.measureLine(neighbour.geometry().asPoint(),
110119
feat.geometry().asPoint())
111120

@@ -117,20 +126,24 @@ def processAlgorithm(self, parameters, context, feedback):
117126
SE = float(0.26136 / math.sqrt(count ** 2 / A))
118127
zscore = float((do - de) / SE)
119128

120-
data = []
121-
data.append('Observed mean distance: ' + str(do))
122-
data.append('Expected mean distance: ' + str(de))
123-
data.append('Nearest neighbour index: ' + str(d))
124-
data.append('Number of points: ' + str(count))
125-
data.append('Z-Score: ' + str(zscore))
126-
127-
self.createHTML(output, data)
128-
129-
self.setOutputValue(self.OBSERVED_MD, float(data[0].split(': ')[1]))
130-
self.setOutputValue(self.EXPECTED_MD, float(data[1].split(': ')[1]))
131-
self.setOutputValue(self.NN_INDEX, float(data[2].split(': ')[1]))
132-
self.setOutputValue(self.POINT_COUNT, float(data[3].split(': ')[1]))
133-
self.setOutputValue(self.Z_SCORE, float(data[4].split(': ')[1]))
129+
results = {}
130+
results[self.OBSERVED_MD] = do
131+
results[self.EXPECTED_MD] = de
132+
results[self.NN_INDEX] = d
133+
results[self.POINT_COUNT] = count
134+
results[self.Z_SCORE] = zscore
135+
136+
if output_file:
137+
data = []
138+
data.append('Observed mean distance: ' + str(do))
139+
data.append('Expected mean distance: ' + str(de))
140+
data.append('Nearest neighbour index: ' + str(d))
141+
data.append('Number of points: ' + str(count))
142+
data.append('Z-Score: ' + str(zscore))
143+
self.createHTML(output_file, data)
144+
results[self.OUTPUT_HTML_FILE] = output_file
145+
146+
return results
134147

135148
def createHTML(self, outputFile, algData):
136149
with codecs.open(outputFile, 'w', encoding='utf-8') as f:

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
from .Intersection import Intersection
6666
from .LinesToPolygons import LinesToPolygons
6767
from .Merge import Merge
68+
from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
6869
from .PointsInPolygon import PointsInPolygon
6970
from .PointsLayerFromTable import PointsLayerFromTable
7071
from .PolygonsToLines import PolygonsToLines
@@ -87,7 +88,6 @@
8788
from .ZonalStatistics import ZonalStatistics
8889

8990
# from .ExtractByLocation import ExtractByLocation
90-
# from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
9191
# from .LinesIntersection import LinesIntersection
9292
# from .MeanCoords import MeanCoords
9393
# from .PointDistance import PointDistance
@@ -183,7 +183,7 @@ def __init__(self):
183183
self.externalAlgs = []
184184

185185
def getAlgs(self):
186-
# algs = [NearestNeighbourAnalysis(), MeanCoords(),
186+
# algs = [MeanCoords(),
187187
# LinesIntersection(), UniqueValues(), PointDistance(),
188188
# ExportGeometryInfo(),
189189
# SinglePartsToMultiparts(),
@@ -259,6 +259,7 @@ def getAlgs(self):
259259
Intersection(),
260260
LinesToPolygons(),
261261
Merge(),
262+
NearestNeighbourAnalysis(),
262263
PointsInPolygon(),
263264
PointsLayerFromTable(),
264265
PolygonsToLines(),

0 commit comments

Comments
 (0)
Please sign in to comment.