6.1 介绍

本章介绍了探索空间数据的几种方法,包括检查数据集是否存在、描述数据集以及在工作空间中列出数据集。列表函数不仅用于列出数据集,还用于列出工作区、字段和表等元素。内置的 Python 函数可用于操作列表。列表在脚本中很常见,因为它们可以遍历元素以自动化工作流程。

6.2 检查数据是否存在

在 Python 脚本中,您可能需要确定数据集是否确实存在。此任务可以使用 arcpy.Exists() 函数完成。
此函数返回一个布尔值 True 或 False,指示元素是否存在。
Exists() 函数可以确定要素类、表、数据集、工作空间、图层和其他文件是否存在。

arcpy.Exists(<dataset>)

例如:

import arcpy
print(arcpy.Exists("C:/Data/streams.shp"))

使用 Python 时,应该记住两种类型的路径:

System paths—these are the paths recognized by the Windows operating system.
 Catalog paths—these are the paths that only ArcGIS Pro recognizes.

系统路径可以使用os.path.exists()来确定,工作路径使用arcpy函数,例如:Exists()来确定。

文件地理数据库称为“.gdb”,企业级地理数据库称为“.sde”,pro中不支持个人地理数据库.mdb

关于目录的其他内容,在实际使用过程可以到书中了解,我们暂时只是需要知道:目录路径由工作空间(路径)和基本名称(文件的名称及类型)组成。

6.3 描述数据

在使用arcpy的函数时,不同的函数的输入要素类型时不同的,所以需要使用函数来确定数据集的要素类型(点、线面)然后再使用要素。在arcpy中有两个函数描述数据集:arcpy,Describe()和rcpy.da.Describe()。

首先,Describe() 函数是 ArcPy 的常规函数,如 Exists() 或 ImportToolbox()。 Describe() 函数返回一个 Describe() 对象,您可以使用该对象检查其属性,例如数据类型。 Describe() 对象的属性是动态的,这意味着可使用的属性随所描述对象的性质而变化。这种行为提供了很大的灵活性,但也可能导致混淆,因为在确定数据类型之前您不会知道哪些属性可用。

其次,da.Describe() 函数是 arcpy.da 模块或数据访问模块的函数。除了描述数据之外,此 ArcPy 模块还用于编辑任务并支持数据库工作流,例如版本控制、副本、域和子类型。后面的章节继续将数据访问模块用于其他任务,但本章的重点是描述数据。 da.Describe() 函数返回与 Describe() 函数相同的信息,但以字典的形式

arcpy.Describe(<input dataset>, {datatype})

例如:

import arcpy
desc = arcpy.Describe("C:/Data/streams.shp")
print(desc.shapeType)

其中shapeType是对象的一个属性。
使用as.Describe可以完成同样的任务:

arcpy.da.Describe(<input dataset>, {datatype})

因为其结果是以字典的形式进行存储,所以可以使用键将其信息描述:

import arcpy
desc = arcpy.da.Describe("C:/Data/streams.shp")
print(desc["shapeType"])

arcpy.as.Describe是arcpy.Describe的更新,其更加透明,可以直接使用键,推荐使用前者。

Describe() 函数和 da.Describe() 函数均可用于各种数据集,包括地理数据库要素类、shapefile、栅格和表。对于这两个函数,结果都是动态的。在 Describe() 函数的情况下,对象的属性是动态的,而在 da.Describe() 函数的情况下,字典的键是动态的。动态意味着可用的属性或键分别取决于所描述的数据类型。
因为有很多不同的属性,所以它们被组织成一系列的属性组。这种分组不会影响语法——属性组的名称不会出现在语法中——但它提供了所有属性的逻辑组织。

在许多情况下,必须访问属性才能正确指定工具参数。例如,以下代码确定要素的几何形状类型,并且仅当形状类型为多边形时才运行裁剪工具:

import arcpy
arcpy.env.workspace = "C:/Data"
infc = "streams.shp"
clipfc = "study.shp"
outfc = "streams_clip.shp"
desc = arcpy.da.Describe(clipfc)
type = desc["shapeType"]
if type == "Polygon":
    arcpy.Clip_analysis(infc, clipfc, outfc)
