# 4.3.从Arcpy创建工具

## 前言

上一篇中，我介绍如何通过ArcPy调用自定义或第三方工具，本节将介绍如果从利用ArcPy创建一个自定义的工具。

## 工具参数

在ArcGIS中，我们使用工具，这些工具都有参数，比如选择处理的数据，处理结果的保存路径等。ArcPy中使用`arcpy.GetParameter(parameterIndex)`来获取指定索引**parameterIndex**处的参数的信息，该方法返回的是一个object对象。此外还有一个函数`arcpy.GetParameterAsText(parameterIndex)`，也是用来获取指定索引**parameterIndex**处的参数，但是从函数名可以看出，这个函数会将获取的参数以字符串的形式进行返回。

这两个函数都具有一个形参**parameterIndex**，这个形参是指参数的索引，从0开始。

## 编写脚本

下面我们来写一个工具，该工具用来将对点进行一个缓冲区分析，但是与ArcGIS中自带的不同，该缓冲的结果是正方形，即以点为中心，向四周做两个半径长度的正方形。工具中有三个参数：输入要素类，距离半径，输入位置。

首先接受参数：

```
# 输入要素
​
input_fs = arcpy.GetParameterAsText(0)    
# distance convert string to number
distance_str = arcpy.GetParameterAsText(1)
distance = float(distance_str)
# output
output_fs = arcpy.GetParameterAsText(2)
```

然后创建输出shapefile：

```
output_dir = os.path.dirname(output_fs)
output_name = os.path.basename(output_fs)
​
arcpy.CreateFeatureclass_management(output_dir, output_name, "Polygon", spatial_reference=input_fs)
```

接着遍历原来的点图层，输出缓冲结果：

```
with arcpy.da.InsertCursor(output_fs, ['SHAPE@']) as i_cur:
    with arcpy.da.SearchCursor(input_fs, ['SHAPE@']) as s_cur:
        for row in s_cur:
            point = row[0].firstPoint
            # buffer for the point, and return a polygon geometry
            point_buffer = buffer_point(point, distance)
            insert_row = [point_buffer]
            i_cur.insertRow(insert_row)
```

**注意**，里面的注释我都是使用的英文，而使用中文的地方，注释与代码间是相隔了一个空行。这是因为，如果声明文件编码为**utf8**，如果没有空行的存在，在运行工具的时候，可能会得到“Name xxx is not defined”的错误；如果声明编码为**cp936**（即：GB2312），则不需要如此。

现在，核心代码已经全部完成了，接下来需要将其变为工具。

## 创建工具

ArcGIS中每个工具都是存在于工具箱之中，为了将该脚本变为工具使用，需要先选择一个工具箱，这里选择上一节中定义的MyTools.tbx工具箱。在工具箱上右键，选择添加|脚本（如图 1所示），打开脚本的添加界面（如图2所示），这里我们为该脚本工具命名为RectBuffer。

![图 1 工具箱右键菜单](/files/-M68UvaPC5khjPOEhbuv)

![图 2 添加脚本（第一步）](/files/-M68UvaRDdybsW6EpLZS)

点击下一步进入添加脚本第二步，这里我们需要选择脚本的路径（如图 3所示）。

![图 3 添加脚本（第二步）​](/files/-M68UvaSptTAATNcCOrd)

点击下一步，接下来，我们需要为该脚本工具设置参数了。

该脚本工具有三个参数，分别为输入数据（限制为点图层），缓冲的半径距离（这里做的比较简单，将单位设置为与输入数据的坐标单位一样即可，数字）以及输出文件。

现在我们先将三个参数输入进去，其数据类型依次为：要素图层、双精度和要素类。为什么第一个参数类型选择的是要素图层呢？因为如果这个图层已经在ArcGIS中打开了，我们可以通过下来菜单选择，而不必再选择去路径了。

接下来，我们选择输入数据，在下方的过滤器中选择要素类，然后将其限制为点图层（如图 4所示）。

![​图 4 添加脚本（第三步，限制输入要素类型）​](/files/-M68UvaWDKjhD4ZQlfNQ)

由于输出结果是向我们的磁盘上写入文件，而不是读取文件，因此我们还需要将出输出位置的方向设置为Output（如图 5所示）。

