ArcGIS Python编程案例(9)-ArcPy数据访问模块

第八章 数据查询和选择 ||| 第十章 获取GIS数据列表和描述信息


我们将在本章中介绍以下几个案例:

  • 游标对象(cursor object)概况
  • 使用搜索游标(SearchCursor)访问要素类中的要素
  • 使用where条件语句筛选记录
  • 使用几何令牌(Geometry tokens)改进游标性能
  • 使用插入游标(InsertCursor)插入行
  • 使用更新游标(UpdateCursor)更新行
  • 使用更新游标(UpdateCursor)删除行
  • 编辑会话中插入行并更新行
  • 读取要素类的几何信息

引言

什么是游标(cursor)?游标是包含从要素类或表中获取的一行或多行数据的内存对象。每行数据包含了数据源中每个字段中的属性以及每个要素的几何信息。游标可对表和要素类的数据进行搜索,增加,插入,更新以及删除。
ArcPy数据访问模块(arcpy.da)是ArcGIS10.1新引入的模块,该模块包含的方法可迭代游标对象中的行。你还可以创建多种形式的游标。比如,搜索游标用于读取行数据。更新游标可用于更新行数据以及删除行,插入游标可用于插入新行。
ArcPy数据访问模块的引入带来了游标性能的提升与改进。ArcGIS10.1版本之前,游标的处理速度一直较慢,而现在游标的处理性能显著提升。ESRI的评估显示搜索游标速度提升了30倍,而插入游标提升了12倍。除了这些整体性能提升之外,数据访问模块还提供了一些新的选项来让程序员提升处理速度。你可以指定返回的字段而不用在游标中返回全部字段。这样就通过减少返回的数据量来提高性能。相同的情况还有几何属性。传统的方式是当你要访问要素的几何属性时,整个几何定义都会返回。你现在可以使用几何令牌(geomtry tokens)返回要素的部分几何属性而不是全部。你还可以使用列表和元组来代替行。此外新功能还包括编辑会话功能以及处理版本,域名以及子类型的功能。
arcpy.da提供了三个游标函数。每个游标函数都会返回一个与该函数同名的游标对象。SearchCursor()函数创建一个只读的搜索游标(SearchCursor)对象,该对象包含了表或要素类中的数据。InsertCursor()函数创建一个插入游标(InsertCursor)对象,该对象可用于向表或要素类插入行。UpdateCursor()函数创建一个更新游标(UpdateCursor)对象,该对象可用于编辑或删除表和要素类中的数据。每一个游标对象都提供了访问游标中行数据的方法。你可以在下表中看到游标函数,游标对象以及用法说明之间的关系:

函数 创建的游标对象 说明
SearchCursor() SearchCursor 只读查看表或要素类数据
InsertCursor() InsertCursor 向表或要素类插入行
UpdateCursor() UpdateCursor 编辑或删除表和要素类行

SearchCursor()函数用于返回一个搜索游标(SearchCursor)对象。该对象只能用于迭代返回的行数据集,且只有只读权限。你不能通过该对象进行插入,删除和更新操作。一个可选的where条件语句可用于限制返回的行。
创建了一个游标实例后通常需要迭代游标中的记录,尤其是使用搜索游标(SearchCursor)和更新游标(UpdateCursor)时。你需要理解关于遍历访问游标记录方面的几个特点。游标只能向前导航。当游标创建时,游标指针会位于游标中第一行记录上面。首次调用next()方法时,指针就会移动到首行。除了调用next()方法外,你还可以使用for循环语句来处理每一行记录。首行数据需要执行的操作完成后,调用next()方法指针就会移动到第二行。只要你需要访问其他行,该过程就会持续下去。不过,某行数据访问之后,你便不能再返回单独访问该行记录。举个例子,如果当前访问的是第三行,你就不能通过程序返回到第二行中。如果要想重新访问第一行和第二行,你就需要调用reset()方法或者重新创建游标对象重新遍历。如前所说,游标也经常使用for循环语句来遍历对象。事实上,这也是迭代游标对象更为常用的方式,也是编写脚本中更为有效的方式。游标访问导航方式如下图所示:

