ArcGIS 自定义 Python 工具箱

本文介绍如何使用Python自定义ArcGIS工具箱,涵盖工具箱及工具的定义方式、参数配置、许可控制等内容,并提供实例演示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ArcGIS 自定义 Python 工具箱

Python 工具箱模板

# -*- coding: utf-8 -*-

import arcpy


class Toolbox(object):
    def __init__(self):
        # 定义工具箱(工具箱的名称是.pyt文件的名称)。
        self.label = "Toolbox"
        self.alias = ""

        # 与此工具箱关联的工具类列表
        self.tools = [Tool]


class Tool(object):
    def __init__(self):
        # 定义工具(工具名称是类的名称)。
        self.label = "Tool"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        # 定义参数定义
        params = None
        return params

    def isLicensed(self):
        # 设置是否允许工具执行。
        return True

    def updateParameters(self, parameters):
        # 在执行内部验证之前修改参数的值和属性。每当参数被更改时,就调用此方法。
        return

    def updateMessages(self, parameters):
        # 修改由内部验证为每个工具参数创建的消息。此方法在内部验证后调用。
        return

    def execute(self, parameters, messages):
        # 该工具的源代码。
        return

    def postExecute(self, parameters):
        # 此方法在输出被处理并添加到显示之后发生。
        return

编辑 Python 工具箱

​ 刷新 Python 工具箱时,只刷新 Python 工具箱文件;并不刷新工具箱中导入的任意模块。要在 Python 工具箱中重新加载模块,可使用可临时添加的 importlib 模块的 reload 功能。

import yourmodule
import importlib
importlib.reload(yourmodule)  # 强制重新加载模块

Python 工具箱中的工具定义

工具将作为类添加到 .pyt 文件。 每个工具类必须至少包含 __init__execute 方法。 或者,可以使用 getParameterInfoisLicensedupdateParametersupdateMessages 方法将控件添加至工具行为。

用于定义工作工具类的方法

工具方法必选或可选描述
_init_必需项初始化工具类。
getParameterInfo可选定义工具的参数。
isLicensed可选返回工具是否获得执行许可。
updateParameters可选在用户每次在工具对话框中更改参数时调用。 从 updateParameters 返回后,地理处理将调用它的内部验证例程。
updateMessages可选在从内部验证例程返回后调用。 可以检查根据内部验证创建的消息,并根据需要对其进行更改。
execute必需项工具的源代码。
postExecute可选当 execute 方法完成,然后处理输出并将其添加到显示后调用。

可在工具的 init 方法中设置以下属性:

属性描述
category工具所在的工具集的名称。 可通过工具集组织工具箱内的工具。
description工具的描述。
label标注是工具的显示名称,如地理处理窗格中所示。

注意:

在命名 Python 工具箱工具类时,Python 语法规则将强制执行大多数地理处理约定。 但是,请避免在工具类名称中使用下划线,因为在 ArcGIS Server 中运行工具时,这些下划线会导致错误。

定义 Python 工具箱中的参数

Parameter

摘要

每个工具参数都拥有一个包含可用于工具验证的属性和方法的关联 Parameter 对象。

说明

虽然很多 Parameter 对象属性为读/写属性,但其中大多数属性只能在最初创建或修改对象时进行设置或修改。多个属性(包括 name、displayName、datatype、direction 和 parameterType)可用于建立工具的特征,且在验证方法(例如 updateMessages 和 updateParameters)期间无法修改。

语法

 Parameter  ({name}, {displayName}, {direction}, {datatype}, {parameterType}, {enabled}, {category}, {symbology}, {multiValue})
参数说明数据类型
name参数名称。(默认值为 None)String
displayName地理处理窗格中显示的参数标注。(默认值为 None)String
direction参数的方向。(默认值为 None)String
datatype参数的数据类型。要获取参数数据类型的列表,请参阅地理处理数据类型。(默认值为 None)String
parameterTypeparameterType 属性可以为 Required、Optional 或 Derived。(默认值为 None)String
enabled如果参数不可用,则为 False。(默认值为 None)Boolean
category参数的类别。(默认值为 None)String
symbology用于绘制输出的图层文件(.lyrx 或 .lyr)的路径。(默认值为 None)String
multiValue如果参数为多值参数,则为 True。(默认值为 None)Boolean

