使用 Python 脚本创作地理处理任务
可在您的计算机上成功执行的大部分 Python 脚本工具都会在 GIS Server 上发布并成功执行 - 您不需要以任何方式修改脚本。但是如果遇到问题,则可能是因为脚本使用了大量的项目数据,或是使用导入语句导入了您开发的 Python 模块。在这种情况下,您会发现该主题很有帮助,因为您可以通过它对以下内容进行深入了解:
- 如何找到在脚本中使用的项目数据,并使其可在服务器上用于任务执行。
- 如何找到导入模块,并使其可在服务器上用于任务执行。
- 如何使项目数据和 Python 模块参数用于脚本。
- 如何处理工具验证代码及其在客户端和服务器之间的交互。
- 如何处理第三方库。
如果您不熟悉 Python、ArcPy 或脚本工具,则可跳到下面的 Python、ArcPy 和脚本工具入门部分,获取有用主题列表。
如何找到脚本中的项目数据
无论何时共享结果,无论共享为包还是服务,结果都会引用一个脚本工具,对该脚本工具进行扫描即可发现在脚本中使用的项目数据。找到项目数据后,会将其合并到临时文件夹,该文件夹将被打包(如果您共享为包)或上传到服务器(如果您共享为服务)。
扫描脚本时,会对用于 Python 变量或作为函数参数的每个加引号的字符串(无论是单引号还是双引号)进行测试,以查看是否存在数据路径。这里的数据是指:
- 内容列表中的图层(ArcMap 或 ArcGlobe)
- 文件夹
- 文件
- 地理数据集,如要素类、shapefile、地理数据库、地图文档 (.mxd) 和图层文件 (.lyr)
出于讨论目的,我们只关注用作地理处理工具或路径(引用了其他 Python 模块)输入的数据。也合并输出数据,但不能将它们视为项目数据。
在脚本中找到加引号的字符串后,按如下问题测试是否存在数据:
- 字符串指的是内容列表中的图层吗?
- 字符串中包含数据的绝对路径(如 "e:\Warehousing\ToolData\SanFrancisco.gdb\streets")吗?
- 可以找到相对于脚本位置的字符串参考数据吗?脚本位置定义如下:
- 包含脚本的文件夹。
- 如果脚本嵌入在工具箱中,其位置是包含工具箱的文件夹。
- 如果脚本在 Python 工具箱中,则位置是包含 Python 工具箱的文件夹。
这些测试按顺序依次进行。如果通过测试,数据存在,将会对数据进行合并,但以下情况除外:如果共享为服务,会检查服务器的数据存储,以确定数据是否位于数据存储中。如果是,则不会合并。
合并文件夹时,只会复制文件夹中的文件和地理数据库,不会复制子文件夹。有些地理数据集(例如,文件地理数据库、栅格和 TIN),从技术上讲它们是文件夹,但它们也是地理数据集,所以也将被复制。如果文件夹包含图层文件 (.lyr) 或地图文档 (.mxd),图层文件或地图文档引用的所有数据也会被合并,这样脚本中的 arcpy.mapping 例程才能访问引用数据。
由于文件夹的合并方式,您应该避免在文件夹中夹杂一些工具永远用不到的大数据集和文件,因为这会不可避免地增大打包或上传到服务器的数据大小。(这不适用于在服务器的数据存储中找到的文件夹,因为这些文件夹不会上传到服务器。)
示例
下面示例是以该文件夹结构为基础的:
相对路径和文件夹
以下查找相对于脚本位置的数据的技术是一种常用方式,特别是对那些为 ArcGIS 10.0 创建的服务。以下脚本代码位于上图所示的脚本文件夹中,仅供参考。ToolData 文件夹包含 SanFrancisco.gdb。SanFrancisco.gdb 中是一个名为 Streets 的要素类。在如下代码示例中,到 ToolData 文件夹的路径是相对于脚本位置(Scripts 文件夹)构建的。
import arcpy
import os
import sys
# Get the pathname to this script, then strip off the
# script file name to yield the containing folder
#
scriptPath = sys.path[0]
thisFolder = os.path.dirname(scriptPath)
# Construct paths to ../ToolData/SanFrancisco.gdb/Streets and
# ../ToolData/Warehouse.lyr
#
toolDataPath = os.path.join(thisFolder, "ToolData")
streetFeatures = os.path.join(toolDataPath, "SanFrancisco.gdb", "Streets")
streetLyr = os.path.join(toolDataPath, "Warehouse.lyr")
在以上代码中,将会测试 "ToolData"(os.path.join 函数的参数),以确认数据是否存在。在本例中,存在相对于脚本位置的名为 ToolData 的文件夹。将会合并该 ToolData 文件夹 - 其全部内容(不包括上面提到的子文件夹)将被打包或上传到服务器(除非 ToolData 文件夹属于服务器的数据存储)。
请注意,复制的是文件夹内容,而非单个文件。例如,在以上代码中,会构建数据集路径 e:/Warehousing/ToolData/SanFrancisco.gdb/Streets。合并过程不是单独的而是仅复制 Streets 数据集 - 复制整个 ToolData 文件夹。
地理数据集的绝对路径
如下图的代码示例所示,绝对路径以盘符开头,如 e:/。
import arcpy
import os
streetFeatures = 'e:/Warehousing/ToolData/SanFrancisco.gdb/Streets'
在以上代码中,Streets 数据集及其所依赖的全部其他数据(如关系类和域)都将被合并。
混合示例
import arcpy
import os
toolDataPath = r'e:\Warehousing\ToolData'
warehouseLyr = os.path.join(toolDataPath, "Warehouse.lyr")
在上述代码中,将合并 ToolData 文件夹的全部内容。由于合并了文件内容(不包括子文件夹),Warehouse.lyr 也将与 Warehouse.lyr 所引用的数据一起被合并。
正斜线与反斜线
Windows 约定使用反斜线 (\) 作为路径中的分隔符。UNIX 系统使用正斜线 (/)。
在 ArcGIS 中,无论是在路径中使用正斜线还是反斜线,ArcGIS 始终可以将正斜线和反斜线转换成相应的操作系统约定。
脚本中的反斜线
诸如 Python 等基于 UNIX 的和类似 C 语言的编程语言将反斜线 (\) 视为转义字符。例如,\t 表示制表符。由于路径可以包含反斜线,因此您需防止将反斜线用作转义字符。最简单的方法是使用 r 指令将路径转换成 Python 原始字符串,如下所示。这会指示 Python 忽略反斜线。
thePath = r"E:\data\telluride\newdata.gdb\slopes"
导入其他 Python 模块
您的脚本可能会导入您开发的其他脚本。例如,以下代码显示了如何导入名为 myutils.py 的 Python 模块,它是在与父脚本相同的目录中找到的,包含一个名为 getFIDName 的例程(程序)。
import arcpy
import myutils
inFeatures = arcpy.GetParameterAsText(0)
inFID = myutils.getFIDName(inFeatures)
遇到导入语句时,按照以下顺序定位脚本:
- 与脚本相同的文件夹。如果脚本嵌入到工具箱中,将使用包含工具箱的文件夹。
- 系统的 PYTHONPATH 变量引用的文件夹。
- 系统的 PATH 变量所引用的所有文件夹。
导入引用模块的另一项技术是,使用 sys.path.append 方法来导入。它可让您设置包含要导入的脚本的文件夹的路径。
import arcpy
import sys
import os
# Append the path to the utility modules to the system path
# for the duration of this script.
#
myPythonModules = r'e:\Warehousing\Scripts'
sys.path.append(myPythonModules)
import myutils # a Python file within myPythonModules
在上述代码中,请注意,sys.path.append 方法需要一个文件夹作为参数。由于 'e:\Warehousing\Scripts' 是一个文件夹,因此将合并文件夹的全部内容。复制文件夹内容的规则在此同样适用 - 文件夹中的所有内容(非地理数据集的子文件夹除外)都将被复制。
不会为项目数据或导入的模块而扫描文件夹内的 Python 脚本。
工具验证代码
如果您具有编写脚本工具的经验,则可提供您自己的工具验证逻辑。地理处理服务的客户端不能执行您的工具验证逻辑,仅服务器具有该功能。客户端将其执行任务请求发送到服务时,将在服务器上执行您的验证逻辑。如果验证例程抛出错误,则任务将停止执行。如果从服务返回消息,则客户端将接收验证例程抛出的消息。
验证逻辑使用 Python 执行,并将为项目数据和模块扫描您的验证代码,如其他 Python 脚本一样。例如,您的验证逻辑会打开一个包含投影文件 (.prj) 的文件夹(例如,d:\approved_projections),以构建一个客户端执行您的工具时可以使用的空间参考选择列表。该文件夹不是工具参数;它是在您的工具验证脚本中使用的项目数据。为 Python 脚本描述的以上规则在此处也同样适用,即 d:\approved_projections 文件夹将被合并,并复制到服务器(除非该文件夹位于服务器的数据存储中)。
设置项目数据和模块工具参数
如上所述,共享时会扫描您的 Python 脚本,并根据代码中找到的加引号的字符串确定脚本使用哪些数据。如果希望控制这一过程,您可以为脚本使用的所有数据和模块创建参数。以下脚本示例即说明了这一思路 - 所有的项目数据和模块都编入可以传递到脚本的参数。
import arcpy
import sys
import os
inFeatures = arcpy.GetParameterAsText(0) # Feature Layer
projectDataFolder = arcpy.GetParameterAsText(1) # Folder
myPythonModules = arcpy.GetParameterAsText(2) # Folder
# Append the path to the utility modules to the system path
# for the duration of this script.
#
sys.path.append(myPythonModules)
import myutils # a Python file within myPythonModules
# Construct a variable to hold the Streets feature class found in the
# project data folder
#
streetsFeatures = os.path.join(projectDataFolder, "SanFrancisco.gdb", "Streets")
如上所示,脚本为所有数据使用参数时,会有以下几个好处:
- 能够更加清楚脚本需要哪些数据 - 因为它是参数,可以在工具对话框中直观地看到。不需要编辑代码即可确定您要使用的数据。
- 内部工具验证逻辑为主导 - 如果参数值引用了不存在的数据,工具对话框会显示错误,您将无法执行工具来创建结果。
- 要重置数据位置,您可以使用工具对话框来浏览位置,而不是在脚本中键入位置(这种做法容易出错)。
- 当结果共享为服务后,服务编辑器 会将文件夹参数设置为常量的输入模式;您的客户端永远看不到参数。发布时,这两个文件夹将复制到服务器(除非它们已注册到数据存储)。在服务器上执行任务时,脚本将接收所复制文件夹的路径。
第三方模块
不会合并第三方模块(不是核心 Python 安装的一部分的任何模块)。您需要确保模块存在且在服务器上正确运行。这不适用于随 ArcGIS Server 一起安装的 numpy 或 matplotlib 模块。
在 Linux 上安装第三方 Python 模块(不是 numpy 和 matplotlib)需要特殊处理。
Python、ArcPy 和脚本工具入门
如果您不熟悉 Python、ArcPy 和脚本工具,下表列出的主题可以帮助您入门。
帮助主题 | 目录 |
---|---|
创建自己的地理处理工具的基本概念。 | |
Python 和 ArcPy 的介绍主题。这些主题中包含有关 Python 和 ArcPy 站点包的更详细主题。 | |
有关使用 Python 创建自定义脚本工具的介绍主题。 | |
熟悉脚本工具的创建过程后,通常需参阅本主题,本主题详细介绍了脚本工具参数的定义。 |