InsertCursor()函数可用于创建插入游标(InsertCursor)对象,该游标对象可以通过程序向要素类和表中添加新行。对象调用insertRow()方法插入行。你还可以使用游标对象的fields属性访问一个包含字段名称的只读元组对象。通过游标访问要素类或表时,游标锁会锁定该要素类或表。脚本在处理完成后需要释放游标,这一点非常重要。
UpdateCursor()函数可用于创建更新游标(UpdateCursor)对象,该对象可以更新或删除要素类和表中的行。同插入游标的情况一样,函数会设置锁来锁定正在编辑或删除的数据。如果游标是在Python的with语句中使用的话,锁会在数据处理完成后自动释放。自动释放游标锁的功能并不是一直都有。ArcGIS10.1之前的版本中,游标需要使用Python的del语句来进行手动释放。一旦创建了更新游标(UpdateCursor)实例,你就可以调用updateCursor()方法来更新表或要素类中的记录,也可以调用deleteRow()方法删除行记录。
数据锁定的问题需要再说明一下。插入游标和更新游标必须要在它们引用的数据源上设置锁。这样就意味着当前情况下其他的应用程序不能访问该数据源。锁是一种避免多个用户同时更改数据进而损坏数据的机制。在脚本中调用insertCursor()updateCursor()方法时,Python就会请求对数据设置锁。游标对象处理完成后必须释放该锁,这样其他的用户在运行ArcMap或ArcCatalog等程序时能够访问这些数据源。否则的话,其他程序不能访问这些数据。ArcGIS10.1之前的版本中,游标必须通过Python的del语句来解锁。类似的情况,ArcMap和ArcCatalog同样会锁定正在更新或删除的数据。如果数据源已经被某一程序锁定,Python脚本便不能访问该数据。因此,最好是在需要使用插入或更新游标的独立脚本运行之前,先关闭ArcMap和ArcCatalog。
本章中,我们会介绍用于访问和编辑表和要素类的游标的使用。不过,在ArcGIS10.1之前版本中的许多游标的概念仍然适用。

使用搜索游标(SearchCursor)访问要素类中的要素

很多情况下,你只是出于读取目的来检索表或要素类中的行数据。举个例子,你可能想要生成一个包含城市中所有价值高于10万美元的地块的列表。在这种情况下,你不需要编辑数据。你的需求只要通过生成一个满足一定要求的行数据列表就可以。

Getting ready

SearchCursor()函数用于返回搜索游标(SearchCursor)对象。该对象仅用于迭代一组返回的只读行数据。搜索游标对象中不执行插入,删除以及更新等操作。一个可选的where条件语句用于限制返回的行。在本案例中,你会学习如何使用SearchCursor()函数来创建一个搜索游标(SearchCursor)对象。
搜索游标(SearchCursor)对象中包含一个fileds属性以及next()reset()方法。fields属性是一个元组形式的只读数据结构,其包含了从要素类和表中获取的字段。接下来你会看到多次元组与游标一起出现的情况。元组是Python中类似于列表的数据结构,用于保存一系列数据。但是元组和列表还是有一些明显的区别。元组定义为包含在括号内的一系列值,而列表则定义为包含了方括号内的一系列值。元组不同于列表,其长度不能进行伸缩,当要求数据每次占据一个指定位置的情况下这会是一件很优雅的特点。

How to do it...

按照以下步骤来学习如何在一个搜索游标(SearchCursor)对象中访问表或要素类的行数据:
1.打开IDLE,打开一个新的脚本窗口。
2.脚本保存为C:\ArcpyBook\Ch9\SearchCursor.py文件。
3.导入arcpy.da模块:

import arcpy.da

4.设置工作空间路径:

arcpy.env.workspace = "C:/ArcpyBook/Ch9"

5.使用Python中的with语句创建一个游标:

with arcpy.da.SearchCursor("Schools.shp",("Facility","Name")) as cursor:

6.循环搜索游标(SearchCursor)并打印学校的名称。确保for循环语句的缩进以位于with语句块内:

for row in sorted(cursor):
    print "Shcool name:" + row[1]

7.保存脚本。
8.运行脚本。你会看到以下输出结果:

School name: ALLAN
School name: ALLISON
School name: ANDREWS
School name: BARANOFF
School name: BARRINGTON
School name: BARTON CREEK
………………………………
How it works...

SearchCursor()函数一起使用的with语句将会创建游标,打开游标并关闭游标。因此你就不必像ArcGIS10.1之前版本那样关注游标锁的释放问题。传递给SearchCursor()函数的第一个参数是一个要素类,这里指Schools.shp文件。第二个参数是一个包含了我们想要返回游标中的字段名称的元组。出于性能考虑,最好控制仅返回游标对象中那些你需要用来完成任务的字段。本案例中,我们仅指定返回FacilityName字段。搜索游标(SearchCursor)对象保存在cursor变量中。
with语句块中,我们使用了Python的for循环语句来循环返回的每一个学校数据。我们还使用了Python中的sorted()函数来对游标中的内容进行排序。你只要简单地使用代表你想要返回的字段的索引数就可以获取该字段值。在本案例中,我们想要返回Name列中的内容,相对应的索引数为1,也就说返回的字段名称元组中的第二个元素项。

使用where条件语句筛选记录

默认情况下,搜索游标(SearchCursor)会包含表或要素类中的所有行。不过很多情况下,你想按照一定的条件来限制返回的行数。通过使用where条件语句指定一个筛选器来限制返回到记录。

Getting ready

当你创建一个搜索游标(SearchCursor)对象时,默认情况下会返回表或要素类中的所有行。不过很多情况下,你想要限制返回的记录。你可以在调用SearchCursor()函数时,创建一个查询条件并传递给where条件语句参数来实现。在本案例中,你会在上一个案例创建的脚本中添加where条件语句来限制返回的记录。

How to do it...

