July 11, 2018

Fiona简介及Shapefile数据读取

Fiona简介及Shapefile数据读取

作者:阿振

邮箱:tanzhenyugis@163.com

博客:https://blog.csdn.net/theonegis/article/details/80089375

修改时间:2018-06-06

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


Fiona简介

用GDAL的Python绑定API书写程序有没有一种仍然在写C/C++的感觉,Fiona基于GDAL提供了更加Pythonic的读取空间矢量数据的API,参见:http://toblerity.org/fiona/index.html

这里主要说一下Fiona中对数据的描述模型和GDAL中的不同:

GDAL中对于矢量数据采用数据源(DataSource)- 图层(Layer)- 要素(Feature)- 属性和几何体(Attributes and Geometry)

Fiona采用Python中内置的数据结构表示矢量数据,一个要素以GeoJSON表示,使用Python内置的字典(dict)结构组织;一个图层包含在一个集合中(Collection)。可以对该集合进行迭代遍历,得到其中的要素。

要素是以GeoJSON表示的,结构如下:

1
{'type': 'Feature', 'id': '0', 'geometry': {'type': 'Polygon', 'coordinates': [[(96.416, 42.7588), (96.416, 42.7148), (95.9766, 42.4951), (96.0645, 42.3193), (96.2402, 42.2314), (95.9766, 41.9238), (95.2734, 41.6162), (95.1855, 41.792), (94.5703, 41.4844), (94.043, 41.0889), (93.8672, 40.6934), (93.0762, 40.6494), (92.6367, 39.6387), (92.373, 39.3311), (92.373, 39.1113), (92.373, 39.0234), (90.1758, 38.4961), (90.3516, 38.2324), (90.6152, 38.3203), (90.5273, 37.8369), (91.0547, 37.4414), (91.3184, 37.0898), (90.7031, 36.7822), (90.791, 36.6064), (91.0547, 36.5186), (91.0547, 36.0791), (90.8789, 36.0352), (90.0, 36.2549), (89.9121, 36.0791), (89.7363, 36.0791), (89.209, 36.2988), (88.7695, 36.3428), (88.5938, 36.4746), (87.3633, 36.4307), (86.2207, 36.167), (86.1328, 35.8594), (85.6055, 35.6836), (85.0781, 35.7275), (84.1992, 35.376), (83.1445, 35.4199), (82.8809, 35.6836), (82.4414, 35.7275), (82.002, 35.332), (81.6504, 35.2441), (80.4199, 35.4199), (80.2441, 35.2881), (80.332, 35.1563), (80.2441, 35.2002), (79.8926, 34.8047), (79.8047, 34.4971), (79.1016, 34.4531), (79.0137, 34.3213), (78.2227, 34.7168), (78.0469, 35.2441), (78.0469, 35.5078), (77.4316, 35.4639), (76.8164, 35.6396), (76.5527, 35.8594), (76.2012, 35.8154), (75.9375, 36.0352), (76.0254, 36.4746), (75.8496, 36.6943), (75.498, 36.7383), (75.4102, 36.958), (75.0586, 37.002), (74.8828, 36.9141), (74.7949, 37.0459), (74.5313, 37.0898), (74.5313, 37.2217), (74.8828, 37.2217), (75.1465, 37.4414), (74.8828, 37.5732), (74.9707, 37.749), (74.8828, 38.4521), (74.3555, 38.6719), (74.1797, 38.6719), (74.0918, 38.54), (73.8281, 38.584), (73.7402, 38.8477), (73.8281, 38.9795), (73.4766, 39.375), (73.916, 39.5068), (73.916, 39.6826), (73.8281, 39.7705), (74.0039, 40.0342), (74.8828, 40.3418), (74.7949, 40.5176), (75.2344, 40.4297), (75.5859, 40.6494), (75.7617, 40.2979), (76.377, 40.3857), (76.9043, 41.001), (77.6074, 41.001), (78.1348, 41.2207), (78.1348, 41.3965), (80.1563, 42.0557), (80.2441, 42.2754), (80.1563, 42.627), (80.2441, 42.8467), (80.5078, 42.8906), (80.4199, 43.0664), (80.7715, 43.1982), (80.4199, 44.165), (80.4199, 44.6045), (79.9805, 44.8242), (79.9805, 44.9561), (81.7383, 45.3955), (82.0898, 45.2197), (82.5293, 45.2197), (82.2656, 45.6592), (83.0566, 47.2412), (83.6719, 47.0215), (84.7266, 47.0215), (84.9023, 46.8896), (85.5176, 47.0654), (85.6934, 47.2852), (85.5176, 48.1201), (85.7813, 48.4277), (86.5723, 48.5596), (86.8359, 48.8232), (86.748, 48.9551), (86.8359, 49.1309), (87.8027, 49.1748), (87.8906, 48.999), (87.7148, 48.9111), (88.0664, 48.7354), (87.9785, 48.6035), (88.5059, 48.3838), (88.6816, 48.1641), (89.1211, 47.9883), (89.5605, 48.0322), (89.7363, 47.8564), (90.0879, 47.8564), (90.3516, 47.6807), (90.5273, 47.2412), (90.8789, 46.9775), (91.0547, 46.582), (90.8789, 46.3184), (91.0547, 46.0107), (90.7031, 45.7471), (90.7031, 45.5273), (90.8789, 45.2197), (91.582, 45.0879), (93.5156, 44.9561), (94.7461, 44.3408), (95.3613, 44.2969), (95.3613, 44.0332), (95.5371, 43.9014), (95.8887, 43.2422), (96.3281, 42.9346), (96.416, 42.7588)]]}, 'properties': OrderedDict([('Name', '新疆维吾尔自治区'), ('CenterX', 84.9023), ('CenterY', 42.148)])}

Shapefile数据读取

下面我们来体验一下Fiona的简洁之处,主要是使用Python内置的结构表示所有数据,所以使用Fiona操作空间数据就像操作Python内置的数据结构一样简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import fiona

with fiona.open('China.shp', encoding='utf-8') as c:
# 输出数据的基本信息
print(f'数据范围:{c.bounds}')
print(f'投影定义:{c.crs}')
print(f'数据格式:{c.driver}')
print(f'数据编码:{c.encoding}')
# 输出文件的属性字段信息
fields = c.schema['properties']
print('文件的属性字段信息:')
for k, v in fields.items():
print(f'{k} -> {v}')
# 遍历集合中的要素
# f是一个tuple,第一个元素是要素编号,第二个是dict格式的要素
for f in c.items():
# 输入要素的详细信息
# 要素是以GeoJSON表示的
print(f[1]['properties']['Name'])

特别需要注意数据的编码问题,要不然默认的编码会引起中文乱码,常见中文编码可能采用GBK或者UTF-8等。

输出结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
数据范围:(73.4766, 18.1055, 135.0879, 53.5693)
投影定义:{'init': 'epsg:4326'}
数据格式:ESRI Shapefile
数据编码:utf-8
文件的属性字段信息:
Name -> str:24
CenterX -> float:24.15
CenterY -> float:24.15
新疆维吾尔自治区
西藏自治区
内蒙古自治区
青海省
四川省
黑龙江省
甘肃省
云南省
广西壮族自治区
湖南省
陕西省
广东省
吉林省
河北省
湖北省
贵州省
山东省
江西省
河南省
辽宁省
山西省
安徽省
福建省
浙江省
江苏省
重庆市
宁夏回族自治区
海南省
台湾省
北京市
天津市
上海市
香港特别行政区
澳门特别行政区