属性

属性说明数据类型
altered(只读)如果用户对值做出了修改,则为 True。Boolean
category(可读写)参数的类别。String
charts(可读写)添加至输出参数的图表对象列表。Object
columns(可读写)值表参数中的列结构。这些列按列表的列表形式进行组织,每个内部列表表示列数据类型、列名称和可选只读值。 如果只读值设置为 ReadOnly,则用户无法修改该列。import arcpy param = arcpy.Parameter() param.datatype = "GPValueTable" param.columns = [["GPFeatureLayer", "Features"], ["GPLong", "Ranks"]]String
datatype(可读写)参数的数据类型。要获取参数数据类型的列表,请参阅地理处理数据类型String
defaultEnvironmentName(可读写)用于设置参数的默认值的地理处理环境设置的名称。String
direction(可读写)参数的方向。String
displayName(可读写)地理处理窗格中显示的参数标注。String
displayOrder(可读写)参数在地理处理窗格中的显示顺序。 该顺序可能与从 Python 访问参数的顺序不同。Integer
enabled(可读写)如果参数不可用,则为 False。Boolean
filter(只读)要应用于参数中值的过滤器Filter
filters(可读写)与 filter 属性相似,但是用于支持值表参数。class SampleTool(object): # __init__ left out to simplify example def getParameterInfo(self): in_fc = arcpy.Parameter( name='in_features', displayName='Input Features', datatype='GPFeatureLayer', direction='Input', parameterType='Required') vt = arcpy.Parameter( name = 'summary_fields', displayName = 'Summary fields', datatype = 'GPValueTable', direction = 'Input', parameterType = 'Optional') vt.parameterDependencies = [in_fc.name] vt.columns = [['Field', 'Field'], ['GPString', 'Statistic'], ['GPDouble', 'Multiplier']] vt.filters[0].list = ['Double', 'Float', 'Short', 'Long'] vt.filters[1].type = 'ValueList' vt.filters[1].list = ['SUM', 'MIN', 'MAX', 'MEAN'] vt.filters[2].type = 'Range' vt.filters[2].list = [0,10]Filter
hasBeenValidated(只读)如果内部验证例程已检查参数,则为 True。Boolean
message(只读)要向用户显示的消息。String
multiValue(可读写)如果参数为多值参数,则为 True。Boolean
name(可读写)参数名称。String
parameterDependencies(可读写)各依存参数的索引列表。在脚本工具中,使用参数索引列表设置 parameterDependencies;在 Python 工具箱工具中,使用参数名称列表设置 parameterDependencies。Integer
parameterType(可读写)parameterType 属性可以为 Required、Optional 或 Derived。在验证中,无法动态修改 parameterType 值。 但是,根据其他参数设置,参数可能需要充当必需参数或可选参数。 如果是这样,将参数设置为可选。 然后,在验证 updateMessages 方法中,将 Parameter setIDMessage 方法与消息 ID 530 或 735 搭配使用。 使用消息 ID 530 或 735 时将导致可选参数的行为与必需参数相同。Required—需要参数值才能运行工具。Optional—无需参数值即可运行工具。Derived—工具将返回未作为输入参数提供的输出值。 派生参数始终为输出参数。String
schema(只读)输出数据集的方案Schema
symbology(可读写)用于绘制输出的图层文件(.lyrx 或 .lyr)的路径。String
value(可读写)参数的值。Object
valueAsText(只读)字符串形式的参数值。String
values(可读写)值表参数的值,使用一系列列表进行设置。Variant

方法概述

方法说明
clearMessage ()清除所有消息文本并将状态设置为信息性的(无错误或警告)。
hasError ()如果参数包含错误,则返回 True。要评估参数是否包含错误,应在工具验证的 updateMessages 方法中调用 hasError。
hasWarning ()如果参数包含警告,则返回 True。
isInputValueDerived ()如果在模型内部验证工具并且输入值是模型中其他工具的输出,则返回 True。
setErrorMessage (message)通过提供的消息将参数设置为存在错误。 如果其中任何参数存在错误,则不会执行工具。
setIDMessage (message_type, message_ID, {add_argument1}, {add_argument2})将参数设置为存在系统消息。
setWarningMessage (message)通过提供的消息将参数设置为存在错误。 与存在错误时不同,工具在有警告消息的情况下也会执行。