按照以下步骤来对搜索游标对象指定一个筛选器来限制从表或要素类中返回的行数据:
1.打开IDLE,加载在上一个案例中创建的SearchCursor.py文件。
2.在SearchCursor()函数中添加where语句来查询Facility字段中包含文本“HIGH SCHOOL”的记录:

with.arcpy.da.SearchCursor("Schools.shp",("Facility","Name"),'"Facility"=\'HIGH SCHOOL\'')as cursor:

3.保存并允许脚本。输出结果只有高中学校返回:

High school name: AKINS
High school name: ALTERNATIVE LEARNING CENTER
High school name: ANDERSON
High school name: AUSTIN
High school name: BOWIE
High school name: CROCKETT
High school name: DEL VALLE
High school name: ELGIN
High school name: GARZA
High school name: HENDRICKSON
High school name: JOHN B CONNALLY
High school name: JOHNSTON
High school name: LAGO VISTA
How it works...

我们在第八章数据查询和选择中介绍了如何创建查询语句。where条件语句参数接受任何语法正确的SQL语句,在本案例中该参数用于限制返回的记录数。

使用几何令牌(Geometry tokens)改进游标性能

几何令牌(Geometry tokens)是ArcGIS10.1引入用来改进游标性能。使用几何令牌允许只返回部分几何信息而不用返回整个几何对象。由于返回数据量的原因,返回要素的完整几何对象会降低游标性能。而仅返回需要的几何信息则速度明显快很多。

Getting ready

令牌是以SHAPE@<要返回的要素几何信息>的格式作为字段列表中的字段来传递给游标构造函数。OID@令牌是唯一的例外,该令牌返回要素的对象ID。下面的代码示例用来访问要素的质心X,Y坐标:

with.arcpy.da.SearchCursor(fc,("SHAPE@XY","Facility","Name"))as cursor:

下表中列出了可用的几何令牌。不是所有的游标对象支持所有的几何令牌。请自行查看ArcGIS帮助文件中关于每类游标类型所支持的令牌的相关内容。SHAPE@几何令牌返回要素的完整几何对象。不过使用SHAPE@需要注意,返回要素的完整几何对象的性能成本开销大,能够显著地影响性能。如果你不需要完整几何对象,那就不要使用该令牌!

令牌 说明
SHAPE@ 要素的几何对象。
SHAPE@XY 一组要素的质心 x,y 坐标。
SHAPE@TRUECENTROID 一组要素的真正质心 x,y 坐标。
SHAPE@X 要素的双精度 x 坐标。
SHAPE@Y 要素的双精度 y 坐标。
SHAPE@Z 要素的双精度 z 坐标。
SHAPE@M 要素的双精度 m 值。
SHAPE@JSON 表示几何的 esri JSON 字符串。
SHAPE@WKB OGC 几何的WKB制图表达。该存储类型将几何值表示为不间断的字节流形式。
SHAPE@WKT OGC 几何的WKT制图表达。其将几何值表示为文本字符串。
SHAPE@AREA 要素的双精度面积。
SHAPE@LENGTH 要素的双精度长度。

在本案例中,将使用几何令牌来提高游标的性能。你将获取parcels要素类中每一个地块的质心XY坐标以及一些其他属性信息。

How to do it...

按照以下步骤向游标对象中添加几何令牌,这会提高游标对象的执行效率:
1.打开IDLE,打开一个新的脚本窗口。
2.保存脚本至C:\ArcpyBook\Ch9\GeometryToken.py文件。
3.导入arcpy.da模块和time模块:

import arcpy,time

4.设置工作空间路径:

arcpy.env.workspace = "C:/ArcpyBook/Ch9"

5.我们将计算使用几何令牌的情况下执行脚本花费的时间。在脚本中添加一个开始时间:

start = time.clock()

6.使用with语句来创建一个游标,该游标包含每一个要素的质心坐标以及存储在PY_FULL_OW字段中的所有者信息:

with.arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW","SHAPE@XY")) as cursor:

7.循环搜索游标(SearchCursor)的每一行并打印地块所有者的名字。确保for循环语句的缩进以位于with语句块内:

for row in cursor:
    print "Parcel owner: {0} has a location of:{1}".format(row[0],row[1])

8.计算运行时间:

elapsed = time.clock()-start

9.打印运行时间:

print "Execution time: " + str(elapsed)

10.保存脚本。
11.运行脚本。你会看到与下面内容类似的输出结果。注意一些执行时间,你的时间会不一样:

Parcel owner:AUSTIN AFFORDABLE HOUSING has a location of:(3139099.127188288, 10111192.98966641)
...............................................
Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: (3110480.5197341456, 10070911.174956793)
Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: (3110670.413783513, 10070800.960865)
Parcel owner: CITY OF AUSTIN has a location of:(3143925.0013213265, 10029388.97419636)
Parcel owner: CITY OF AUSTIN % DOROTHY NELL ANDERSON ATTN BARRY LEE ANDERSON has a location of: (3134432.983822767,10072192.047894118)
Execution time: 59.2429891474

