June 13, 2020

Shapefile属性操作之查

版权声明:本文为博主原创文章,转载请注明原文出处!

作者:阿振

写作时间:2020-06-13 夜


开篇

在前面几篇博文中,我们分别介绍了矢量空间数据的属性数据的增(CREATE)删(DELETE)改(UPDATE)操作,这篇博文我们来聊聊属性数据的查询(Retrieve)操作。

案例介绍

我们还是使用之前的分省Shapefile数据,主要包含每个省的一些统计信息。下面以两个案例进行介绍:

  1. 从给定数据中查询中学数量(HighSchool字段)大于1万所的省份
  2. 从给定数据中查询中学数量最多的省份

下面简单说一下使用GDAL进行属性数据查询的两种思路:

  1. 因为矢量数据的属性一般都是以关系表进行保存的,所以我们可以使用关系数据库查询语言SQL进行数据查询。GDAL支持部分SQL查询功能。
  2. 我们可以遍历图层Layer中包含的所有Feature要素,然后读取要素的属性数据进行筛选过滤得到我们想要的结果。

SQL查询方式

代码展示

Talk is cheap. Show me the code.

首先,我们来看看使用SQL进行查询的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from osgeo import ogr
ogr.UseExceptions()

ds: ogr.DataSource = ogr.Open('../data/Provinces.shp')
# 注意Layer的名称不能包含中文
layer: ogr.Layer = ds.GetLayer()
# 选择出中学数量大于1万所的省份
query: str = f'SELECT NAME, HighSchool FROM {layer.GetName()} WHERE HighSchool > 10000'
selected: ogr.Layer = ds.ExecuteSQL(query)
# 这里的Feature中只包含两个属性NAME和HighSchool
for feature in selected:
print(feature.GetField('NAME'))

# 选择出中学数量最多的省份
# 我尝试使用MAX函数和嵌套的SELECT语句进行实现,但是执行报错,应该是OGR不支持嵌套的SQL查询
query: str = f'SELECT NAME, HighSchool FROM {layer.GetName()} ORDER BY HighSchool DESC'
selected: ogr.Layer = ds.ExecuteSQL(query)
print(selected.GetFeature(0).GetField('NAME'))
print(selected.GetFeature(0).GetField('HighSchool'))

del ds

方法总结

  1. 首先我们使用ogr.Open()函数读取数据,使用GetLayer()方法获取图层
  2. 然后构造SQL查询语句,图层名称对应的是SQL语句中的表名。注意如果图层名称为中文,查询会失败。
  3. 然后使用ExecuteSQL()方法执行查询,得到的查询结果仍然是一个ogr.Layer图层类,但是图层中的要素属性只包含我们查询语句中指定的字段
  4. 对于第二个案例,我们本来可以使用一个嵌套的SELECT查询语句以及MAX聚合函数得到最大的中学数量,但是使用嵌套的SQL查询执行会失败。所以我在第二个案例中使用了ORDER BY子句进行排序,然后查询结果的第一个要素就是我们寻找的最大值。

遍历Feature要素方式

代码展示

我们再来看使用遍历Feature要素的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from osgeo import ogr
ogr.UseExceptions()

ds: ogr.DataSource = ogr.Open('../data/Provinces.shp')
# 注意Layer的名称不能包含中文
layer: ogr.Layer = ds.GetLayer()
# 使用filter函数对要素属性进行过滤
selected = list(filter(lambda f: f.GetField('HighSchool') > 10000, layer))
for feature in selected:
print(feature.GetField('NAME'))

# 使用sorted方法对要素进行自定义排序,这里使用逆序
selected = sorted(layer, key=lambda f: f.GetField('HighSchool'), reverse=True)
print(selected[0].GetField('NAME'))
print(selected[0].GetField('HighSchool'))

del ds

方法总结

  1. 使用遍历Feature要素的方法进行查询是我们在获取了图层包含的所有Feature要素集合以后,使用Python内置的函数对该集合进行过滤,排序等操作得到我们想要的查询结果。
  2. filter()函数的第一个参数是一个自定义函数,第二个参数是一个可迭代对象iterable。该函数会遍历可迭代对象将满足第一个自定义函数的值过滤出来。
  3. sorted()函数包含三个参数(后两个可选),第一个参数是一个可迭代对象iterable,第二个参数是用于自定义排序的函数,第三个参数指定是否逆序。sorted()函数的返回值是一个list对象。
  4. 我更喜欢使用第二种遍历的方式,因为更方便调试一些。当然如果对SQL语言熟悉的同学,可能更喜欢SQL这种声明式编程的方式。