方法

hasError ()

返回值

数据类型说明
Boolean如果参数包含错误,则为 True。

hasWarning ()

返回值

数据类型说明
Boolean如果参数包含警告,则为 True。

isInputValueDerived ()

返回值

数据类型说明
Boolean如果在模型内部验证工具并且输入值是模型中其他工具的输出,则为 True。

setErrorMessage (message)

参数说明数据类型
messageThe string to be added as an error message to the geoprocessing tool messages.String

setIDMessage (message_type, message_ID, {add_argument1}, {add_argument2})

参数说明数据类型
message_typeDefines whether the message will be an error or a warning.ERROR—The message will be an error message.WARNING—The message will be a warning message.String
message_IDThe message ID allows you to reference existing system messages.Integer
add_argument1Depending on which message ID is used, an argument may be necessary to complete the message. Common examples include dataset or field names. The data type is variable depending on the message.Object
add_argument2Depending on which message ID is used, an argument may be necessary to complete the message. Common examples include dataset or field names. The data type is variable depending on the message.Object

setWarningMessage (message)

参数说明数据类型
messageThe string to be added as a warning message to the geoprocessing tool messages.String

代码示例

参数示例

启用或禁用 ToolValidator 类中的参数。

def updateParameters(self):
    # If the option to use a weights file ("Get Spatial Weights From File") 
    # is selected, enable the parameter for specifying the file; 
    # otherwise, disable it
    if self.params[3].value == "Get Spatial Weights From File":
        self.params[8].enabled = True
    else:
        self.params[8].enabled = False
    return

参数示例 2

为 ToolValidator 类中的参数设置默认值。

def updateParameters(self):
    # Set the default distance threshold to 1/100 of the larger of
    # the width or height of the extent of the input features.  Do
    # not set if there is no input dataset yet, or the user has set
    # a specific distance (Altered is true).
    if self.params[0].value:
        if not self.params[6].altered:
            extent = arcpy.Describe(self.params[0].value)
        width = extent.XMax - extent.XMin
        height = extent.YMax - extent.YMin
        if width < height:
            self.params[6].value = width / 100
        else:
            self.params[6].value = height / 100
        return

参数示例 3

为 ToolValidator 类中的参数设置自定义错误消息。

def updateMessages(self):
    self.params[6].clearMessage()
    # Check to see if the threshold distance contains a value of
    # zero and the user has specified a fixed distance band.
    if self.params[6].value <= 0:
        if self.params[3].value == "Fixed Distance Band":
            self.params[6].setErrorMessage(
                "Zero or a negative distance is invalid when "
                "using a fixed distance band. Please use a "
                "positive value greater than zero.")
        elif self.params[6].value < 0:
            self.params[6].setErrorMessage(
                "A positive distance value is required when "
                "using a fixed distance band. Please specify "
                "a distance.")
    return

控制 Python 工具箱中的许可行为

isLicensed 方法是一种可选验证方法,用于检查 Python 工具箱中的工具是否具有执行许可。 如果运行其他地理处理工具(由 Python 工具箱工具使用)所需的相应许可和扩展模块不可用,那么可使用该方法限制工具的运行。

如果 isLicensed 方法返回 False,则工具无法运行。 如果该方法返回 True 或者未使用该方法,则工具可以运行。

def isLicensed(self):
    """Allow the tool to run, only if the ArcGIS 3D Analyst extension 
    is available."""
    try:
        if arcpy.CheckExtension("3D") != "Available":
            raise Exception
    except Exception:
        return False  # The tool cannot be run

    return True  # The tool can be run

Python 工具箱消息

在 Python 工具箱中,可以在 execute 方法中访问 messages 对象以将消息添加回工具。用于写入消息的 5 个方法如下所示:

方法说明
addMessage(message)信息性消息将添加到该工具的消息中。
addWarningMessage(message)警告消息将添加到该工具的消息中。
addErrorMessage(message)错误消息将添加到该工具的消息中。
addIDMessage(message_type, message_ID, add_argument1=None, add_argument2=None)可以使用地理处理消息代码添加任意类型的消息。
addGPMessages()来自上次运行的地理处理工具的消息将添加到该工具的消息中。

注:

也可使用诸如 AddMessage 等脚本工具函数来添加消息。有关详细信息,请参阅在脚本工具中写入消息

添加消息示例

在以下示例中,系统会评估输入内容,如果不包含输入要素,则会向工具添加错误消息,并会引发 arcpy.ExecuteError 异常以结束工具运行。

def execute(self, parameters, messages):
    input = parameters[0].valueAsText
    output = parameters[1].valueAsText
        
    # If the input has no features, add an error message, and raise
    #  an arcpy.ExecuteError
    if int(arcpy.GetCount_management(input)[0]) == 0:
        messages.addErrorMessage("{0} has no features.".format(input))
        raise arcpy.ExecuteError
            
    return

Python 工具箱中的后处理验证

postExecute 方法是一种可选验证方法,将在工具处理完成后运行。 当 Python 工具箱工具的 execute 方法完成并将输出添加到活动地图的内容窗格后,将调用该方法。 此方法允许使用 arcpy.mp 模块来查询并更改输出的显示。

postExecute 代码将根据活动地图来标识图层,并使用 SimpleRenderer 值将每个点的符号系统更改为机场符号。 代码假设工具的第二个参数为输出点要素类。

def postExecute(self, parameters):
    
    try:
        project = arcpy.mp.ArcGISProject('CURRENT')
        active_map = project.activeMap
        
        if active_map:
            out_layer = active_map.listLayers(os.path.basename(parameters[1].valueAsText))[0]
            
            symbology = out_layer.symbology
            symbology.updateRenderer('SimpleRenderer')
            symbology.renderer.symbol.applySymbolFromGallery('Airport')
            symbology.renderer.symbol.size = 12
            out_layer.symbology = symbology
            
    except Exception:
        pass

    return

加密 Python 工具箱

默认情况下,Python 工具箱 (.pyt) 是一个可在任何文本编辑器或 Python IDE 中编辑的纯文本文件。但是,在某些情况下,可能需要隐藏 Python 工具箱的内容。

要加密 Python 工具箱,请右键单击该工具箱并单击加密。输入并确认密码时,可保留原始 .pyt 文件的备份副本。

警告:

在同一位置对 Python 工具箱执行加密,将覆盖未加密的原始文件。建议您对输入文件进行备份,以免在忘记密码时造成内容丢失。

要对加密的 Python 工具箱进行解密,请右键单击该工具箱并单击解密

此外,ArcPy 函数 EncryptPYTDecryptPYT 也可用于加密或解密 Python 工具箱。

eg:

# -*- coding: utf-8 -*-

import time
import arcpy
import json


class Toolbox(object):
    def __init__(self):
        self.label = "ARM工具箱"
        self.alias = "ARMToolbox"

        # List of tool classes associated with this toolbox
        self.tools = [PublishService3D]