现在,我们计算返回完整几何对象的的运行时间:

1.另存为脚本至C:\ArcpyBook\Ch9\GeomteryTokenEntireGeometry.py文件。
2.在SearchCursor()函数使用SHAPE@替换SHAPE@XY来返回完整几何信息:

with arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW","SHAPE@")) as cursor:

3.保存并运行脚本。你会看到下面的输出结果。你的时间会跟我的不一样,不过注意执行时间变的慢了一些。在本案例中,由于我们仅返回了2600个元素运行时间只慢了一秒多。如果要素类的数据量足够大,运行时间的差异会加大:

Parcel owner: AUSTIN AFFORDABLE HOUSING has a location of:<geoprocessing describe geometry object object at 0x02ED44C0>
.........................................
Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: <geoprocessing describe geometry object object at 0x06B9BE00>
Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: <geoprocessing describe geometry object object at 0x2400A700>
Parcel owner: CITY OF AUSTIN has a location of: <geoprocessing describe geometry object object at 0x06B9BE00>
Parcel owner: CITY OF AUSTIN % DOROTHY NELL ANDERSON ATTN BARRY LEE ANDERSON has a location of: <geoprocessing describe geometry object object at 0x2400A700>
Execution time: 60.0561424156
How it works...

几何令牌可以作为游标构造函数中的一个字段名称来使用。这些令牌仅返回部分几何信息而不用返回完整的几何信息,因此使用几何令牌用于提升游标性能。这将会显著提升游标性能,尤其是处理大数据量的线或面数据集。如果只需要游标对象中的特定的几何信息,那你应该使用几何令牌。

使用插入游标(InsertCursor)插入行

你还可以使用插入游标(InsertCursor)对象向表或要素类中插入行。如果想在新行中插入属性值,你就需要按照属性表中字段顺序依次赋值。

Getting ready

InsertCursor()函数可用于创建插入游标(InsertCursor)对象,该游标对象可以通过程序向要素类和表中添加新行。insertRow()方法可向插入游标(InsertCursor)对象中添加新行。行以列表或元组的形式传递给insertRow()方法。列表中的值需与插入游标对象创建时定义的字段值一致。同其他类型的游标一样,你还可以使用该方法中的第二个参数来限制返回的字段名称。InsertCursor()函数也支持几何令牌。
下面的代码示例阐述了如何使用插入游标(InsertCursor)对象向要素类中插入新行。本案例中,我们要在California要素类中插入两个新的火情点数据。要插入的行数据需要保存在一个列表变量中。之后,在构造函数中使用要素类和字段参数创建一个插入游标对象。最后,调用insertRow()方法向要素类中插入新行:

rowValue = [('Bastrop','N',3000,(-105.345,32.234)),('Ft Davis','N',456,(-109.456,33.468))]
fc = "C:/data/wildfires.gdb/California"
fileds = ["FIRE_NAME","FIRE_CONTAINED","ACRES","SHAPE@XY"]
with arcpy.da.InsertCursor(fc,fields) as cursor:
    for row in rowValues:
        cursor.insertCursor(row)

在本案例中,使用插入游标将从文本文件中的读取的火情数据添加到一个点要素类中。向要素类中插入行时,你需要清楚如何向要素类中添加要素的几何表达。这可以通过使用插入游标(InsertCursor)以及两个重要的对象:数组(Array)和点(Point)。在本案例中,我们将火情发生位置点添加到一个当空的点要素类中。此外,你还会使用Python的文件操作方法从文本文件中读取坐标数据。

How to do it...

我们将导入北美洲地区发生在2007年10月份某一天的火情数据。数据包含在一个以逗号为分隔符的文本文件中,该文件包含了一天内发生的每一次火灾,一次火灾一行记录。火灾数据包含了使用逗号分隔符隔开的经纬度以及可信度值。该数据是使用遥感数据自动获取火灾的发生情况。可信度值数据范围从0到100。可信值越高则表示火灾发生的可能性越大:
1.打开C:\ArcpyBook\Ch9\WildfireData\NorthAmericaWildfire_2007275.txt文件查看文件中的内容。
你会发现该文件是一个包含火灾发生位置以及可信度值信息的逗号分隔符文件。我们会使用Python来逐行读取该文件的内容并向位于
C:\ArcpyBook\Ch9\WildfireData\WildlandFires.mdb个人地理数据库中的FireIncidents要素类中插入新的点要素。
2.关闭文本文件。
3.打开ArcCatalog。
4.浏览至C:\ArcpyBook\Ch9\WildfireData位置。
你会看到一个叫做WildlandFires的个人地理数据库。打开该数据框就会看到一个叫做FireIncidents的要素类。当前这是一个空的要素类。我们会通过读取刚才打开的文本文件来添加点要素。
5.右键单击FireIncidents选择属性(Properties)
6.点击字段(Fields)选项卡。
我们之前在文件中看到的经纬度值会导入SHAPE字段中而可信度值将写入到CONFIDENCEVALUE字段中。
7.打开IDLE并创建一个新脚本。
8.脚本保存为C:\ArcpyBook\Ch9\InsertWildfires.py文件。
9.导入arcpy模块。