else:
    print("The clip features are not polygons.")

可以缩写为:

if arcpy.da.Describe(clipfc)["shapeType"] == "Polygon":

以下代码描述了一个 shapefile 并打印了数据集的类型和空间参考的名称:

import arcpy
fc = "C:/Data/streams.shp"
desc = arcpy.da.Describe(fc)
sr = desc["spatialReference"]
print("Dataset type: " + desc["shapeType"])
print("Spatial reference: " + sr.name)

在许多情况下,数据集类型并不那么明显。以下代码确定地理数据库内元素的数据集类型:

import arcpy
element = "C:/Data/study.gdb/final"
desc = arcpy.da.Describe(element)
print("Dataset type: " + desc["datasetType"])

确定数据类型可能很重要,因为地理数据库中的元素没有文件扩展名。Describe() 和 da.Describe() 函数的 ArcGIS Pro 帮助页面包含有效数据集类型的完整列表。帮助页面中的大部分示例代码都使用了 Describe() 函数,但可以使用 da.Describe() 完成相同的任务。

描述数据集的两个函数还访问许多其他相关属性。这些属性包括文件路径、目录路径、名称、文件名和基本名称。运行以下代码会打印其中几个属性:

import arcpy
arcpy.env.workspace = "C:/Data/study.gdb"
element = "roads"
desc = arcpy.da.Describe(element)
print("Data type: " + desc["dataType"])
print("File path: " + desc["path"])
print("Catalog path: " + desc["catalogPath"])
print("File name: " + desc["file"])
print("Base name: " + desc["baseName"])
print("Name: " + desc["name"])
Data type: FeatureClass
File path: C:/Data/study.gdb
Catalog path: C:/Data/study.gdb/roads
File name: roads
Base name: roads
Name: roads

也可以在栅格上使用Describe或者as.Describe。

6.4 列表数据

在这一节中,很多文件类型并不区分大小写,比如point和POINT。

平时我们进行的批处理都是使用某一个工具,使用不同的数据来多次执行这个工具。在第三章中介绍了很多批处理的方法。
使用脚本进行批处理,需要对数据进行迭代,要首先清点数据或者形成一个列表,然后进行循环。

Arcpy中包含了多个用于清点的函数,这些函数返回一个列表,其中包含项目列表。
在python或者其他语言中,进行循环一般是使用for循环。

ArcPy 列表函数包括 ListFields()、ListIndexes()、ListDatasets()、ListFeatureClasses()、ListFiles()、ListRasters()、ListTables()、ListWorkspaces() 和 ListVersions()。

最广泛使用的列表函数之一是 arcpy.ListFeatureClasses() 函数,它返回当前工作空间中的要素类列表。该函数的语法如下:

arcpy.ListFeatureClasses({wild_card}, {feature_type}, 
                         {feature_dataset})

该函数的三个参数都是可选的。三个参数分别是:名称、要素类型或要素数据集。

import arcpy
arcpy.env.workspace = "C:/Data"
fclist = arcpy.ListFeatureClasses()
print(fclist)
['floodzone.shp', 'roads.shp', 'streams.shp', 'wetlands.shp', 'zipcodes.shp']

函数的结果是一个列表,列表是方括号和逗号组成的。
对于**第一个参数,**其中可以使用通配符*来限制列表,例如使用通配符✳来选择以w开头的文件名:

fclist = arcpy.ListFeatureClasses("w*")

这一点和matlab等一样,matlab使用*.csv之类的结果来选择csv后缀的文件。

对于第二个参数,可以设置文件的类型(点线面)。

#选择点要素
fclist = arcpy.ListFeatureClasses("", "point")

有效的矢量类型包括:annotation, arc,
dimension, edge, junction, label, line, multipatch, node, point, polygon, polyline, region, route, and tic.
注释、圆弧、尺寸、边、交汇点、标签、线、多面体、节点、点、多边形、折线、区域、路线和 tic。

对于栅格数据集的列表,和矢量要素语法相似:

arcpy.ListRasters({wild_card}, {raster_type})

