python画指北针_python如何画出漂亮的地图?

python如何画出漂亮的地图?

要画一张好看的地图,数据量的多少、底图的支持程度与选择乃至个人的美学素养是一张好看的地图重要的因素。目前python也有很多能够实现地图可视化的包,这里给大家推荐最基础也是个人最常使用的两个包geopandas配合contextily来进行地理信息的可视化。

后面将涉及各种类型图形的介绍,代码数量可能会较多,但都是非常简单的代码块,一定要坚持看下去哦!

1 geopandas数据的导入

geopandas与大名鼎鼎的pandas库有异曲同工之妙,甚至我们可以说geopandas就是地理信息领域的pandas。准确说,geopandas是将地理信息记录在数据表中,并可以通过一系列的绘图库进行显示,和arcmap中的属性表非常类似。

目前geopandas支持读取shp、geojson,和pandas一样只需要一行代码就可以导入:

Taiwan = gpd.read_file("/Users/creative/Documents/python/geopandas/data/Taiwan_shp/gadm36_TWN_0.shp")

如果你是已经整理好的经纬度坐标表格,也可以通过简单的几行代码将其转换为geodataframe的格式:

df = pd.read_excel(data_path) #先利用pandas导入

gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.lng, df.lat)) #转换为geodataframe

gdf.crs = 'EPSG:4326' #设置坐标系

值得一提的是,如果你对python中关于openstreetmap数据下载的osmnx库有一定的了解,你也可以直接从openstreetmap中下载街道网络数据或者行政边界数据转化为geodataframe格式,形成一个从数据下载到数据可视化的闭环。

import osmnx as ox

import geopandas as gpd

"""下载城市边界"""

city = ox.geocode_to_gdf('india')

"""基于范围下载路网"""

G = ox.graph_from_bbox(22.5229, 22.5178, 113.9265, 113.9360, network_type='drive')

G_projected = ox.project_graph(G)

"""保存为geodataframe"""

nodes, edges = ox.graph_to_gdfs(G_projected)

2 利用geopandas和contextily绘图

数据导入之后,我们就可以进入正题了,如何画出一张漂亮的地图。

2.1 最简单的绘图

在geopandas中只需要一行代码就可以将图像进行可视化(不过在此之前要设置好你的参考坐标系),如果你想可视化台湾的行政边界,只需要输入以下的代码就可以轻松实现

Taiwan.to_crs("EPSG:3857").plot()

2.2 进行数据可视化

数据可视化是检验一个好的绘图库的基本标准,以下本文将使用台湾省的军事设施数据进行简单的数据可视化。

以下图标数据来源openstreetmap中关于台湾省的土地利用数据,不代表本人观点。

基础地图和数据来自 OpenStreetMap 和 OpenStreetMap 基金会

首先,我们先将所有的数据在地图上进行描绘:

fig = plt.figure(figsize=(15,15),dpi=300)

ax = fig.add_subplot(1,1,1)

Taiwan.boundary.to_crs("EPSG:3857").plot(ax=ax, edgecolor='k',linewidth=1, zorder=2)

city.boundary.to_crs("EPSG:3857").plot(ax=ax,edgecolor='gray',linewidth=0.8,zorder=1)

for idx, _ in enumerate(city.geometry.representative_point().to_crs(3857)):

region = city.loc[idx, 'NL_NAME_2']

ax.text(_.x, _.y, region, ha="center", va="center", size=6,color='k')

military_point.to_crs("EPSG:3857").plot(column='type', cmap='YlGn',markersize=5,edgecolor='k',linewidth=0.3, ax=ax, legend=True,legend_kwds={'loc': 8,"title":"图例","shadow":True,"ncol":5}, zorder=3)

ctx.add_basemap(ax, source='https://d.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png',zoom=8)

image

从图中我们似乎可以认为台湾省大量军事设施布置在台湾海峡一侧,但是这只是我们肉眼可见的数据,从地理信息数据处理的角度来看,我们还需要将其数量赋值到台湾省每一个市中才能更加清晰的进行分析。

这个时候geopandas像arcmap一样给我们提供了空间连接功能,只需要几行代码就可以快速的进行空间连接:

sjoin = gpd.sjoin(city,military_point) #括号内填入要空间连接的geodataframe

这个时候我们点的信息就赋予到了我们的面上面,我们只需要进行一下简单的汇总统计就可以实现对每一个市的军事设施数量进行统计

sjoin = sjoin["NL_NAME_2"].value_counts().reset_index() #汇总统计

sjoin = sjoin.rename(columns={"NL_NAME_2":"military_count","index":"NL_NAME_2"})

count_city = city.merge(sjoin, on='NL_NAME_2') #再次连接属性表

count_city.head(1)

image

其中military_count就是我们计算的结果,接着我们把结果可视化到我们的地图中(后文代码部分就差不多了,这里将不加入代码块了):

image

定量可视化后我们可以更清晰的发现,台湾省军事设施主要分布在台北市周边地图、台中、高雄、花莲等地,并不是单一部署在台湾海峡一岸。我们在统计数据的时候还发现这套数据也包括机场和军事基地等设施,那么我们就可以思考,如果从这些基地出发,台湾最大的军事覆盖范围将有多大呢?

geopandas的buffer功能为我们这个想法提供了支撑,我们假设台湾省目前的F16b的基本作战半径为700公里,最大作战半径为1300公里,来观察这个作战半径可以覆盖的区域。

image

根据结果我们可以发现在台湾省1300公里半径内可以到达广东省的深圳市和上海市区,而在700公里则可以覆盖东南沿海的一些城市。

然而,真实的情况是它可能连台湾海峡都飞不过。。。。。

利用buffer功能,在城市规划领域我们可以划定一些公共服务设施的服务半径,这里我们也简单绘制了一张台湾军事电台可以覆盖的一些范围(假定服务半径为20000m)

image

在对军事设施进行简单的分析后,我们也可以关注台湾省的社会经济信息,如灯光地图就常常被用来衡量城市的繁荣程度与城市夜经济的发达程度,利用contextily库我们可以轻松的把灯光地图和我们的geodataframe结合起来进行分析与研究。

image

地形图与卫星影像地图也常常是我们分析的重点,我们在使用gis时常常为这种数据的获取而感到头痛,但是在geopandas里,你依旧只需要几行代码就可以轻松的实现这些数据的操作与分析,为了图像好看,我们将这几张地图放到一起来进行可视化。

image

geopandas也支持绘制热力地图等操作(这里偷懒放了官网的图)

image

image

image

image

除了区域层面的分析外,对于微观层面的分析,geopandas也不在话下,比如下面这张商业店铺的分析图从数据的获取到可视化就完成依靠python完成。

image

image

还有一些关于子图等等的操作本文没有进行介绍,以后有时间补上。

3 geopandas的不足

作为强大的python中的地理信息处理库,geopandas也支持如同arcmap中的某些功能,同时和osmnx、shapely等库配合进行更加强大的地理处理。

但是geopandas与arcmap相比依旧有较大的差距,比如说目前不支持比例尺和指北针的绘制。对一些高级的地理处理功能也没有办法进行。如果需要进行专业的研究,我们还是离不开arcgis的帮助。

本文主要提供了一种与传统地理数据处理不同的思路,希望对大家有所帮助!

你可能感兴趣的:(python画指北针)