本文对应代码已上传至个人
Github
仓库https://github.com/CNFeffery/DataScienceStudyNotespython
geopandas是创建在GEOS、GDAL、PROJ等开源地理空间计算相关框架之上的,相似pandas
语法风格的空间数据分析Python
库,其目标是尽量地简化Python
中的地理空间数据处理,减小对Arcgis
、PostGIS
等工具的依赖,使得处理地理空间数据变得更加高效简洁,打造纯Python
式的空间数据处理工做流。本系列文章就将围绕geopandas
及其使用过程当中涉及到的其余包进行系统性的介绍说明,每一篇将尽量全面具体地介绍geopandas
对应方面的知识,计划涵盖geopandas
的数据结构、投影坐标系管理、文件IO、基础地图制做、集合操做、空间链接与聚合。
做为基于geopandas的空间数据分析系列文章的第一篇,经过本文你将会学习到geopandas
中的数据结构。
geopandas
的安装和使用须要若干依赖包,若是不事先妥善安装好这些依赖包而直接使用pip install geopandas
或conda install geopandas
可能会引起依赖包相关错误致使安装失败,官方文档中的推荐安装方式为:git
conda install --channel conda-forge geopandas
conda-forge
是一个社区项目,在conda
的基础上提供了更普遍更丰富的软件资源包,经过它咱们能够自动下载安装好全部geopandas
的必要依赖包而无需手动繁琐地去安装它们。在完成安装后,下面咱们开始对geopandas
的系统性学习之旅。github
geopandas
做为pandas
向地理分析计算方面的延拓,基础的数据结构延续了Series
和DataFrame
的特色,创造出GeoSeries
与GeoDataFrame
两种基础数据结构:shell
与Series
类似,GeoSeries
用来表示一维向量,只不过这里的向量每一个位置上的元素都表示着一个shapely
中的几何对象,有以下几种类型:数据结构
shapely.geometry
中的Point
,用于表示单个点,下面咱们建立一个由若干Point
对象组成的GeoSeries
并像Series
同样定义索引:from shapely import geometry import geopandas as gpd # 建立存放Point对象的GeoSeries # 这里shapely.geometry.Point(x, y)用于建立单个点对象 gpd.GeoSeries([geometry.Point(0, 0), geometry.Point(0, 1), geometry.Point(1, 1), geometry.Point(1, 0)], index=['a', 'b', 'c', 'd'])
能够看到建立出的GeoSeries
数据类型为geometry,即几何对象。框架
shapely
中的MultiPoint
,用于表示多个点的集合,下面咱们建立一个由若干MultiPoint
对象组成的GeoSeries
:# 建立存放MultiPoint对象的GeoSeries # 这里shapely.geometry.MultiPoint([(x1, y1), (x2, y2), ...])用于建立多点集合 gpd.GeoSeries([geometry.MultiPoint([(0, 1), (1, 0)]), geometry.MultiPoint([(0, 0), (1, 1)])], index=['a', 'b'])
在jupyter notebook
或jupyter lab
中能够图像的形式直接显示GeoSeries
中的单个元素:
dom
shapely
中的LineString
,用于表示由多个点按顺序链接而成的线,下面咱们建立一个由若干LineString
对象组成的GeoSeries
:# 建立存放LineString对象的GeoSeries # 这里shapely.geometry.LineString([(x1, y1), (x2, y2), ...])用于建立多点按顺序链接而成的线段 gpd.GeoSeries([geometry.LineString([(0, 0), (1, 1), (1, 0)]), geometry.LineString([(0, 0), (0, 1), (-1, 0)])], index=['a', 'b'])
一样地,直接显示第一个元素:
工具
shapely
中的MultiLineString
,用于表示多条线段的集合,下面咱们建立一个由若干MultiLineString
对象组成的GeoSeries
:# 建立存放MultiLineString对象的GeoSeries # 这里shapely.geometry.MultiLineString([LineString1, LineString2])用于建立多条线段的集合 gpd.GeoSeries([geometry.MultiLineString([[(0, 0), (1, 1), (1, 0)], [(-0.5, 0), (0, 1), (-1, 0)]])], index=['a'])
一样地,直接显示第一个元素:
学习
geopandas
中的Polygon
对应shapely
中的Polygon
,用于表示面,根据内部有无孔洞可继续细分。下面咱们建立一个由无孔Polygon
对象组成的GeoSeries
:# 建立存放无孔Polygon对象的GeoSeries # 这里shapely.geometry.Polygon([(x1, y1), (x2, y2),...])用于建立无孔面 gpd.GeoSeries([geometry.Polygon([(0, 0), (0, 1), (1, 1), (1, 0)])], index=['a'])
一样地,直接显示第一个元素:
3d
无孔Polygon
,下面咱们建立一个由有孔Polygon
对象组成的GeoSeries
:# 建立存放有孔Polygon对象的GeoSeries # 这里shapely.geometry.Polygon(polygonExteriors, interiorCoords)用于建立有孔面 # 其中polygonExteriors用于定义整个有孔Polygon的外围,是一个无孔的多边形 # interiorCoords是用于定义内部每一个孔洞(本质上是独立的多边形)的序列 gpd.GeoSeries([geometry.Polygon([(0,0),(10,0),(10,10),(0,10)], [((1,3),(5,3),(5,1),(1,1)), ((9,9),(9,8),(8,8),(8,9))])])
一样地,直接显示第一个元素:
shapely
中的MultiPolygon
,用于表示多个面的集合,下面咱们建立一个由MultiPolygon
对象组成的GeoSeries
:# 建立存放MultiPolygon对象的GeoSeries # 这里shapely.geometry.MultiPolygon([Polygon1, Polygon2])用于建立多个面的集合 gpd.GeoSeries([geometry.MultiPolygon([geometry.Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)]), geometry.Polygon([(2, 2), (2, 3), (3, 3), (3, 2), (2, 2)])])], index=['a'])
显示第一个元素:
LinearRing
对应shapely.geometry
中的LinearRing
,是一种特殊的几何对象,能够理解为闭合的线或无孔多边形的边框,建立时传入数据的格式与Polygon
相同,下面咱们建立一个由LinearRing
对象组成的GeoSeries
:# 建立存放LinearRing对象的GeoSeries # 这里shapely.geometry.LinearRing([(x1, y1), (x2, y2),...])用于建立LinearRing gpd.GeoSeries([geometry.LinearRing([(0, 0), (0, 1), (1, 1), (1, 0)])], index=['a'])
显示第一个元素,能够看出LinearRing
就是无孔多边形的边框线:
在同一个
GeoSeries
能够混合上述类型中的多种几何对象,这意味着点线面在概念上相异的几何对象能够共存于同一份数据中
相似pandas
中的Series
,GeoSeries
在被建立完成以后也拥有不少实用的地理属性,下面对其中较为经常使用的进行列举:
area
属性返回与GeoSeries
中每一个元素一一对应的面积值(这里的面积单位和下文涉及的长度单位取决于投影坐标系,以后关于geopandas
投影坐标系管理的文章将会详细介绍,这里仅作演示):# 建立混合点线面的GeoSeries,这里第5个有孔多边形内部空洞建立时使用[::-1]颠倒顺序 # 是由于GeoSeries.plot()方法绘制有孔多边形的一个bug,即外部边框与内部孔洞建立时坐标 # 方向同为顺时针或顺时针时内部孔洞会自动被填充,若是你对这个bug感兴趣,能够前往 # https://github.com/geopandas/geopandas/issues/951查看细节 s = gpd.GeoSeries([geometry.Polygon([(0, 0), (0.5, 0.5), (1, 0), (0.5, -0.5)]), geometry.Polygon([(1, 1), (1.5, 1.5), (2, 1), (1.5, -1.5)]), geometry.Point(3, 3), geometry.LineString([(2, 2), (0, 3)]), geometry.Polygon([(4, 4), (8, 4), (8, 8), (4, 8)], [[(5, 5), (7, 5), (7, 7), (5, 7)][::-1]])]) # 在jupyter中开启matplotlib交互式绘图模式 %matplotlib widget s.plot() # 对s进行简单的可视化
能够看到,s
中包含了多种几何对象,下面直接获得s
的面积:
bounds
bounds
属性返回每一个几何对象所在box左下角、右上角的坐标信息:
length
length
属性返回每一个几何对象边长:
geom_type
geom_type
返回每一个几何对象类型:
exterior与interiors
对于多边形对象,exterior
返回LinearRing
格式的外边框线,对于有孔多边形,interiors
返回全部内部孔洞LinearRing
格式边框线集合:
shapely
中涉及到不少拓扑计算操做时,对几何对象的合法性有要求,譬如定义多边形时坐标按顺序连线时穿过了以前定义的边就属于非法,由于geopandas
对矢量对象的计算依赖于shapely
,因而引进了属性用于判断每一个几何对象是否合法,下面咱们建立两个形状相同的多边形,其中一个知足上述所说的非法状况,另外一个由两个多边形拼接而成:s_ = gpd.GeoSeries([geometry.Polygon([(4, 0), (6, 1), (4, 1), (6, 0)]), geometry.MultiPolygon([geometry.Polygon([(4, 0), (5, 0.5), (6, 0)]), geometry.Polygon([(5, 0.5), (6, 1), (4, 1)])])])
从形状上看二者相同:
shapely
中的
intersection
方法来取得这两个几何对象的相交部分,出现了拓扑逻辑错误:
s_.is_valid
,能够看出第一个自相交的多边形非法:
boundary
boundary
返回每一个几何对象的低维简化表示(点对象无具体的更低维简化,故无返回值):
centroid
centroid
返回每一个几何对象的重心(几何中心):
convex_hull
返回每一个几何对象的凸包,Polygon
格式,即恰巧包含对应几何对象的凸多边形:import numpy as np # 利用独立的正态分布随机数建立两个MultiPoint集合 s__ = gpd.GeoSeries([geometry.MultiPoint(np.random.normal(loc=0, scale=2, size=[10, 2]).tolist()), geometry.MultiPoint(np.random.normal(loc=5, scale=2, size=[10, 2]).tolist())]) ax = s__.plot(color='red') # 绘制s__ s__.convex_hull.plot(ax=ax, alpha=0.4) # 叠加绘制各自对应凸包,调低填充透明度以显示更明显
envelope
属性返回对应几何对象的box范围,Polygon
格式,即包含对应元素中全部点的最小矩形:import numpy as np # 建立两团独立的MultiPoint s__ = gpd.GeoSeries([geometry.MultiPoint(np.random.normal(loc=0, scale=2, size=[10, 2]).tolist()), geometry.MultiPoint(np.random.normal(loc=5, scale=2, size=[10, 2]).tolist())]) ax = s__.plot(color='red') # 绘制s__ s__.envelope.plot(ax=ax, alpha=0.4) # 叠加绘制各自对应envelope,调低填充透明度以显示更明显
顾名思义,geopandas
中的GeoDataFrame
是在pandas.DataFrame
的基础上,加入空间分析相关内容进行改造而成,其最大特色在于其在原有数据表格基础上增长了一列GeoSeries
使得其具备矢量性,全部对于GeoDataFrame
施加的空间几何操做也都做用在这列指定的几何对象之上。下面咱们举个简单的例子,基于不一样均值和标准差的正态分布随机数,建立GeoDataFrame
来记录这些信息:
contents = [(loc, 0.5) for loc in range(0, 10, 2)] geo_df = gpd.GeoDataFrame(data=contents, geometry=[geometry.MultiPoint(np.random.normal(loc=loc, scale=scale, size=[10, 2]).tolist()) for loc, scale in contents], columns=['均值', '标准差']) geo_df
其中定义GeoDataFrame
时做为每行所关联几何对象的GeoSeries
须要经过geometry
参数指定,而除了用上述的方式建立GeoDataFrame
,先建立数据表,再添加矢量信息列亦可,这时几何对象列的名称能够自由设置,但必定要利用GeoDataFrame.set_geometry()
方法将后添加的矢量列指定为矢量主列,由于每一个GeoDataFrame
若在定义之处没有指定矢量列,后将没法进行与适量信息挂钩的全部操做(GeoSeries
全部属性均可一样做用于GeoDataFrame
,由于全部空间操做实际上都直接做用于其矢量主列):
geo_df = gpd.GeoDataFrame(contents, columns=['均值', '标准差']) geo_df['raw_points'] = [geometry.MultiPoint(np.random.normal(loc=loc, scale=scale, size=[10, 2]).tolist()) for loc, scale in contents] # 尝试查看矢量类型 geo_df.geom_type
这时全部直接针对GeoDataFrame
的矢量相关操做都没法使用。
GeoDataFrame
指定矢量列geo_df.set_geometry('raw_points').geom_type
这时相关操做可正常使用:
GeoDataFrame
都有一个矢量主列,相关操做例如绘图都基于此列,实际上GeoDataFrame
容许表中存在多个矢量列,只要求任意时刻有且仅有1列为矢量主列便可,所以咱们能够在一个GeoDataFrame
中保存多列矢量,须要用到哪列时再进行切换便可,以下面的例子:geo_df = gpd.GeoDataFrame(contents, columns=['均值', '标准差']) geo_df['raw_points'] = [geometry.MultiPoint(np.random.normal(loc=loc, scale=scale, size=[10, 2]).tolist()) for loc, scale in contents] geo_df.set_geometry('raw_points', inplace=True) # inplace=True表示对原数据进行更新 # 绘制第一图层 ax = geo_df.plot(color='red') geo_df['convex_hull'] = geo_df.convex_hull # 切换矢量主列 geo_df.set_geometry('convex_hull', inplace=True) # 绘制第二图层 geo_df.plot(ax=ax, color='blue', alpha=0.4)
做为pandas.DataFrame
的延伸,GeoDataFrame
一样支持pandas.DataFrame
中的.loc
以及.iloc
对数据在行、列尺度上进行索引和筛选,这里咱们以geopandas
自带的世界地图数据为例:
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) world.plot()
查看其表格内容:
.loc
+条件筛选选择数据:
.iloc
选择数据:
geopandas
为
GeoDataFrame
添加了
.cx
索引方式,能够传入所需的空间范围,用于索引与传入范围相交的对应数据:
# 选择与东经80度-110度,北纬0度-30度范围相交的几何对象 part_world = world.cx[80:110, 0:30] # 绘制第一图层:世界地图 ax = world.plot(alpha=0.05) # 绘制第二图层:.cx所选择的地区 ax = part_world.plot(ax=ax, alpha=0.6) # 绘制第三图层:.cx条件示意图 ax = gpd.GeoSeries([geometry.box(minx=80, miny=0, maxx=110, maxy=30).boundary])\ .plot(ax=ax, color='red')
示意图以下:
.cx
,全部与指定空间范围有重叠的对象都被选择:
以上就是本文的所有内容,若有笔误望指出,系列文章下一篇将详细介绍geopandas
中的投影坐标系管理,敬请期待。