例如筛选tif格式:

rasterlist = arcpy.ListRasters("", "TIF")

有效的栅格数据类型有:BMP, GIF, IMG, JP2, JPG, PNG, TIF, GRID

另一个常用的列表函数是 arcpy.ListFields()。此函数列出指定数据集的要素类或表中的字段。语法为
arcpy.ListFields(dataset, {wild_card}, {field_type}) ListFields() 函数有三个参数,其中只有第一个(数据集)是必需的。数据集是其字段将作为列表中的值返回的要素类或表。例如,以下代码创建 shapefile 中所有字段的列表:

import arcpy
arcpy.env.workspace = "C:/Data"
fieldlist = arcpy.ListFields("roads.shp")

这两个可选参数允许按名称或字段类型限制列表。以下代码创建 shapefile 中所有整数字段的列表:
fieldlist = arcpy.ListFields("roads.shp", "", "Integer")
有效字段类型包括 BLOB(二进制大对象)、Date、Double , 几何, GlobalID, GUID, Integer, OID, Raster, Single, SmallInteger 和 String。
字段类型写为字符串,不区分大小写

然后以下代码使用整数类型作为字段类型,进行筛选:

fieldlist = arcpy.ListFields("roads.shp", "", "Integer")

字段类型包括:BLOB (binary large object), Date, Double, Geometry, GlobalID, GUID, Integer, OID, Raster, Single, SmallInteger, String

但是这里ListFields() 函数使用的字段类型名称与 ArcGIS Pro 应用程序中使用的名称不同。 Integer 类型称为 Long; Single被称为Float; SmallInteger 被称为 Short;String被称为Text。此命名可能会造成混淆,因为 arcpy.AddField() 函数与 ArcGIS Pro 应用程序的术语一致。使用 AddField() 函数添加字段时,之前的字段类型分别称为 LONG、FLOAT、SHORT 和 TEXT。

ListFields() 函数返回 Field 对象的列表。相比之下,大多数其他列表函数都返回一个字符串列表。 Field 对象代表 表中的一列。字段对象属性包括名称、别名、类型和长度。下一节包括使用这些属性的示例,如果看不太懂可以等下一节再看看就能懂了。请注意,type property 使用与 ListFields() 函数相同的字段类型,即long integer 称为 Integer 等。

另一个有用的列表函数是 arcpy.ListFiles()。此函数返回工作区中所有文件的列表

arcpy.ListFiles({wild_card})

使用此函数,能获得工作区内的所有文件的列表:

import arcpy
arcpy.env.workspace = "C:/Testing/Demo/Greenway"
for file in arcpy.ListFiles():
    print(file)

其结果:显示子文件夹,但不显示这些文件夹中的内容。显示文件地理数据库,但不包括其内容。
因为该函数只是从数据管理的角度出发,没有考虑数据的内容等,所以在处理空间数据格式(例如 shapefile 和地理数据库)时,建议使用其他 ArcPy 列表函数,包括 ListFeatureClasses()、ListWorkspaces()、ListDatasets() 等。
可以使用该函数进行筛选,筛选的方法就和matlab等很相似了。

import arcpy
arcpy.env.workspace = "C:/Testing/Demo/Greenway"
for file in arcpy.ListFiles("*.csv"):
    print(file)

但是这个操作仅仅打印了文件名,在实际使用过程中,要使用获得的文件列表去执行其他操作

6.5 工作区和列表数据

通过将工作区设置为 MyData

python 空间地理 python空间数据_数据集

考虑在此文件夹上使用 ListFeatureClasses() 函数时会发生什么:

import arcpy
arcpy.env.workspace = "C:/Testing/MyData"
fcs = arcpy.ListFeatureClasses()
print(fcs)
['facilities.shp', 'parks.shp', 'roads.shp']

在mydata工作空间下的数据库中的数据并没有被检索,其实这也很容易理解。要获取数据库中的数据,还需要将工作空间设置到数据库。

import arcpy
arcpy.env.workspace = "C:/Testing/MyData/City.gdb"
fcs = arcpy.ListFeatureClasses()
print(fcs)
['bus_routes', 'bus_stops']

