在ArcGIS中創建Python工具(三)

從 ArcGIS 10.1 版本開始,我們可以創建 python工具箱 來自定義腳本工具,這種工具箱相比較上一篇提到的標準工具箱。有着獨特的優勢,具體二者的區別總結過,看這一篇


認識 Python工具箱

Python 工具箱 (.pyt) 是一個簡單的文本文件,可以在任何文本編輯器中或者任何 Python IDE 中創建、查看和編輯。要確保 ArcGIS 正確識別 Python 工具箱,工具箱類的名稱必須是 Toolbox。在 Toolbox 類的 __init__ 方法中定義工具箱的屬性,這些屬性包括 alias、label 和 description,我們可以按照 幫助文檔 中的模板構建 Python 工具箱模板。

如下代碼中創建了包含一個工具(名爲 Tool)的 Python 工具箱:

import arcpy


class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the
        .pyt file)."""
        self.label = "Toolbox"
        self.alias = ""

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


class Tool(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Tool"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""
        params = None
        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        return

    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool
        parameter.  This method is called after internal validation."""
        return

    def execute(self, parameters, messages):
        """The source code of the tool."""
        return



動手做做

下面我就依據這個模板,寫一個簡單的腳本工具箱。需求是批量裁剪,我希望我只提供一個文件夾或者數據庫等這樣的工作空間和一個裁剪區域面,就可以批量完成工作空間內全部數據的裁剪工作,並且無視柵格還是矢量,一併裁剪。

Let the scripting begin ……


1 創建工具箱

工具箱的name就是 .pyt 文件的名字,通常我們把工具添加到 ArcToolbox窗口中時會顯示工具箱的 label。在 Toolbox 類的 __init__ 方法中定義屬性,例如: aliaslabeldescription

工具作爲被添加至 .pyt 中,工具箱的 tools 屬性必須設置爲包含定義的所有工具列表。比如,需要做ATool,ATool,CTool三個工具,不是寫三個腳本,而是創建三個,然後將類名放入列表, self.tools = [ATool,ATool,CTool]


這裏,我僅定義一個工具類 ClipWorkspace,來說明構建過程即可 :

'''
Source Name:   ClipWorkspace.pyt
Author:        Kikita
Description:   Python tool to clip spatial data in the same workspace by batch.
'''

import arcpy

# The class name must be "Toolbox" ...
class Toolbox(object):
    def __init__(self):

        self.label = "Clip Workspace Toolbox"
        self.alias = ""

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


class ClipWorkspace(object):
    ……


在 ArcGIS Desktop 中已經可以看到這個工具箱的雛形:

這裏寫圖片描述


2 定義工具

下面就是完善工具內部的代碼。我就以 ClipVectorWorkspace 爲例。


每個工具類應至少包括 __init__execute 方法。此外,還可以選擇使用 getParameterInfoisLicensedupdateParametersupdateMessages 方法向工具的行爲中添加其他控制。

工具類中的 __init__ 方法是標準 Python 類初始化方法。對於 Python 工具箱中的工具,__init__ 方法用於設置該工具的屬性,例如工具的標註、描述、是否允許在後臺運行等。

下面的例子就創建了ClipVectorWorkspace這個工具:

class ClipWorkspace(object):

    def __init__(self):
        self.label = "Clip Workspace"
        self.description = "clip spatial data in the same workspace by batch."
        self.canRunInBackground = True

有了工具的構造函數,我們繼續看如何給工具定義參數。在 Python 工具箱 (.pyt) 中,可在工具類的 getParameterInfo 方法中創建 Parameter 對象,並設置對象的屬性來定義工具參數。Parameter的屬性中datatype
包含的類型可以在幫助文檔中查詢,點這裏


此示例中的參數就是輸入工作空間(inWorkspace)、裁剪區域面(ClipArea)、輸出工作空間(outWorkspace)。

    def getParameterInfo(self):

        # Parameter Definitions
        # First parameter - Input Workspace
        param0 = arcpy.Parameter(
            displayName="Input Workspace",
            name="inWorkspace",
            datatype="DEWorkspace",
            parameterType="Required",
            direction="Input")

        # Second parameter - Clip Area
        param1 = arcpy.Parameter(
            displayName="Clip Area",
            name="CLipArea",
            datatype="DEFeatureClass",
            parameterType="Required",
            direction="Input")

        # Third parameter - Output Workspace
        param2 = arcpy.Parameter(
            displayName="Output Workspace",
            name="outWorkspace",
            datatype="DEWorkspace",
            parameterType="Required",
            direction="Input")

        params = [param0,param1,param2]
        return params   

PS : 在代碼中,如果仔細看,或許你會疑惑,爲何輸出工作空間的方向是 input ,而不是 output? 因爲工具最終輸出的爲 Feature Class 或 Raster,輸出工作空間也是作爲輸入參數傳入工具使用的。如果不關心,也可以不在意這些細節…… 繼續向下瞭解工具的構建過程。


下面就是工具的具體執行部分了,當然裏面還加了些輔助瞭解工具執行狀態的消息:

    def execute(self, parameters, messages):

        """The source code of the tool."""

        # Get tool parameters
        inWorkspace = parameters[0].valueAsText
        arcpy.AddMessage("###Input Workspace is {0}".format(inWorkspace))

        ClipArea = parameters[1].valueAsText
        arcpy.AddMessage("###Clip Area is {0}".format(ClipArea))

        outWorkspace =  parameters[2].valueAsText
        arcpy.AddMessage("###Out Workspace is {0}".format(outWorkspace))


        # Clip Feature by Batch
        arcpy.env.workspace = inWorkspace

        # Clip Vector
        FeatureClasses = arcpy.ListFeatureClasses()
        arcpy.AddMessage("Input Workspace contains {0}".format(FeatureClasses))
        for fc in FeatureClasses:
            arcpy.AddMessage(">> Clipping  {0}".format(fc))
            arcpy.Clip_analysis(fc,ClipArea, os.path.join(outWorkspace,fc))
            arcpy.AddMessage("{0} has been clipped.".format(os.path.join(outWorkspace,fc)))

        # Clip Raster
        Rasters = arcpy.ListRasters()
        arcpy.AddMessage("Input Workspace contains {0}".format(Rasters))
        for Raster in Rasters:
            arcpy.AddMessage(">> Clipping  {0}".format(Raster))
            arcpy.Clip_management(in_raster = Raster,
                                  rectangle = "",
                                  out_raster = os.path.join(outWorkspace,Raster),
                                  in_template_dataset = ClipArea,
                                  nodata_value = "",
                                  clipping_geometry = "ClippingGeometry",
                                  maintain_clipping_extent = "NO_MAINTAIN_EXTENT")
            arcpy.AddMessage("{0} has been clipped.".format(os.path.join(outWorkspace,Raster)))

        return


到這裏,工具的核心部分已經完成,執行下試試。

這裏寫圖片描述


OK,應該是預期的結果:

這裏寫圖片描述


3 完善

我們發現不像標準工具箱中的腳本工具和腳本文件本身是散列存儲的,python工具箱以及其中的所有工具的代碼都在這一個pyt文件中,維護起來便利了不少。如果想在工具箱中繼續添加工具,只要繼續增加一個工具類即可。

經過前兩步的過程,工具已經可以拿去使用。如果爲了工具更友好,還可以繼續調整下代碼,以便遇到異常的時候,讓用戶瞭解更詳細的原因,這裏就再往下進行了。工具分享給別人,最後只差要豐富下工具文檔了,同樣在 Python 工具的 Item Description 中編輯。

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章