import arcpy

10.设置工作空间路径:

arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"

11.打开文本文件并读取所有的行至列表中:

f = open(r"C:\ArcpyBook\Ch9\WildfireData\NorthAmericaWildfire_2007275.txt","r")
lstFires = f.readlines()

12.添加try语句块:

try:

13.使用with语句创建一个插入游标(InsertCursor)对象。确保语句语句以位于try语句内。游标会创建在FireIncidents要素类中:

with arcpy.da.InsertCursor("FireIncidents",("SHAPE@XY","CONFIDENCEVALUE")) as cur:

14.创建一个计数器变量以用于打印处理进程:

cntr = 1

15.使用for语句循环文本文件的行文件。由于文本文件使用逗号分隔符,因此我们使用Python的split()函数来将数值分离并保存至一个列表变量vals中。之后我们将分别提取纬度,经度和可信度值并分别赋值给变量。最后,我们会将这些值放入一个叫做rowValue的列表变量中,该变量之后传递给insertRow()方法,最后我们将打印消息:

for fire in lstFires:
    if 'Latitude' in fire:
        continue
    vals = fire.split(",")
    latitude =float(vals[0])
    longitude = float(vals[1])
    confid = int(vals[2])
    rowValue = [(longitude,latitude),confid]
    cur.insertRow(rowValue)
    print "Record number " + str(cntr) + " written to feature class"
    cntr = cntr + 1

16.添加except语句,如果发生错误将打印错误:

except Exception as e:
    print e.message

17.添加finally语句来关闭文本文件:

finally:
    f.close()

18.完整代码如下:

import arcpy
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
f = open(r"C:\ArcpyBook\Ch9\WildfireData\NorthAmericaWildfire_2007275.txt","r")
lstFires = f.readlines()
try:
    with arcpy.da.InsertCursor("FireIncidents",("SHAPE@XY","CONFIDENCEVALUE")) as cur:
        cntr = 1
        for fire in lstFires:
            if "Latitude" in fire:
                continue
            vals =  fire.split(",")
            latitude = float(vals[0])
            longitude = float(vals[1])
            confid = int(vals[2])
            rowValue  = [(longitude,latitude),confid]
            cur.insertRow(rowValue)
            print "Record number " + str(cntr) + " written to feature class"
            cntr = cntr + 1
except Exception as e:
    print e.message
finally:
    f.close()

19.保存并运行脚本。随着脚本的运行,你会看到下面的消息写入窗口屏幕中:

Record number: 1 written to feature class
.......................................
Record number: 406 written to feature class
Record number: 407 written to feature class
Record number: 408 written to feature class
Record number: 409 written to feature class
Record number: 410 written to feature class
Record number: 411 written to feature class

20.打开ArcMap添加FireIncidents要素类。点数据如下图所示:

How it works...

这里有必要作进一步解释。lstFires变量保存了一个包含逗号分隔符文本文件中所有火情数据的列表。for语句会逐一循环遍历每条记录,将每一个单独的记录插入到fire变量中。我们同样还包括了一个if条件语句来跳过文件中的首行记录,该行记录用来作为数据头用。如前所述,我们之后会从vals变量中提取每个单独的纬度,经度和可信度值元素项,其中vals变量是一个Pyhon列表对象。之后我们将提取的值分别赋值给变量latitudelongitude以及confid。之后我们按照插入游标(InsertCursor)创建时定义的字段顺序将这些值放入一个叫做rowValue的列表变量中。即经纬度值对放在前面,之后是可信度值。最后,我们对变量cur调用insertRow()方法并将新的rowValue变量传递给该方法。我们打印一条信息来指明脚本执行的进程,同时创建exceptfinally语句来处理错误并关闭文本文件。在finally语句块中添加f.close()方法确保即便在前面的try语句中发生错误,该语句仍会执行关闭文本文件操作。

使用更新游标(UpdateCursor)更新行

如果需要编辑或删除表或要素类中的行数据,你可以使用更新游标(UpdateCursor)。同插入游标(InsertCursor)一样,更新游标(UpdateCursor)中的数据内容可以通过使用where条件语句来控制。

Getting ready

UpdateCursor()函数用于更新或删除表或要素类中的行数据。调用UpdateCursor()函数将返回一个更新游标(UpdateCursor)对象。
更新游标(UpdateCursor)对象会在正在编辑或删除的数据上设置锁。如果游标是在Python的with语句中使用的话,该锁会在数据处理完成后自动释放。游标锁自动释放的功能并不是一直都有。之前的版本中,游标需要使用Python的del语句来进行手动释放。创建了更新游标(UpdateCursor)实例,你就可以调用updateRow()方法来更新表或要素类中的记录,也可以调用deleteRow()方法删除行记录。
本案例中,我们将会在脚本中使用更新游标(UpdateCursor)来更新FireIncidents要素类中的每一个要素,我们会添加一个对可信度值描述性更强的字段并赋值poorfairgoodexcellent。更新字段值之前,脚本会先向FireIncidents要素类中添加一个新字段。