对于更复杂的文件结构,如下图,一个文件夹包含了子文件夹和数据库。

python 空间地理 python空间数据_数据集_02


当工作空间为 C:\Project 时,ListFeatureClasses() 函数仅返回bounds.shp。

可以使用 ListWorkspaces() 函数列出设置工作空间中的工作空间。这个函数的一般语法是:

arcpy.ListWorkspaces({wild_card}, {workspace_type})
import arcpy
arcpy.env.workspace = "C:/Project"
wspaces = arcpy.ListWorkspaces()
print(wspaces)
['C:/Project\\City.gdb', 'C:/Project\\Shapefiles', 
 'C:/Testing\\Water.gdb']

该函数可以识别五种工作空间:
ACCESS (personal geodatabases)
COVERAGE (coverages)
FILEGDB (file geodatabases)
FOLDER (shapefiles)
SDE (enterprise geodatabase)
但是前两种已经不太支持使用。

可以使用第二个参数设置工作空间的种类:

wspaces = arcpy.ListWorkspaces("", "FILEGDB")

以下文件夹示例,该文件夹在子文件夹结构中包含多个地理数据库和 shapefile

python 空间地理 python空间数据_python_03

arcpy.env.workspace = "C:/Project"
wspaces = arcpy.ListWorkspaces()

但在这个例子中使用ListWorkspaces()函数,就会识别planning文件夹,但是不会进一步识别文件夹中的数据库。

而地理数据库中的要素数据集更加复杂:

python 空间地理 python空间数据_python_04


函数 ListFeatureClasses() 返回数据库根目录下的两个要素类,roads 和 traffic_lights,但不返回要素数据集中的要素类。要获取这些要素类,需要将要素数据集 Cycling 设置为工作空间,如下所示:

import arcpy
arcpy.env.workspace = "C:/Project/Transportation.gdb/Cycling"
fcs = arcpy.ListFeatureClasses()
print(fcs)

到目前为止,应该清楚的是,列出文件夹中的所有数据会因不同的数据格式和子文件夹结构而变得复杂。为了便于处理更复杂的文件夹和文件结构,可以使用 arcpy.da.Walk() 函数。这是数据访问模块的一个功能,它是专门设计用来“走”下文件夹和数据库结构的。

arcpy.da.Walk(top, {topdown}, {onerror}, {followlinks}, {datatype}, 
              {type})

python 空间地理 python空间数据_python_05

import arcpy
walk = arcpy.da.Walk("C:/MyData")
for dirpath, dirnames, filenames in walk:
    print(dirpath, dirnames, filenames)

顶级工作区设置为 C:\MyData。 for 循环用于迭代结果元组中的项目。对于每个“级别”,da.Walk() 函数返回工作空间、文件夹名称和文件名,如下所示:

C:/MyData ['City.gdb'] ['facilities.shp', 'parks.shp', 'roads.shp']
C:\MyData\City.gdb [] ['bus_routes', 'bus_stops']

这里原书介绍的很复杂,我没有多做理解,感觉这部分在实际的使用中,暂时没有用到,不知道在以后的学习中,会不会使用到。

6.6 使用列表进行for循环

我认为这是比较重要的一节,在实际使用中,经常进行for循环。

获得所需值的列表后,您可以使用该列表对多个数据集进行批处理。这种处理最常使用 for 循环来完成。 for 循环遍历列表,一次一个元素;当没有要迭代的值时,循环结束。

本节仔细研究使用 for 循环的迭代。

import arcpy
arcpy.env.workspace = "C:/Data"
tifflist = arcpy.ListRasters("", "TIF")
for tiff in tifflist:
    arcpy.BuildPyramids_management(tiff)

在此示例中,ListRasters() 函数用于创建 TIFF 文件列表。 for 循环遍历列表中的每个元素并为每个栅格构建金字塔。这段代码变得非常强大,因为它可以自动执行相当繁琐的任务。例如,为数百个栅格构建金字塔可能会变得非常耗时。这里使用的几行 Python 代码就足以完成这项任务,无论是只有几个栅格数据集还是数百个栅格数据集,代码都是一样的。

