Skip to content

Commit c8aceb2

Browse files
committed
[processing] add Extract by expression algorithm as combination
of "Select by expression" and "Save selected features" does not work in modeler
1 parent 88dc615 commit c8aceb2

File tree

5 files changed

+167
-1
lines changed

5 files changed

+167
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
***************************************************************************
5+
ExtractByExpression.py
6+
---------------------
7+
Date : September 2017
8+
Copyright : (C) 2017 by Alexander Bruy
9+
Email : alexander dot bruy 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__ = 'Alexander Bruy'
21+
__date__ = 'September 2017'
22+
__copyright__ = '(C) 2017, Alexander Bruy'
23+
24+
# This will get replaced with a git SHA1 when you do a git archive
25+
26+
__revision__ = '$Format:%H$'
27+
28+
from qgis.core import QgsExpression, QgsExpressionContext, QgsExpressionContextUtils, QgsFeatureRequest
29+
from processing.core.GeoAlgorithm import GeoAlgorithm
30+
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
31+
from processing.core.parameters import ParameterVector
32+
from processing.core.parameters import ParameterString
33+
from processing.core.outputs import OutputVector
34+
from processing.tools import dataobjects
35+
36+
37+
class ExtractByExpression(GeoAlgorithm):
38+
39+
INPUT = 'INPUT'
40+
EXPRESSION = 'EXPRESSION'
41+
OUTPUT = 'OUTPUT'
42+
43+
def defineCharacteristics(self):
44+
self.name, self.i18n_name = self.trAlgorithm('Extract by expression')
45+
self.group, self.i18n_group = self.trAlgorithm('Vector selection tools')
46+
47+
self.addParameter(ParameterVector(self.INPUT,
48+
self.tr('Input Layer'), [ParameterVector.VECTOR_TYPE_ANY]))
49+
self.addParameter(ParameterString(self.EXPRESSION,
50+
self.tr("Expression")))
51+
self.addOutput(OutputVector(self.OUTPUT, self.tr('Extracted (expression)')))
52+
53+
def processAlgorithm(self, progress):
54+
layer = layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
55+
56+
expression = self.getParameterValue(self.EXPRESSION)
57+
qExp = QgsExpression(expression)
58+
if qExp.hasParserError():
59+
raise GeoAlgorithmExecutionException(qExp.parserErrorString())
60+
61+
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
62+
layer.fields(), layer.wkbType(), layer.crs())
63+
64+
context = QgsExpressionContext()
65+
context.appendScope(QgsExpressionContextUtils.globalScope())
66+
context.appendScope(QgsExpressionContextUtils.projectScope())
67+
context.appendScope(QgsExpressionContextUtils.layerScope(layer))
68+
69+
count = layer.featureCount()
70+
step = 100.0 / count if count else 1
71+
72+
request = QgsFeatureRequest(qExp, context)
73+
74+
for current, f in enumerate(layer.getFeatures(request)):
75+
writer.addFeature(f)
76+
progress.setPercentage(int(current * step))
77+
78+
del writer

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
from .RandomExtract import RandomExtract
5656
from .RandomExtractWithinSubsets import RandomExtractWithinSubsets
5757
from .ExtractByLocation import ExtractByLocation
58+
from .ExtractByExpression import ExtractByExpression
5859
from .PointsInPolygon import PointsInPolygon
5960
from .PointsInPolygonUnique import PointsInPolygonUnique
6061
from .PointsInPolygonWeighted import PointsInPolygonWeighted
@@ -192,7 +193,7 @@ def __init__(self):
192193
ZonalStatistics(), PointsFromPolygons(),
193194
PointsFromLines(), RandomPointsExtent(),
194195
RandomPointsLayer(), RandomPointsPolygonsFixed(),
195-
RandomPointsPolygonsVariable(),
196+
RandomPointsPolygonsVariable(), ExtractByExpression(),
196197
RandomPointsAlongLines(), PointsToPaths(),
197198
PostGISExecuteSQL(), ImportIntoPostGIS(),
198199
SetVectorStyle(), SetRasterStyle(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://ogr.maptools.org/ extract_expression.xsd"
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>4</gml:X><gml:Y>-3</gml:Y></gml:coord>
10+
<gml:coord><gml:X>10</gml:X><gml:Y>5</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:extract_expression fid="polys.1">
16+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,5 6,4 4,4 5,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
17+
<ogr:name>Aaaaa</ogr:name>
18+
<ogr:intval>-33</ogr:intval>
19+
<ogr:floatval>0.00000</ogr:floatval>
20+
</ogr:extract_expression>
21+
</gml:featureMember>
22+
<gml:featureMember>
23+
<ogr:extract_expression fid="polys.3">
24+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,1 10,1 10,-3 6,-3 6,1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,0 7,-2 9,-2 9,0 7,0</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></ogr:geometryProperty>
25+
<ogr:name>ASDF</ogr:name>
26+
<ogr:intval>0</ogr:intval>
27+
<ogr:floatval xsi:nil="true"/>
28+
</ogr:extract_expression>
29+
</gml:featureMember>
30+
</ogr:FeatureCollection>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
3+
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
4+
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
5+
<xs:complexType name="FeatureCollectionType">
6+
<xs:complexContent>
7+
<xs:extension base="gml:AbstractFeatureCollectionType">
8+
<xs:attribute name="lockId" type="xs:string" use="optional"/>
9+
<xs:attribute name="scope" type="xs:string" use="optional"/>
10+
</xs:extension>
11+
</xs:complexContent>
12+
</xs:complexType>
13+
<xs:element name="extract_expression" type="ogr:extract_expression_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="extract_expression_Type">
15+
<xs:complexContent>
16+
<xs:extension base="gml:AbstractFeatureType">
17+
<xs:sequence>
18+
<xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
19+
<xs:element name="name" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:string">
22+
<xs:maxLength value="255"/>
23+
</xs:restriction>
24+
</xs:simpleType>
25+
</xs:element>
26+
<xs:element name="intval" nillable="true" minOccurs="0" maxOccurs="1">
27+
<xs:simpleType>
28+
<xs:restriction base="xs:integer">
29+
<xs:totalDigits value="10"/>
30+
</xs:restriction>
31+
</xs:simpleType>
32+
</xs:element>
33+
<xs:element name="floatval" nillable="true" minOccurs="0" maxOccurs="1">
34+
<xs:simpleType>
35+
<xs:restriction base="xs:decimal">
36+
<xs:totalDigits value="21"/>
37+
<xs:fractionDigits value="5"/>
38+
</xs:restriction>
39+
</xs:simpleType>
40+
</xs:element>
41+
</xs:sequence>
42+
</xs:extension>
43+
</xs:complexContent>
44+
</xs:complexType>
45+
</xs:schema>

python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

+12
Original file line numberDiff line numberDiff line change
@@ -614,3 +614,15 @@ tests:
614614
OUTPUT:
615615
name: expected/single_to_multi.gml
616616
type: vector
617+
618+
- algorithm: qgis:extractbyexpression
619+
name: Test (qgis:extractbyexpression)
620+
params:
621+
EXPRESSION: left("Name", 1) = 'A'
622+
INPUT:
623+
name: polys.gml
624+
type: vector
625+
results:
626+
OUTPUT:
627+
name: expected/extract_expression.gml
628+
type: vector

0 commit comments

Comments
 (0)