How to do it...

按照以下步骤来创建一个更新游标(UpdateCursor)对象来编辑要素类中的行数据:
1.打开IDLE并创建一个新脚本。
2.脚本保存为C:\ArcpyBook\Ch9\UpdateWildfires.py文件。
3.导入arcpy模块。

import arcpy

4.设置工作空间路径:

arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"

5.添加try语句块:

try:

6.在FireIncidents要素类中添加一个CONFID_RATING的新字段。确保语句缩进以位于try语句中:

arcpy.AddField_management("FireIncidents","CONFID_RATING","TEXT",10)
print "CONFID_RATING field added to FireIncidents"

7.在with语句中创建一个更新游标(UpdateCursor)的实例:

with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE","CONFID_RATING")) as cursor:

8.创建一个计数器变量用于打印处理进程。确保语句的缩进以位于with语句块中:

cntr = 1

9.循环遍历FireIncidents要素类中每行数据。按照以下原则更新CONFID_RATING字段值:

可信值在0至40之间赋值POOR
可信值在41至60之间赋值FAIR
可信值在61至85之间赋值GOOD
可信值在86至100之间赋值EXCELLENT

for row in cursor:
    if row[0] <= 40:
        row[1] = 'POOR'
    elif row[0] > 40 and row[0] <= 60:
        row[1] = 'FAIR'
    elif row[0] > 61 and row[0] <= 85:
        row[1] = 'GOOD'
    else:
        row[1] = 'EXCELLENT'
    cursor.updateRow(row)
    print "Record number " + str(cntr) + " updated"
    cntr = cntr + 1

10.添加except语句块,发生错误时打印错误消息:

except Exception as e:
    print e.message

11.完整代码如下:

import arcpy
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
try:
    arcpy.AddField_management("FireIncidents","CONFID_RATING","TEXT","10")
    print "CONFID_RATING field added to FireIncidents"
    with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE","CONFID_RATING")) as cursor:
        cntr = 1
        for row in cursor:
            if row[0] <= 40:
                row[1] = 'POOR'
            elif row[0] > 40 and row[0] <= 60:
                row[1] = 'FAIR'
            elif row[0] > 60 and row[0] <=85:
                row[1] = 'GOOD'
            else:
                row[1] = 'EXCELLENT'
            cursor.updateRow(row)
            print "Record number " + str(cntr) + " updated"
            cntr = cntr + 1
except Exception as e:
    print e.message

12.保存并运行脚本。随着脚本的运行,你会看到下面的消息写入窗口屏幕中:

CONFID_RATING field added to FireIncidents
Record number 1 updated
..................
Record number 406 updated
Record number 407 updated
Record number 408 updated
Record number 409 updated
Record number 410 updated

13.打开ArcMap,添加FireIncidents要素类数据。打开属性表你就会看到一个新的CONFID_RATING字段,且已经通过更新游标(UpdateCursor)生成了属性值:

你在非编辑会话状态下对游标对象中所执行的插入,更新和删除操作是不能恢复的。不过,ArcGIS10.1支持编辑会话状态下的游标功能,也就意味着你可以在编辑状态下完成这些操作来避免不能恢复的问题。我们会在后面介绍编辑会话相关内容。

How it works...

本案例中,我们使用更新游标(UpdateCursor)来更新了要素类中的所有要素。首先我们使用Add Field工具添加一个CONFID_RATING字段,该字段用于保存我们根据其他字段值来赋的新值。根据CONFIDENCEVALUE字段值分成差(poor),中(fair),好(good),优(excellent)四个级别。之后基于FireIncidents要素类创建了一个更新游标(UpdateCursor)实例,并返回了之前提及的两个字段。随后脚本循环遍历每一个要素并根据CONFIDENCEVALUE字段值在CONFID_RATING字段赋值差(poor),中(fair),好(good)或优(excellent)。Python的if/elif/else结构用来控制根据可信度值赋值的处理流程。CONFID_RATING的值之后通过updateRow()方法更新到要素类中。

使用更新游标(UpdateCursor)删除行

更新游标(UpdateCursor)除了用于编辑表或要素类中的行,还可以删除行。需要注意一点,非编辑会话状态下的删除行操作是不可恢复的。

Getting ready

更新游标(UpdateCursor)除了可以更新记录,还可以删除表或要素类中的行。更新行和删除行操作中,创建更新游标(UpdateCursor)的方式都是相同的,不过删除行操作不调用updateRow()方法,而是调用deleteRow()方法。你也可以使用where条件语句来限制返回的记录。在本案例中,我们将使用一个通过where条件语句筛选的更新游标(UpdateCursor)来删除FireIncidents要素类中的记录。

How to do it...

按照以下步骤创建一个更新游标(UpdateCursor)来删除要素类中的行:
1.打开IDLE并创建一个新脚本。
2.脚本保存为C:\ArcpyBook\Ch9\DeleteWildfires.py文件。
3.导入arcpy模块。