![​图 5 添加脚本（第四步，更改输出要素的方向）​](/files/-M68UvaXkrozYUqa9TOa)

接下来点击完成，即可将该脚本封装为工具，双击RectBuffer工具，其界面如图 6所示。

![图 6 RectBuffer工具​](/files/-M68Uva_QQeakcdHPCsW)

分别进行5度，10度的缓冲（元素数据是WGS84坐标系，因此缓冲单位为度），结果如图 7所示。​

![图 7 RectBuffer结果​](/files/-M68UvaZ9juHo82T3xTH)

## 进阶

### 添加消息输出

ArcPy脚本中的`print`函数的执行结果并不会显示在工具运行时的对话框中，但我们想在知道程序运行到了哪一步怎么办呢？ArcPy提供了一些函数来实现这些功能，其中常用的是下面三个：

1. `AddMessage`：向工具对话框、历史记录和 Python 窗口显示一条消息；
2. `AddWarning`：向工具对话框、历史记录和 Python 窗口显示一条警告；
3. `AddError`：向工具对话框、历史记录和 Python 窗口显示一条错误；

现在向脚本中添加以下三行代码，结果如图 8所示。在图7中，我们可以看到工具对话框中显示了这三条信息，并且还有了颜色进行区分。

```
arcpy.AddMessage(u"这是一条普通消息")
arcpy.AddWarning(u"这是一条警告消息")
arcpy.AddError(u"这是一条错误消息")​
```

![图 8 输出消息示例​](/files/-M68UvaT5vqejCxW8uDx)

### 添加进度条

另一个用于显示处理进度的是进度条，进度条的使用要复杂些，先看Demo：

```
arcpy.SetProgressor("step", "Title", 0, 100, 1)
time.sleep(5)
for i in range(1, 100):
    arcpy.SetProgressorLabel("Loading {0}...".format(i))
    time.sleep(1)
    arcpy.SetProgressorPosition()
arcpy.ResetProgressor()
```

这是使用的`time.sleep`函数来模拟数据的处理，其效果如图9 所示：

![图9 a 初始化显示标注​](/files/-M68UvahLtdne1hcuoyn)

![图 9 ​b 处理过程中](/files/-M68UvaipVKD8RKcztgT)

#### 使用过程

1\). 设置进度条

使用进度条前要先使用`arcpy.SetProgressor`声明一个进度条，`arcpy.SetProgressor`的定义如下：

```
SetProgressor(type, {message}, {min_range}, {max_range}, {step_value})
```

| 参数          | 说明                                                                 | 数据类型    |
| ----------- | ------------------------------------------------------------------ | ------- |
| type        | 进度条类型（默认或步骤）。default —进度条连续向后或向前移动；step —进度条显示完成百分比。(默认值为 default) | String  |
| message     | 进度条标注。默认情况下没有标注。                                                   | String  |
| min\_range  | 进度条的开始值。默认值为 0。(默认值为 0)                                            | Integer |
| max\_range  | 进度条的结束值。默认值为 100。(默认值为 100)                                        | Integer |
| step\_value | 用于更新进度条的进度条步长间隔。(默认值为 1)                                           | Integer |

*引用自：*[*https://desktop.arcgis.com/zh-cn/arcmap/10.3/analyze/arcpy-functions/setprogressor.htm*](https://desktop.arcgis.com/zh-cn/arcmap/10.3/analyze/arcpy-functions/setprogressor.htm)

2\). 更新进度条

更新进度条则需要使用`arcpy.SetProgressorPosition`函数，其定义如下：

```
SetProgressorPosition({position})
```

参数**position**用来设置进度条的进度，其不是百分比，百分比是根&#x636E;**(position-min\_range)/max\_range**计算的。如果不指定**position**，则会在上次的**position**（初始为min\_range）基础上递增**step\_value**

3\). 重置进度条

当进度条达到100%后，我们可能想为下一个操作设置进度条，这时候，我们需要使用`arcpy.ResetProgressor`函数。如果是最后处理完成， 我们也可以不用重置进度条。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zxyao.gitbook.io/arcpy/4.arcpy-yu-gong-ju-xiang/4.3.-cong-arcpy-chuang-jian-gong-ju.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
