基于Python的地理空间分析(二):PostgreSQL,PostGIS与Python

地理空间数据库介绍

基本概念

虽然早早就听说了GIS,但是对于地理学、GIS的基本概念还是需要认真学习。

地理空间数据(geospatial data),是指带有地理坐标的数据,包括资源、环境、经济和社会等领域的一切带有地理坐标的数据,按照表示方法的不同,可以分为地图数据和地理信息数据。地理信息数据的获取、处理、管理和分析及其在地学领域的应用催生了地理信息系统。

地理信息系统(geographic information system, GIS),是利用计算机及其外部设备,采集、存储、分析和描述整个或部分地球表面的空间信息系统,他的研究对象是整个地理空间,为人们采用数字形式分析现实空间世界提供了一系列空间操作和分析方法。其核心是地理信息数据库。

地理空间数据库(geospatial database, GDB)的主要任务是研究地理空间物体的数据表示、数据模型以及在计算机内数据存储结构和建立空间索引方法,数据库系统的核心软件是地理空间数据库管理系统(GDBMS)。常见的空间书库管理系统包括Oracle Spatial, DB2 Spatial Extender,SQL Server Spatial, MySQL Spatial和Post GIS等,其中Post GIS可以说是OGC标准规范的最佳实现。

PostgreSQL与PostGIS介绍

我对数据库的了解还停留在本科上课学的那点东西,对PostgreSQL的性能、优劣势和使用场景并不了解。根据维基百科的介绍,PostgreSQL的开发历史已经超过30年,目前最新的版本是PostgreSQL 11。1(2018年12月),作为一种关系型数据库,PostgreSQL具有优异的性能,其商业化相对MySQL稍显落后。PostgreSQL是目前开源空间信息软件领域性能最优的数据库,构建在其上的空间对象扩展模块PostGIS使其成为一个真正的大型空间数据库。

postgreSQL_dbengine

同样根据维基百科的介绍,PostGIS是一个开源GIS,为PostgreSQL提供了存储空间地理数据的支持,使PostgreSQl成为了一个空间数据库,能够进行空间数据管理、数量测量与几何拓扑分析。PostGIS 实现了Open Geospatial Consortium所提出的基本要素类(点、线、面、多点、多线、多面等)的SQL实现参考。PostGIS使用well-known text与well-known binary在数据库中存储空间对象,前者是一种用文本表示空间对象的注记方法,后者是一种用二进制流表示空间对象的存储方法。

PostGIS是一个重要的GIS基础软件,因为当前它是为数不多的开源空间数据库存储方案之一。有许多著名的GIS软件都使用PostGIS作为数据库后端,其中包括GRASS GIS、ArcGIS等。

PostgreSQL,PostGIS和Python配置

安装PostgreSQL和PostGIS

PostgreSQL和PostGIS提供Winodws/Mac/Linux多个平台的程序,Windows为例,在PostgreSQL的官网上,有两个版本的安装包,一个是由EnterpriseDB提供的,一个是由BigSQL提供的。在安装的时候选择EDB提供的版本(我试着安装BigSQL)提供的版本,但是安装出现了错误。

在安装的过程中选择安装StackBuilder,然后可以用StackBuilder完成PostGIS的安装。

安装psycopg2

poscopg2对官方提供的libpq库进行了封装,是Python中管理PostgreSQL数据库最流行的库。安装与其他包一样,可以采用pip也可以采用conda。

Python管理PostgreSQL/PostGIS

首先要在PostGIS里创建一个数据库(可以在安装的时候就完成),采用命令行工具,具体命令如下:

createdb -U postgres pythonspatial
psql -U postgres -d pythonspatial -c "CREATE EXTENSION postgis;"

然后,就可以在Python中连接刚才创建的数据库,并创建一个叫做"art_pieces"的数据表,用cursor.execute()命令可以构造SQL的查询命令, commit()命令用来确保操作执行,示例如下:

1
2
3
4
5
6
7
import psycopg2


connection = psycopg2.connect(database="pythonspatial",user="postgres", password="123456")
cursor = connection.cursor()
#cursor.execute("CREATE TABLE art_pieces (id SERIAL PRIMARY KEY, code VARCHAR(255), location GEOMETRY)")
connection.commit()

在《Mastering geospatial analysis with Python》书中,提供了一个可以查询地理空间数据的网站作为例子(新墨西哥州的阿尔伯克基,头一次听说),这个网站还需要代理才能访问。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests



proxies = {
"http": "socks5://127.0.0.1:13579",
'https': 'socks5://127.0.0.1:13579'
}

url = ('http://coagisweb.cabq.gov/arcgis/rest/services'
'/public/PublicArt/MapServer/0/query')
params = {"where":"1=1","outFields":"*","outSR":"4326","f":"json"}
r = requests.get(url,params=params, proxies=proxies)
data = r.json()
print(data["features"][0])
{'attributes': {'OBJECTID': 1249669, 'ART_CODE': '101', 'TITLE': 'Almond Blossom/Astronomy', 'TYPE': 'public sculpture', 'YEAR': '1986', 'ARTIST': 'David Anderson', 'ADDRESS': '4440 Osuna NE', 'LOCATION': 'Osuna Median bet.Jefferson/ W.Frontage Rd', 'X': -106.5918383, 'Y': 35.1555, 'IMAGE_URL': 'http://www.flickr.com/photos/abqpublicart/6831137393/', 'JPG_URL': 'http://farm8.staticflickr.com/7153/6831137393_fa38634fd7_m.jpg'}, 'geometry': {'x': -106.59183830022498, 'y': 35.155500000061544}}

解析json数据,然后构造成well-know text(WKT)表示的空间数据,就可以迭代地将数据逐条插入数据库中。

1
2
3
4
5
6
7
8
9
for a in data["features"]:
code = a["attributes"]["ART_CODE"]
wkt="POINT("+str(a["geometry"]["x"])+" "+str(a["geometry"]["y"])+")"
if a["geometry"]["x"]=='NaN':
pass
else:
cursor.execute("INSERT INTO art_pieces (code, location) "
"VALUES ({},ST_GeomFromText('{}'))".format(code, wkt))
connection.commit()

如果不需要继续使用,记得要关闭数据库的连接:

1
connection.close()