import arcpy

4.设置工作空间路径:

arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"

5.添加try语句块:

try:

6.在with语句中创建一个更新游标(UpdateCursor)的实例:

with arcpy.da.UpdateCursor("FireIncidents",("CONFID_RATIING"),'[CONFID_RATING]=\'POOR\'') as cursor:

7.创建一个计数器变量用于打印处理进程。确保语句的缩进以位于with语句块中:

cntr = 1

8.调用deleteRow()方法删除返回的行。循环遍历返回的行,每次删除一行:

for row in cursor:
    cursor.deleteRow()
    print "Record number " + str(cntr) + " deleted"
    cntr = cntr + 1

9.添加except语句块,发生错误时打印错误消息:

except Exception as e:
    print e.message

10.完整代码如下:

import arcpy
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
try:
    with arcpy.da.UpdateCursor("FireIncidents",("CONFID_RATING"),'[CONFID_RATING]=\'POOR\'') as cursor:
        cntr = 1
        for row in cursor:
            cursor.deleteRow()
            print "Record number " + str(cntr) + " deleted"
            cntr = cntr + 1
except Exception as e:
    print e.message

11.保存并运行脚本。随着脚本的运行,你会看到下面的消息写入窗口屏幕中。37条记录从FireIncidents要素类中删除:

Record number 1 deleted
Record number 2 deleted
......................
Record number 33 deleted
Record number 34 deleted
Record number 35 deleted
Record number 36 deleted
Record number 37 deleted
How it works...

要素类和表中的行可以调用更新游标(UpdateCursor)中的deleteRow()方法来删除。在本案例中,我们在更新游标(UpdateCursor)构造函数中使用了where条件语句来限制仅返回CONFID_RATING字段值为POOR的记录。我们之后循环遍历游标中返回的记录并调用deleteRow()方法来删除行。

编辑会话中插入行并更新行

在本章中一直提及编辑会话外对表或要素类所执行的插入,更新和删除操作都是永久性且不可恢复的。编辑会话则让你拥有了更大的灵活性,可以回滚不想要的更改操作。

Getting ready

目前为止,我们已经使用了插入游标和更新游标向表和要素类中添加数据,编辑数据和删除数据。只是脚本执行完成后,这些更改都是永久性且不可恢复的。数据访问模块中新的Editor类支持创建编辑会话和编辑操作。编辑会话中,要素类和表的更改在调用特定方法来保存应用修改之前的临时数据。这一点与ArcGIS桌面软件中的编辑工具的功能相同。
编辑会话是通过调用初始化会话的Editor.startEditing()方法开始。在编辑会话中,你通过调用Editor.startOperation()方法开始执行编辑操作。之后你可以执行各种操作来编辑你的数据。这些编辑结果可以执行恢复,重做和中止操作来回滚,向前滚动和取消编辑操作。操作完成后,你可以调用Editor.stopOperation()方法,紧接着调用Editor.stopEditing()方法。编辑回话的处理过程如下图所示:

你可以退出会话而不保存所做的修改。在这种情况下,这些修改不会保存。编辑会话允许在会话内执行操作并可以将修改永久保存到数据库中或是回滚。此外Editor类还支持撤销和重做操作。
下面的代码示例展示了完整的编辑会话过程,包括创建Editor对象,开始编辑会话和编辑操作,编辑数据操作(这里是一个插入操作),停止操作以及最后保存修改结果来停止编辑会话:

edit = arcpy.da.Editor('Database Connections/Portland.sde')
edit.startEditing()
edit.startOperation()
with.arcpy.da.InsertCursor("Portland.jpg.schools",("SHAPE@XY","Name")) as cursor:
    cursor.insertRow((764271.100,686465.725),'New School')
edit.stopOperation()
edit.stopEditing(True)

Editor类可用于个人地理数据库,文件地理数据库以及ArcSDE地理数据库。此外,编辑会话还可以在版本化的数据库中开启和关闭。你只能一次编辑一个工作空间,该工作空间通过将工作空间的引用地址传递给Editor构造函数来指定。Editor对象创建后就可以调用所有的方法来执行开始操作,停止操作和取消操作,以及撤销和重做操作。

How to do it...

按照以下步骤在编辑会话中使用更新游标(UpdateCursor):
1.打开IDLE。
2.打开C:\ArcpyBook\Ch9\UpdateWildfires.py脚本并另存为
C:\ArcpyBook\Ch9\EidtSessionUpdateWildfires.py文件。
3.我们要对脚本做些修改来更新CONFID_RATING字段值。
4.删除下面几行代码:

arcpy.AddField_management("FireIncidents","CONFID_RATING","TEXT",10)
print "CONFID_RATING field added to FireIncidents"

5.创建一个Editor类的实例并开始编辑会话。下面的代码放到try语句块中:

edit = arcpy.da.Editor('C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb')
edit.startEditing(True)

6.如下所示修改if语句:

if row[0] > 40 and row[0] <= 60:
    row[1] = 'GOOD'