class PublishService3D(object):
    def __init__(self):
        self.label = "发布三维服务"
        self.description = "发布三维服务"
        self.canRunInBackground = False

    def getParameterInfo(self):
        # GeoScene Server 地址。
        param0 = arcpy.Parameter(
            displayName="Server地址",
            name="server_url",
            datatype="GPString",
            parameterType="Required",
            direction="Input")

        # GeoScene Server 用户名。
        param1 = arcpy.Parameter(
            displayName="Server用户名",
            name="server_username",
            datatype="GPString",
            parameterType="Required",
            direction="Input")

        # GeoScene Server 密码。
        param2 = arcpy.Parameter(
            displayName="Server密码",
            name="server_password",
            datatype="GPStringHidden",
            parameterType="Required",
            direction="Input")

        # GeoScene Server 上的服务存储路径,输入正确的Server地址、用户和密码后,会自动读取可用目录。
        param3 = arcpy.Parameter(
            displayName="服务路径",
            name="service_folder",
            datatype="GPString",
            parameterType="Required",
            direction="Input")
        # 服务名称。
        param4 = arcpy.Parameter(
            displayName="服务名称",
            
            name="service_name",
            datatype="GPString",
            parameterType="Required",
            direction="Input")

        # 三维场景图层包。
        param5 = arcpy.Parameter(
            displayName="SLPK文件",
            name="slpk_file",
            datatype="DEFile",
            parameterType="Required",
            direction="Input")
        param5.filter.list = ["slpk"]

        # Token。
        param6 = arcpy.Parameter(
            displayName="输出",
            name="output",
            datatype="GPString",
            parameterType="Derived",
            direction="Output")

        return [param0, param1, param2, param3, param4, param5, param6]

    def isLicensed(self):
        return True

    def updateParameters(self, parameters):
        if self.checkLoginInfo(parameters) and self.isChangeLoginInfo(parameters):
            parameters[3].filter.list = []
            parameters[3].value = None
            if self.login(parameters):
                parameters[3].filter.list = self.getServerFolders(parameters)
        return

    def updateMessages(self, parameters):
        if self.checkLoginInfo(parameters):
            if parameters[6].value:
                json_object = json.loads(parameters[6].value)
                if not json_object["loginSuccessful"]:
                    for i in range(3):
                        parameters[i].setErrorMessage("验证失败!请检查{0}!".format(parameters[i].displayName))
        return

    def execute(self, parameters, messages):
        arcpy.SetProgressor("step", "测试进程...", 0, 100, 10)
        for i in range(5):
            arcpy.SetProgressorLabel("步骤 {0}...".format(i + 1))
            time.sleep(2)
            messages.addMessage("Message: {0}".format(i + 1))
            messages.addMessage("Message: {0}".format(parameters[6].value))
            arcpy.SetProgressorPosition((i + 1) * 10)
        for i in range(5, 8):
            arcpy.SetProgressorLabel("步骤 {0}...".format(i + 1))
            time.sleep(2)
            messages.addWarningMessage("WarningMessage: {0}".format(i + 1))
            arcpy.SetProgressorPosition((i + 1) * 10)
        for i in range(8, 10):
            arcpy.SetProgressorLabel("步骤 {0}...".format(i + 1))
            time.sleep(2)
            messages.addErrorMessage("ErrorMessage: {0}".format(i + 1))
            arcpy.SetProgressorPosition((i + 1) * 10)
        time.sleep(2)
        arcpy.ResetProgressor()
        return

    def postExecute(self, parameters):
        return
    
    def checkLoginInfo(self, parameters):
        return parameters[0].value and parameters[2].value and parameters[1].value
    
    def isChangeLoginInfo(self, parameters):
        if not self.checkLoginInfo(parameters):
            return False
        if not parameters[6].value:
            return True
        json_object = json.loads(parameters[6].value)
        return (json_object["server"] != parameters[0].value) or (json_object["username"] != parameters[1].value) or (json_object["password"] != parameters[2].value)

    def login(self, parameters):
        time.sleep(3)
        json_object = {}
        json_object["server"] = parameters[0].value
        json_object["username"] = parameters[1].value
        json_object["password"] = parameters[2].value
        if(parameters[0].valueAsText == 'a' and parameters[1].valueAsText == 'a' and parameters[2].valueAsText == 'a'):
            json_object["token"] = "tk"
            json_object["loginSuccessful"] = True
            json_string = json.dumps(json_object, indent=4)
            parameters[6].value = json_string
            return True
        else:
            json_object["token"] = ""
            json_object["loginSuccessful"] = False
            json_string = json.dumps(json_object, indent=4)
            parameters[6].value = json_string
            return False

    def getServerFolders(self, parameters):
        if parameters[6].value:
            json_object = json.loads(parameters[6].value)
            if json_object["loginSuccessful"]:
                return ['folder1', 'folder2', 'folder3', 'folder4', 'folder5']
        return []
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Winemonk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值