构建处理插件(QGIS3)¶
在上一个教程中 以 Python 制作附加元件 (QGIS3) ,您学习了如何创建一个python插件-包括用户界面和处理数据的自定义逻辑。虽然这些类型的插件很有用,但它将设计用户界面的负担推给了插件作者。这导致每个插件都有不同的方式与之交互——这让用户感到困惑。此外,常规插件不会与QGIS的其他部分交互。例如,不能使用其他算法的插件功能。如果您想要编写的插件主要用于分析,而您想要的用户交互仅限于让用户选择输入和输出,那么使用处理框架编写插件有一种更简单、更受欢迎的方法。它消除了设计用户界面的需要—简化了流程。内置的处理库根据您的输入创建一个标准的处理接口,它的外观和行为与QGIS中的任何其他处理算法一样。它还与处理框架的其他部分无缝集成,因此您的插件算法可以用于批处理、图形建模、从python控制台调用等。
任务概述¶
我们将从教程中重新实现一个简单的插件 以 Python 制作附加元件 (QGIS3) 作为处理插件。它将产生一个新的处理提供程序 Save Attributes
还有一个算法 Save Attributes as CSV
这将允许用户选择一个向量层并将其属性写入CSV文件。
把工具拿来¶
文本编辑器或Python IDE¶
任何一种软件开发都需要一个好的文本编辑器。如果您已经有了一个喜爱的文本编辑器或IDE(集成开发环境),则可以在本教程中使用它。否则,每个平台都为文本编辑器提供多种免费或付费选项。选择一个适合你需要的。
本教程在Windows上使用Notepad++编辑器。
Windows
Notepad++ 是一个很好的windows免费编辑器。下载并安装 Notepad++ editor .
注解
如果您使用的是记事本++,请确保转到 Replace by space . Python对空白非常敏感,此设置将确保正确处理制表符和空格。
使能程序¶
打开QGIS。去
.
你会看到 QGIS Plugin Builder 与窗体对话。您可以填写与我们插件相关的详细信息。这个 Class name 将是包含插件逻辑的Python类的名称。这也是包含所有插件文件的文件夹的名称。进入
SaveAttributes
作为类名。这个 Plugin name 是插件将出现在 Plugin Manager . 输入名称为Save Attributes (Processing)
. 在中添加说明 Description 字段。这个 Module name 将是插件的主python文件的名称。输入为save_attributes_processing
. 保持版本号不变,并在相应的字段中输入您的姓名和电子邮件地址。点击 Next .
输入插件的简要说明 About 对话并单击 Next .
选择
Processing Provider
从 Template 选择器。这个 Algorithm name 值将是用户如何在处理工具箱中找到处理算法。输入为Save Attributes as CSV
. 离开 Algorithm group 空白。输入 Provider name 作为Save Attributes
. 在中输入说明 Provider description 字段。点击 Next .
Plugin builder将提示您生成文件的类型。保留默认选择并单击 Next .
由于我们不打算发布插件,您可以将 Bug tracker , Repository 和 Home page 默认值。检查 Flag the plugin as experimental 在底部的框中单击 Next .
系统将提示您为插件选择目录。现在,将其保存到计算机上可以轻松找到的目录中,然后单击 Generate .
下一步,按 generate 按钮。创建插件模板后,您将看到一个确认对话框。
注解
你可能会得到一个提示说路径中没有找到pyrcc5。您可以忽略此消息。
QGIS中的插件存储在一个特殊的文件夹中。我们必须先将插件目录复制到该文件夹,然后才能使用它。在QGIS中,通过转到
.
在profile文件夹中,将plugin文件夹复制到
子文件夹。
现在我们准备好第一次看看我们创建的全新插件。关闭QGIS并再次启动它。去
并启用Save Attributes (Processing)
中的插件 Installed 标签。
去
. 您将注意到底部有一个新的提供者Save Attributes
. 展开它以找到一个名为Save Attributes as CSV
. 双击启动它。
您将注意到一个熟悉的处理算法对话框,其中一个下拉列表用于输入层,一个选择器用于输出层。我们现在将自定义此对话框以满足我们的需要。关闭此对话框。
转到插件目录并加载文件
save_attributes_processing_algorithm.py
在文本编辑器中。对于我们的插件,我们将向量层作为输入,并将CSV文件作为输出。所以不是进口QgsProcessingParameterFeatureSink
作为输出-用于矢量层-添加QgsProcessingParameterFileDestination
这是一个文件。from qgis.core import (QgsProcessing, QgsFeatureSink, QgsProcessingAlgorithm, QgsProcessingParameterFeatureSource, QgsProcessingParameterFileDestination)
接下来,向下滚动并在下面定义输出参数
initAlgorithm()
方法,代码如下。self.addParameter( QgsProcessingParameterFileDestination( self.OUTPUT, self.tr('Output File'), 'CSV files (*.csv)', ) )
让我们重新加载插件,以便在对话框窗口中看到更改。去
. 选择save_attributes_processing
在 Configure Plugin reloader 对话框。
单击 Reload plugin 按钮加载插件的最新版本。为了测试这个新功能,我们必须在QGIS中加载一些层。加载一些层后,启动 算法。您将看到输出更改为文件而不是图层。
让我们为算法添加一些逻辑,该算法接受选定的向量层并将属性写入CSV文件。有关此代码的说明,请参见 Python 程式设计入门 (QGIS3) . 这里的显著区别是帮助显示处理进度的计数器。将以下代码添加到
processAlgorithm
方法并保存文件。def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ source = self.parameterAsSource(parameters, self.INPUT, context) csv = self.parameterAsFileOutput(parameters, self.OUTPUT, context) fieldnames = [field.name() for field in source.fields()] # Compute the number of steps to display within the progress bar and # get features from source total = 100.0 / source.featureCount() if source.featureCount() else 0 features = source.getFeatures() with open(csv, 'w') as output_file: # write header line = ','.join(name for name in fieldnames) + '\n' output_file.write(line) for current, f in enumerate(features): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break # Add a feature in the sink line = ','.join(str(f[name]) for name in fieldnames) + '\n' output_file.write(line) # Update the progress bar feedback.setProgress(int(current * total)) return {self.OUTPUT: csv}
回到QGIS主窗口,点击 Reload plugin 按钮。启动 算法。为 Input layer . 下一步,单击 … 按钮旁边 Output file .
命名输出文件
test.csv
然后点击 Run . 算法将在选定的位置运行并生成CSV文件。
如前所述,尽管该算法来自插件,但它与内置的处理工具集成得非常好。为了演示这一点,让我们使用内置的批处理接口运行此算法。右键单击算法并选择 Execute as Batch Process.. .
您可以选择多个输入并成批运行此算法,以便在一次运行中生成多个CSV文件。如果不熟悉批处理界面,请参见 使用处理框架进行批次处理 (QGIS3) 用于分步说明。
插件已经准备好了,您可以以当前形式发送它。但是,我们可以通过使处理插件的行为类似于常规插件来改善用户体验。使用下面概述的混合方法,可以添加菜单项和工具栏按钮。这样,用户就可以更容易地发现和启动作为插件一部分安装的工具。我们需要一个插件图标。下载 logo.png 并将其复制到插件目录。
打开文件
save_attributes_processing.py
. 在文件顶部添加以下导入。from qgis.PyQt.QtWidgets import QAction from qgis.PyQt.QtGui import QIcon from qgis.core import QgsProcessingAlgorithm, QgsApplication import processing
向下滚动并修改
__init__()
方法初始化iface。def __init__(self, iface): self.provider = None self.iface = iface
进一步向下滚动并找到
initGui
方法。它只包含初始化处理提供程序的代码。我们将添加代码以添加工具栏按钮和菜单项。我们还需要将代码添加到unload
方法,以便在移除插件时移除这些元素。def initGui(self): self.initProcessing() icon = os.path.join(os.path.join(cmd_folder, 'logo.png')) self.action = QAction( QIcon(icon), u"Save Attributes as CSV", self.iface.mainWindow()) self.action.triggered.connect(self.run) self.iface.addPluginToMenu(u"&SaveAttributes", self.action) self.iface.addToolBarIcon(self.action) def unload(self): QgsApplication.processingRegistry().removeProvider(self.provider) self.iface.removePluginMenu(u"&SaveAttributes", self.action) self.iface.removeToolBarIcon(self.action)
我们已经连接了按钮和菜单项来触发
run
方法。在底部添加使用helper方法的新方法execAlgorithmDialog
启动处理算法。def run(self): processing.execAlgorithmDialog("Save Attributes:Save Attributes as CSV")
接下来,我们需要对
__init__.py
插件目录中的文件。打开文件并添加iface
返回语句,因此对QGIS接口的引用将传递给插件。
回到QGIS主窗口,点击 Reload plugin 按钮。您将在下面看到一个新的工具栏图标和一个菜单项 . 您可以单击这些启动
Save Attributes as CSV
算法。您将注意到处理提供程序和工具栏中的算法仍具有默认图标。我们来解决这个问题。
打开
save_attributes_processing_provider.py
插件目录中的文件。在顶部添加导入,如下所示。import os import inspect from qgis.PyQt.QtGui import QIcon
修改
icon
方法添加自定义图标。def icon(self): cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0] icon = QIcon(os.path.join(os.path.join(cmd_folder, 'logo.png'))) return icon
接下来,打开
save_attributes_processing_algorithm.py
文件。在顶部添加导入,如下所示。import os import inspect from qgis.PyQt.QtGui import QIcon
添加新的
icon
方法,代码如下。def icon(self): cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0] icon = QIcon(os.path.join(os.path.join(cmd_folder, 'logo.png'))) return icon
重新加载插件,你会看到提供者和算法都有我们的自定义图标。
您可以压缩插件目录并与用户共享。他们可以解压到他们的插件目录的内容,并尝试您的插件。如果这是一个真正的插件,你可以把它上传到 QGIS Plugin Repository 这样所有的QGIS用户都能找到并下载你的插件。
注解
此插件仅用于演示。请勿发布此插件或将其上载到QGIS插件库。
下面是作为参考的完整源文件。
__init__.py
# -*- coding: utf-8 -*-
"""
/***************************************************************************
SaveAttributes
A QGIS plugin
This plugin adds an algorithm to save attributes of selected layer as a CSV file
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2019-09-18
copyright : (C) 2019 by Ujaval Gandhi
email : ujaval@spatialthoughts.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
This script initializes the plugin, making it known to QGIS.
"""
__author__ = 'Ujaval Gandhi'
__date__ = '2019-09-18'
__copyright__ = '(C) 2019 by Ujaval Gandhi'
# noinspection PyPep8Naming
def classFactory(iface): # pylint: disable=invalid-name
"""Load SaveAttributes class from file SaveAttributes.
:param iface: A QGIS interface instance.
:type iface: QgsInterface
"""
#
from .save_attributes_processing import SaveAttributesPlugin
return SaveAttributesPlugin(iface)
save_attributes_processing.py
# -*- coding: utf-8 -*-
"""
/***************************************************************************
SaveAttributes
A QGIS plugin
This plugin adds an algorithm to save attributes of selected layer as a CSV file
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2019-09-18
copyright : (C) 2019 by Ujaval Gandhi
email : ujaval@spatialthoughts.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
__author__ = 'Ujaval Gandhi'
__date__ = '2019-09-18'
__copyright__ = '(C) 2019 by Ujaval Gandhi'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
import sys
import inspect
from qgis.PyQt.QtWidgets import QAction
from qgis.PyQt.QtGui import QIcon
from qgis.core import QgsProcessingAlgorithm, QgsApplication
import processing
from .save_attributes_processing_provider import SaveAttributesProvider
cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0]
if cmd_folder not in sys.path:
sys.path.insert(0, cmd_folder)
class SaveAttributesPlugin(object):
def __init__(self, iface):
self.provider = None
self.iface = iface
def initProcessing(self):
"""Init Processing provider for QGIS >= 3.8."""
self.provider = SaveAttributesProvider()
QgsApplication.processingRegistry().addProvider(self.provider)
def initGui(self):
self.initProcessing()
icon = os.path.join(os.path.join(cmd_folder, 'logo.png'))
self.action = QAction(
QIcon(icon),
u"Save Attributes as CSV", self.iface.mainWindow())
self.action.triggered.connect(self.run)
self.iface.addPluginToMenu(u"&SaveAttributes", self.action)
self.iface.addToolBarIcon(self.action)
def unload(self):
QgsApplication.processingRegistry().removeProvider(self.provider)
self.iface.removePluginMenu(u"&SaveAttributes", self.action)
self.iface.removeToolBarIcon(self.action)
def run(self):
processing.execAlgorithmDialog("Save Attributes:Save Attributes as CSV")
save_attributes_processing_algorithm.py
# -*- coding: utf-8 -*-
"""
/***************************************************************************
SaveAttributes
A QGIS plugin
This plugin adds an algorithm to save attributes of selected layer as a CSV file
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2019-09-18
copyright : (C) 2019 by Ujaval Gandhi
email : ujaval@spatialthoughts.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
__author__ = 'Ujaval Gandhi'
__date__ = '2019-09-18'
__copyright__ = '(C) 2019 by Ujaval Gandhi'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
import inspect
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsFeatureSink,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFileDestination)
class SaveAttributesAlgorithm(QgsProcessingAlgorithm):
"""
This is an example algorithm that takes a vector layer and
creates a new identical one.
It is meant to be used as an example of how to create your own
algorithms and explain methods and variables used to do it. An
algorithm like this will be available in all elements, and there
is not need for additional work.
All Processing algorithms should extend the QgsProcessingAlgorithm
class.
"""
# Constants used to refer to parameters and outputs. They will be
# used when calling the algorithm from another algorithm, or when
# calling from the QGIS console.
OUTPUT = 'OUTPUT'
INPUT = 'INPUT'
def initAlgorithm(self, config):
"""
Here we define the inputs and output of the algorithm, along
with some other properties.
"""
# We add the input vector features source. It can have any kind of
# geometry.
self.addParameter(
QgsProcessingParameterFeatureSource(
self.INPUT,
self.tr('Input layer'),
[QgsProcessing.TypeVectorAnyGeometry]
)
)
# We add a file output of type CSV.
self.addParameter(
QgsProcessingParameterFileDestination(
self.OUTPUT,
self.tr('Output File'),
'CSV files (*.csv)',
)
)
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
"""
source = self.parameterAsSource(parameters, self.INPUT, context)
csv = self.parameterAsFileOutput(parameters, self.OUTPUT, context)
fieldnames = [field.name() for field in source.fields()]
# Compute the number of steps to display within the progress bar and
# get features from source
total = 100.0 / source.featureCount() if source.featureCount() else 0
features = source.getFeatures()
with open(csv, 'w') as output_file:
# write header
line = ','.join(name for name in fieldnames) + '\n'
output_file.write(line)
for current, f in enumerate(features):
# Stop the algorithm if cancel button has been clicked
if feedback.isCanceled():
break
# Add a feature in the sink
line = ','.join(str(f[name]) for name in fieldnames) + '\n'
output_file.write(line)
# Update the progress bar
feedback.setProgress(int(current * total))
return {self.OUTPUT: csv}
def name(self):
"""
Returns the algorithm name, used for identifying the algorithm. This
string should be fixed for the algorithm, and must not be localised.
The name should be unique within each provider. Names should contain
lowercase alphanumeric characters only and no spaces or other
formatting characters.
"""
return 'Save Attributes as CSV'
def displayName(self):
"""
Returns the translated algorithm name, which should be used for any
user-visible display of the algorithm name.
"""
return self.tr(self.name())
def group(self):
"""
Returns the name of the group this algorithm belongs to. This string
should be localised.
"""
return self.tr(self.groupId())
def groupId(self):
"""
Returns the unique ID of the group this algorithm belongs to. This
string should be fixed for the algorithm, and must not be localised.
The group id should be unique within each provider. Group id should
contain lowercase alphanumeric characters only and no spaces or other
formatting characters.
"""
return ''
def tr(self, string):
return QCoreApplication.translate('Processing', string)
def icon(self):
"""
Should return a QIcon which is used for your provider inside
the Processing toolbox.
"""
cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0]
icon = QIcon(os.path.join(os.path.join(cmd_folder, 'logo.png')))
return icon
def createInstance(self):
return SaveAttributesAlgorithm()
save_attributes_processing_provider.py
# -*- coding: utf-8 -*-
"""
/***************************************************************************
SaveAttributes
A QGIS plugin
This plugin adds an algorithm to save attributes of selected layer as a CSV file
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2019-09-18
copyright : (C) 2019 by Ujaval Gandhi
email : ujaval@spatialthoughts.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
__author__ = 'Ujaval Gandhi'
__date__ = '2019-09-18'
__copyright__ = '(C) 2019 by Ujaval Gandhi'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
import inspect
from qgis.PyQt.QtGui import QIcon
from qgis.core import QgsProcessingProvider
from .save_attributes_processing_algorithm import SaveAttributesAlgorithm
class SaveAttributesProvider(QgsProcessingProvider):
def __init__(self):
"""
Default constructor.
"""
QgsProcessingProvider.__init__(self)
def unload(self):
"""
Unloads the provider. Any tear-down steps required by the provider
should be implemented here.
"""
pass
def loadAlgorithms(self):
"""
Loads all algorithms belonging to this provider.
"""
self.addAlgorithm(SaveAttributesAlgorithm())
# add additional algorithms here
# self.addAlgorithm(MyOtherAlgorithm())
def id(self):
"""
Returns the unique provider id, used for identifying the provider. This
string should be a unique, short, character only string, eg "qgis" or
"gdal". This string should not be localised.
"""
return 'Save Attributes'
def name(self):
"""
Returns the provider name, which is used to describe the provider
within the GUI.
This string should be short (e.g. "Lastools") and localised.
"""
return self.tr('Save Attributes')
def icon(self):
"""
Should return a QIcon which is used for your provider inside
the Processing toolbox.
"""
cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0]
icon = QIcon(os.path.join(os.path.join(cmd_folder, 'logo.png')))
return icon
def longName(self):
"""
Returns the a longer version of the provider name, which can include
extra details such as version numbers. E.g. "Lastools LIDAR tools
(version 2.2.1)". This string should be localised. The default
implementation returns the same string as name().
"""
return self.name()