Skip to content

Commit

Permalink
Port Unique Values algorithm to new API
Browse files Browse the repository at this point in the history
Improvements:
- by default output a table with unique values, instead of a HTML
file. This allows the values to be more easily used in follow up
analysis (e.g. in a model). HTML output is still available, but
not output by default
  • Loading branch information
nyalldawson committed Jul 15, 2017
1 parent 82edbab commit ea06500
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 25 deletions.
5 changes: 3 additions & 2 deletions python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Expand Up @@ -89,12 +89,12 @@
from .SumLines import SumLines
from .SymmetricalDifference import SymmetricalDifference
from .Union import Union
from .UniqueValues import UniqueValues
from .VectorSplit import VectorSplit
from .VoronoiPolygons import VoronoiPolygons
from .ZonalStatistics import ZonalStatistics

# from .ExtractByLocation import ExtractByLocation
# from .UniqueValues import UniqueValues
# from .ExportGeometryInfo import ExportGeometryInfo
# from .SinglePartsToMultiparts import SinglePartsToMultiparts
# from .ExtractNodes import ExtractNodes
Expand Down Expand Up @@ -184,7 +184,7 @@ def __init__(self):

def getAlgs(self):
# algs = [
# UniqueValues(),
#
# ExportGeometryInfo(),
# SinglePartsToMultiparts(),
# ExtractNodes(),
Expand Down Expand Up @@ -283,6 +283,7 @@ def getAlgs(self):
SumLines(),
SymmetricalDifference(),
Union(),
UniqueValues(),
VectorSplit(),
VoronoiPolygons(),
ZonalStatistics()
Expand Down
79 changes: 56 additions & 23 deletions python/plugins/processing/algs/qgis/UniqueValues.py
Expand Up @@ -31,25 +31,32 @@

from qgis.PyQt.QtGui import QIcon

from qgis.core import QgsProcessingUtils, QgsFeatureSink
from qgis.core import (QgsCoordinateReferenceSystem,
QgsWkbTypes,
QgsFeature,
QgsFeatureSink,
QgsFields,
QgsProcessingParameterField,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputNumber,
QgsProcessingOutputString,
QgsProcessingParameterFileDestination,
QgsProcessingOutputHtml)

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterTableField
from processing.core.outputs import OutputHTML
from processing.core.outputs import OutputNumber
from processing.core.outputs import OutputString

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


class UniqueValues(QgisAlgorithm):

INPUT_LAYER = 'INPUT_LAYER'
INPUT = 'INPUT'
FIELD_NAME = 'FIELD_NAME'
TOTAL_VALUES = 'TOTAL_VALUES'
UNIQUE_VALUES = 'UNIQUE_VALUES'
OUTPUT = 'OUTPUT'
OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE'

def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'unique.png'))
Expand All @@ -61,14 +68,18 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer')))
self.addParameter(ParameterTableField(self.FIELD_NAME,
self.tr('Target field'),
self.INPUT_LAYER, ParameterTableField.DATA_TYPE_ANY))
self.addOutput(OutputHTML(self.OUTPUT, self.tr('Unique values')))
self.addOutput(OutputNumber(self.TOTAL_VALUES, self.tr('Total unique values')))
self.addOutput(OutputString(self.UNIQUE_VALUES, self.tr('Unique values')))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer')))
self.addParameter(QgsProcessingParameterField(self.FIELD_NAME,
self.tr('Target field'),
parentLayerParameterName=self.INPUT, type=QgsProcessingParameterField.Any))

self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Unique values'), optional=True, defaultValue=''))

self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT_HTML_FILE, self.tr('HTML report'), self.tr('HTML files (*.html)'), None, True))
self.addOutput(QgsProcessingOutputHtml(self.OUTPUT_HTML_FILE, self.tr('HTML report')))
self.addOutput(QgsProcessingOutputNumber(self.TOTAL_VALUES, self.tr('Total unique values')))
self.addOutput(QgsProcessingOutputString(self.UNIQUE_VALUES, self.tr('Unique values')))

def name(self):
return 'listuniquevalues'
Expand All @@ -77,14 +88,36 @@ def displayName(self):
return self.tr('List unique values')

def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
fieldName = self.getParameterValue(self.FIELD_NAME)
outputFile = self.getOutputValue(self.OUTPUT)
values = QgsProcessingUtils.uniqueValues(layer, layer.fields().lookupField(fieldName), context)
self.createHTML(outputFile, values)
self.setOutputValue(self.TOTAL_VALUES, len(values))
self.setOutputValue(self.UNIQUE_VALUES, ';'.join([str(v) for v in
values]))
source = self.parameterAsSource(parameters, self.INPUT, context)
field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
values = source.uniqueValues(source.fields().lookupField(field_name))

fields = QgsFields()
field = source.fields()[source.fields().lookupField(field_name)]
field.setName('VALUES')
fields.append(field)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
results = {}
if sink:
for value in values:
if feedback.isCanceled():
break

f = QgsFeature()
f.setAttributes([value])
sink.addFeature(f, QgsFeatureSink.FastInsert)
results[self.OUTPUT] = dest_id

output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
if output_file:
self.createHTML(output_file, values)
results[self.OUTPUT_HTML_FILE] = output_file

results[self.TOTAL_VALUES] = len(values)
results[self.UNIQUE_VALUES] = ';'.join([str(v) for v in
values])
return results

def createHTML(self, outputFile, algData):
with codecs.open(outputFile, 'w', encoding='utf-8') as f:
Expand Down
@@ -0,0 +1,15 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>unique_values</Name>
<ElementPath>unique_values</ElementPath>
<GeometryType>100</GeometryType>
<DatasetSpecificInfo>
<FeatureCount>3</FeatureCount>
</DatasetSpecificInfo>
<PropertyDefn>
<Name>VALUES</Name>
<ElementPath>VALUES</ElementPath>
<Type>Integer</Type>
</PropertyDefn>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

<gml:featureMember>
<ogr:unique_values fid="unique_values.0">
<ogr:VALUES>0</ogr:VALUES>
</ogr:unique_values>
</gml:featureMember>
<gml:featureMember>
<ogr:unique_values fid="unique_values.1">
<ogr:VALUES>1</ogr:VALUES>
</ogr:unique_values>
</gml:featureMember>
<gml:featureMember>
<ogr:unique_values fid="unique_values.2">
<ogr:VALUES>2</ogr:VALUES>
</ogr:unique_values>
</gml:featureMember>
</ogr:FeatureCollection>
13 changes: 13 additions & 0 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -241,6 +241,19 @@ tests:
# geometry:
# precision: 7
#

- algorithm: qgis:listuniquevalues
name: Unique values
params:
INPUT:
name: points.gml
type: vector
FIELD_NAME: id2
results:
OUTPUT:
name: expected/unique_values.gml
type: vector

- algorithm: qgis:addautoincrementalfield
name: Add autoincremental field
params:
Expand Down

0 comments on commit ea06500

Please sign in to comment.