elif row[0] > 60 and row[0] <= 85:
    row[1] =  'BETTER'
else:
    row[1] = 'BEST'

7.结束编辑会话并保存编辑内容。下面语句置于计数器递增语句下面:

edit.stopEditing(True)

8.完整代码如下:

import arcpy
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
try:
    edit = arcpy.da.Editor('C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb')
    edit.startEditing(True)
    edit.startOperation()
    with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE","CONFID_RATING")) as cursor:
        cntr = 1
        for row in cursor:
            if row[0] > 40 and row[0] <= 60:
                row[1] = 'GOOD'
            elif row[0] > 60 and row[0] <=85:
                row[1] = 'BETTER'
            else:
                row[1] = 'BEST'
            cursor.updateRow(row)
            print "Record number " + str(cntr) + " updated"
            cntr = cntr + 1
    edit.stopOperation()
    edit.stopEditing(True)
except Exception as e:
    print e.message

9.保存并运行脚本。

How it works...

编辑操作应在编辑会话中进行,其中编辑会话调用Editor.startEditing()方法来初始化。startEditing()方法接受两个可选参数分别为with_undo以及multiuser_mode。其中with_undo参数接受一个布尔值true/false,默认值为true。当该参数设置为true时,则创建了撤销和重做堆栈。multiuser_mode默认为true,当该参数设置为false时,你就完全控制了对正在编辑的未版本化或版本化数据集。如果数据集是未版本化的数据集,那么你调用stopEditing(False)则不会提交编辑内容。而如果设置为true,则会提交编辑内容。Editor.stopEditing()方法接受一个布尔值true/false参数,用来指明编辑内容是否保存。默认值为true
Editor类支持撤销和重做操作。我们先看一下撤销操作。在编辑会话中,可以执行许多编辑操作。在这种情况下你需要撤销之前的操作的话,可以调用Editor.undoOperation()方法来移除撤销堆栈中最近的编辑操作。如下图所示:


恢复操作通过调用Editor.redoOperation()方法来初始化,会恢复之前撤销的一步操作。如下图所示:

读取要素类的几何信息

有些时候你需要访问要素类中要素的几何信息。Arcpy提供了读取不同对象几何信息的功能。

Getting ready

Arcpy中与要素类有关的几何对象包括PolygonPolylinePointGeomtry以及MultiPoint,这些对象都可以通过游标来访问。几何对象与要素类中shape字段有关。你可以通过几何对象来读取要素类中每一个要素的几何信息。
线(polyline)与面(polygon)要素类由包含了多个部分的要素组成。你可以调用partCount属性来返回每个要素的部分数量然后对每个部分调用getPart()来循环遍历每个点并提取坐标信息。点(point)要素类由包含了每个点坐标信息的要素组成,每个要素对应一个PointGeometry对象。
本案例中,你将使用搜索游标(SearchCursor)对象和Polygon对象来读取一个面要素类的几何信息。

How to do it...

按照以下步骤来学习如何读取要素类中每个要素的几何信息:
1.打开IDLE,创建一个新的脚本。
2.脚本保存为C:\ArcpyBook\Ch9\ReadGeometry.py文件。
3.导入arcpy模块:

import arcpy

4.将SchoolDistricts面要素类设置为输入要素类:

infc = "C:/ArcpyBook/data/CityOfSanAntonio.gdb/SchoolDistricts"

5.基于输入要素类创建搜索游标(SearchCursor)对象,并返回ObjectIDShape字段。Shape字段包含了每个要素的几何信息。游标会在for循环语句中创建,我们将循环迭代要素类中的所有要素:

with arcpy.da.SearchCursor(infc,["OID@","SHAPE@"]) as cursor:
    for row in cursor:
        print "Feature {0}:".format(row[0])
        partnum = 0

6.使用for循环语句迭代要素的每个部分:

for part in row[1]:
    print "Part {0}".format(partnum)

7.使用for循环语句循环遍历每个部分的节点并打印X,Y坐标:

for pnt in part:
    if pnt:
        print "{0},{1}".format(pnt.X,pnt.Y)
    else:
        print "Interior Ring"
partnum += 1

8.保存并运行脚本。脚本将每个要素,要素的每个部分以及每个部分的节点坐标信息如下:

Feature 1:
Part 0:
-98.492224986, 29.380866971
-98.489300049, 29.379610054
-98.486967023, 29.378995028
-98.48503096, 29.376808947
-98.481447988, 29.375624018
-98.478799041, 29.374304981
.....................
-98.4472064,29.467672906
-98.44719583,29.46827383
-98.447195407,29.468297826

**How it works...
**
我们一开始先创建一个搜索游标对象来保存要素类内容。之后使用for语句循环遍历游标内的每一行。对于每一行数据,我们再次循环遍历所有的几何部分。对于每个部分,我们返回每个部分相关的点并打印每个点的x,y坐标信息。


第八章 数据查询和选择 ||| 第十章 获取GIS数据列表和描述信息

推荐阅读更多精彩内容