作为另一个示例,使用与 ListFields() 函数结合使用的 for 循环进行迭代提供了字段及其属性的详细描述。以下代码在单个 shapefile 中创建字段列表,然后打印每个字段的名称、类型和长度:

import arcpy
arcpy.env.workspace = "C:/Data"
fieldlist = arcpy.ListFields("roads.shp")
for field in fieldlist:
    print("{0} is a field of type {1} with a length of {2}".
          format(field.name, field.type, field.length))

Python 列表通常用于自动执行重复性任务。考虑一个场景,其中原始数据由单个文件夹中的多个 shapefile 组成。您的任务是读取所有 shapefile 并将它们复制到现有地理数据库中。这是此任务的代码:

import arcpy
import os
arcpy.env.workspace = "C:/Transportation"
outgdb = "C:/Transportation/City.gdb"
fcs = arcpy.ListFeatureClasses()
for fc in fcs:
    desc = arcpy.da.Describe(fc)
    outfc = os.path.join(outgdb, desc["baseName"])
    arcpy.CopyFeatures_management(fc, outfc)

shapefile 的文件扩展名为 .shp。要删除此文件扩展名,da.Describe() 函数获取 shapefile 的 baseName 属性。例如,对于名为rivers.shp 的shapefile,baseName 属性是rivers,它被用作输出要素类的名称。但是,复制要素工具需要完整路径,即 C:\Transportation\City.gdb\rivers。故 可以使用 os.path.join() 获得此完整路径。

当存在子文件夹时,需要一种稍微不同的方法。考虑以下名为 City 的文件夹的文件结构,其中包含包含 shapefile 的子文件夹和名为 City_Copy 的文件夹以及地理数据库,如图所示。

python 空间地理 python空间数据_python_06


任务是将所有 shapefile 复制到现有地理数据库中。 shapefile 位于不同的文件夹中。这种文件夹结构使 ListFeatureClasses() 函数的使用变得复杂,因为每个文件夹都是一个单独的工作区。 da.Walk() 函数是查找所有 shapefile 并复制它们的另一种更有效的方法。这是此任务的代码:

import arcpy
import os
workspace = "C:/City"
outgdb = "C:/City_Copy/Study.gdb"
walk = arcpy.da.Walk(workspace, datatype="FeatureClass")
for dirpath, dirnames, filenames in walk:
    for file in filenames:
        infc = os.path.join(dirpath, file)
        desc = arcpy.da.Describe(infc)
        outfc = os.path.join(outgdb, desc["baseName"])
        arcpy.CopyFeatures_management(infc, outfc)

该代码在几个方面与以前的解决方案不同。首先,没有使用 env.workspace,因为工作空间是在 da.Walk() 函数中明确设置的。其次,da.Walk() 函数返回的文件名不包含完整路径,因此必须使用 os.path.join() 创建输入要素类的路径。

6.7 列表的使用:

列表是一种通用的 Python 数据类型,可以以不同的方式进行操作。尽管要素类、字段或栅格列表是使用 ArcPy 函数创建的,但该列表是使用 Python 的内置函数和列表方法进行操作的。以下是一些最常用的内置函数和方法的示例。
可以使用内置 Python len() 函数确定工作空间中要素类的数量。代码如下:

import arcpy
arcpy.env.workspace = "C:/Data/Example.gdb"
fcs = arcpy.ListFeatureClasses()
print(len(fcs))

可以使用 sort() 方法对列表进行排序。默认排序是按字母数字顺序排列的,但可以使用 sort() 方法的 reverse 参数进行反转。以下代码创建要素类列表,按字母数字对它们进行排序,并打印它们的名称。然后将排序反转,并再次打印名称。代码如下:

import arcpy
arcpy.env.workspace = "C:/Data/Example.gdb"
fcs = arcpy.ListFeatureClasses()
fcs.sort()
print(fcs)
fcs.sort(reverse=True)
print(fcs)

处理要素类、表、字段、栅格或其他空间数据类型的列表时,可以使用索引、切片和列表方法。
使用列表的另一种方法称为列表理解。 Python 中的列表推导式是一种通过迭代可迭代对象来创建列表的简洁方法。它提供了类似于 for 循环的紧凑语法。考虑以下 for 循环的通用示例:

for <item> in <list>:
    <expression>

接下来是典型列表理解的另一个示例。在此示例中,现有列表中的每个字母都转换为小写,结果是一个仅包含小写字符串的新列表:

old_list = ["G", "I", "S"]
newlist = [letter.lower() for letter in old_list]
print(newlist)
['g', 'i', 's']

列表推导还支持使用带有条件的元素过滤。使用这种条件的一般形式是:

[<expression> for <item> in <list> if <condition>]

下面的示例使用列表推导通过使用 isdigit() 方法评估字符串的字符是否为数字来过滤字符串的字符。结果是一个新列表,其中只有实际上是数字的字符。

mystring = "This string is 28 characters"
digits = [x for x in mystring if x.isdigit()]
print(digits)

列表推导可以与 ArcPy 的列表函数结合使用。以下脚本使用 ListFields() 函数创建要素类的字段列表。回想一下 ListFields 函数返回 Field 对象的列表。您可以通过遍历这些 Field 对象并使用 name 属性来获取字段名称列表,如下所示:

import arcpy
fc = "C:/Data/Study.gdb/zones"
field_names = []
for f in arcpy.ListFields(fc):
    field_names.append(f.name)
print(field_names)

可以使用列表推导以更简洁的方式完成相同的任务:

import arcpy
fc = "C:/Data/Study.gdb/zones"
field_names = [f.name for f in arcpy.ListFields(fc)]
print(field_names)

需要记住的点:

ArcPy includes several functions for exploring spatial data, including checking for the existence of datasets and describing datasets in a workspace. Lists of datasets are commonly used because they allow you to iterate over the elements to automate workflows.

The Exists() function determines whether a dataset exists. The Describe() and da.Describe() functions determine the properties of a dataset. These functions ensure that inputs for a script conform to expectations.

List functions facilitate batch processing. Once a list of elements is created, a script can be designed to iterate over all the elements in the list. For example, the ListFeatureClasses() function creates a list of all feature classes in a workspace, and a for loop iterates over all the elements in the list to perform the same operation on each feature class. List functions exist for different types of elements, including workspaces, files, datasets, feature classes, fields, rasters, tables, and others.

When exploring data, it is critical to be aware of the workspace being used as well as the use of catalog and system paths. List functions return data elements in the current workspace. Several functions can be used to carefully explore datasets, including ListWorkspaces(), ListDatasets(),and ListFiles().

Listing all the data elements is complicated by different data formats and subfolder structures. To facilitate working with more complex situations, you can use the da.Walk() function to “walk” up and down the folder and database structure to obtain all the elements inside a folder.

List comprehensions provide a concise alternative to regular for loops when working with lists.

ArcPy 包含多个用于探索空间数据的函数,包括检查数据集是否存在以及描述工作空间中的数据集。数据集列表是常用的,因为它们允许您迭代元素以自动化工作流程。
Exists() 函数确定数据集是否存在。 Describe() 和 da.Describe() 函数确定数据集的属性。这些函数确保脚本的输入符合预期。
列表函数有助于批处理。一旦创建了元素列表,就可以设计一个脚本来迭代列表中的所有元素。例如,ListFeatureClasses() 函数创建工作空间中所有要素类的列表,for 循环遍历列表中的所有元素以对每个要素类执行相同的操作。列表函数适用于不同类型的元素,包括工作空间、文件、数据集、要素类、字段、栅格、表格等。
在探索数据时,了解正在使用的工作空间以及目录和系统路径的使用至关重要。列表函数返回当前工作区中的数据元素。可以使用几个函数来仔细探索数据集,包括 ListWorkspaces()、ListDatasets() 和 ListFiles()。
列出所有数据元素因不同的数据格式和子文件夹结构而变得复杂。为了便于处理更复杂的情况,您可以使用 da.Walk() 函数在文件夹和数据库结构中上下“走动”,以获取文件夹内的所有元素。
使用列表时,列表推导式提供了常规 for 循环的简洁替代方案。