先看下面三张图:
如果不仔细看,大家会觉得几乎是一模一样的……起码从风格上看,是一样的。
上面三张图,左边是从百度地图网站上直接截取的图片,而右边是用Python直接绘制出来的数据。
可以明显的看出来,右边地图的数据不如左边那么完善……穷人虾获取不到最新版本的数据所以只能用十几年前的老数据来应付一下了。
好了,回归正题。
用Python来绘制地图,来源于虾神和我司某个封疆大吏的闲聊,说如果要用Python写个GIS软件,使用者除了数据处理以外,突然想要搞高级制图怎么办?所以就有了今天的这个构思。
Python拥有强大的可视化能力,这是毋庸置疑的,而地图做为可视化的巅峰,能在地图上绘制出什么效果,大部分人都心里没底的。
平时如果直接用Python对地图进行可视化,平时更多使用Python自带的一些包,比如geopandas,比如Cartopy这种比较成熟专业地图包:
但是如果要进行更精细化制图,比如需要定制百度地图这种风格的,是不是可行呢?就那天我们就通过Python来进行一个定制。
实际上用matplotlib和geopandas用得好的同学,看一眼就知道怎么做了,无非就是对点线面进行可视化而且,唯一稍微有点点技术含量的,就以下三个细节内容:
1、标注的掩膜晕圈效果,即标注的“北京”两个字旁边那一圈白边:
2、高速路牌标注的背景符号,即下面G4501的后面红头绿底的背景:
3、机场、车站、公园等POI点的点状标识:
掌握了这三个细节,制作这个地图,就没有啥技术难度了。下面我们来一一解析。
1、字体晕圈掩膜:
在ArcMap里面,可以通过标注类似设置:
而在matplotlib里面,这个功能则可以通过matplotlib.patheffects类来实现:
在text方法里面,直接通过path_effects属性,来设置,就可以得到这个效果了:
代码和效果如下:
#设置标注字体为微软雅黑
from matplotlib import font_manager as fm
prop = fm.FontProperties('SimHei')
# 设置字体晕圈掩膜,透明度为0.5
plt.text(0.5,0.5,"晕圈掩膜效果_绿色",weight='bold',fnotallow={'size':15},
fnotallow=prop,
path_effects=[pe.withStroke(linewidth=6, foreground="green")],
alpha=0.5)
plt.text(0.1,0.1,"晕圈掩膜效果_红色",weight='bold',fnotallow={'size':15},
fnotallow=prop,
path_effects=[pe.withStroke(linewidth=6, foreground="red")],
alpha=0.5)
2、高速公路的路标背景
这个实现就更简单了,直接绘制两个矩形,如下:
fig,ax = plt.subplots(figsize=(6,4))
rect=plt.Rectangle((0.2,0.4), 0.5, 0.3, color='#ec635e', alpha=1,zorder=10)
rect2=plt.Rectangle((0.2,0.4), 0.5, 0.25, color='#50d3ba', alpha=1,zorder=20)
ax.add_patch(rect)
ax.add_patch(rect2)
ax.text(0.21,0.41,"G4501",fnotallow={'size':65,"color":"white"},
fnotallow=prop,zorder=30)
注意点如下:
合并的时候有两种方法,一种是完全不浪费的方法,用头和底拼接起来,第二种就是绘制一大一小两个,然后叠加起来,效果是完全一样的。
但是第二种叠加的方式,因为用的是同一个中心,所以省去了计算拼接的功夫,更省事。
用第二种叠加的方式,注意zorder这个参数,这个参数控制的是显示顺序的问题,数值越大,优先级越高。
3、POI标注
这个说简单也很简单,你只需要去找个png图片贴上去就行,但是问题来了,如果你和虾神一样,是个完全不会作图的美术盲,怎么办?完全找不到合适的图标啊。
这样就涉及到图标叠加的问题了,比如我这里的首都机场的标注,是通过两个图片叠加出来的:
实现方式如下:
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
b = plt.imread("image/BluePin2LargeB.png",format='png')
f = plt.imread("image/aa.png",format='png')
fig,ax = plt.subplots(figsize=(4,4))
b2 = AnnotationBbox(OffsetImage(b, zoom=2.1),(0.5,0.5),framenotallow=False)
f2 = AnnotationBbox(OffsetImage(f, zoom=0.6,alpha=1),(0.5,0.5),framenotallow=False)
ax.add_artist(b2)
ax.add_artist(f2)
plt.show()
掌握这个细节技术,就可以制作出下面百度风格的专题图了:
源码如下:
源代码和数据都在虾神的gitee代码库中,地址如下:
https://gitee.com/godxia/python_map_visualization
006百度风格北京地图
打完收工。