I am creating a processing plugin in QGIS that has two steps.
- Write features to a
FeatureSink
. - Convert the
FeatureSink
to a layer and performnative:joinattributesbylocation
.
I am using the QGIS script template as a starting point.
I have two output parameters: one for each of the outputs of the second step but the script produces 3 temporary layers. It is writing the output of the FeatureSink
to a scratch layer as well. How can I prevent this appearing? Ideally I would like to prevent the intermediate FeatureSink
appearing at all, but I could also delete it at the end of the process.
Code snippet below:
def initAlgorithm(self, config=None):
mastermap_parameter = QgsProcessingParameterFeatureSource(
self.INPUT,
self.tr('\'Area\' data from OS Mastermap'),
[QgsProcessing.TypeVectorAnyGeometry]
)
mastermap_parameter.setDefaultValue('OSMM_AREA')
self.addParameter(mastermap_parameter)
string1_parameter = QgsProcessingParameterString(
self.STRING_1,
self.tr('Select features with the following value...'),
'',
multiLine = False,
optional = False
)
string1_parameter.setDefaultValue('Buildings')
self.addParameter(string1_parameter)
field1_parameter = QgsProcessingParameterField(
self.FIELD_1,
self.tr('...in the following attribute field.'),
'',
self.INPUT
)
field1_parameter.setDefaultValue('theme')
self.addParameter(field1_parameter)
string2_parameter = QgsProcessingParameterString(
self.STRING_2,
self.tr('Additionally, select features with the following value...'),
'',
multiLine = False,
optional = True
)
string2_parameter.setDefaultValue('Building')
self.addParameter(string2_parameter)
field2_parameter = QgsProcessingParameterField(
self.FIELD_2,
self.tr('...in the following attribute field.'),
'',
self.INPUT,
QgsProcessingParameterField.DataType.Any,
allowMultiple = False,
optional = True
)
field2_parameter.setDefaultValue('descriptivegroup')
self.addParameter(field2_parameter)
self.addParameter(
QgsProcessingParameterFeatureSource(
self.NRD_INPUT,
self.tr('Data from National Receptor Dataset'),
[QgsProcessing.TypeVectorAnyGeometry]
)
)
self.addParameter(
QgsProcessingParameterFeatureSink(
self.OUTPUT,
self.tr('Output data')
)
)
self.addParameter(
QgsProcessingParameterVectorDestination(
self.OUTPUT_2,
self.tr('OS Mastermap buildings without NRD')
)
)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(
parameters,
self.INPUT,
context)
field_1 = self.parameterAsString(
parameters,
self.FIELD_1,
context)
string_1 = self.parameterAsString(
parameters,
self.STRING_1,
context)
field_2 = self.parameterAsString(
parameters,
self.FIELD_2,
context)
string_2 = self.parameterAsString(
parameters,
self.STRING_2,
context)
(sink, dest_id) = self.parameterAsSink(
parameters,
self.OUTPUT,
context,
source.fields(),
source.wkbType(),
source.sourceCrs()
)
total = 100.0 / source.featureCount() if source.featureCount() else 0
valid_features = []
for current, feature in enumerate(source.getFeatures()):
if feedback.isCanceled():
break
if (feature[field_1] == string_1 or feature[field_2] == string_2):
sink.addFeature(feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
nrd_input = self.parameterAsLayer(
parameters,
self.NRD_INPUT,
context)
mm_building_layer = QgsProcessingUtils.mapLayerFromString(
dest_id,
context)
joined_layer = processing.run("native:joinattributesbylocation", {
'DISCARD_NONMATCHING' : True,
'INPUT' : mm_building_layer,
'JOIN' : nrd_input,
'JOIN_FIELDS' : [],
'METHOD' : 0,
'NON_MATCHING' : parameters['OUTPUT_2'],
'OUTPUT' : parameters['OUTPUT'],
'PREDICATE' : [0],
'PREFIX' : ''
},
is_child_algorithm=True,
context=context,
feedback=feedback)
if feedback.isCanceled():
return {}
return {}
Best Answer
You can create an intermediate layer with the filtered features, using
native:extractbyexpression
(and without a feature sink at any stage):You could also filter features using
getFeatures()
(with an expression) ornative:extractbyattribute
(with a single attribute).