小白学习cartopy画地图的第一天(中国行政区域图,含南海)
这是地图小白的我学习用cartopy画地图的第一天,慢慢摸索慢慢学习,一步一步学会使用cartopy。后面会持续更新。其中很多是从各个博主公众号中学习来的知识,难免雷同,在此先感谢(公众号:气象学家)
第一步是安装cartopy
这一步我不再说明了,作者也是尝试了很多方法,pip了半天,年轻人最后还是认怂了,建议大家安装方式为anaconda然后转化为国内镜像源安装,简直不要太简单,一条命令就够了,收起年轻人的那点小倔强,比如我。
这里强调一下地图包的问题,安装完cartopy后可以直接使用,但是自带地图包它会在使用的时候下载,这样很慢,所以作者建议提前找离线的下载好,放进正确的路径就好了,(离线地图包很多地方可以找到,要是没用,下方评论区留下你的百度网盘地址,作者发给你),地图存放位置为C:\Users\Administrator.local\share\cartopy\shapefiles\natural_earth\physical
作者也是找了很久才找到的。
第二步下载正确的中国行政区边界
老外坏得很,如果只用cartopy自带地图画国界,会发现很多边边角角是错的,所以需要下载咱们自己的行政区边界
网址是:*https://gmt-china.org/data/*下载里面的CN-border-La.dat,如果还有错误请及时告知作者,作者也是小白,立马删帖。文件也可以找作者要(下方评论区留下你的百度网盘地址,作者发给你)
第三步可以开始画图了
导入库
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
这一步就不讲了
读取CN-border-La.dat文件
with open('CN-border-La.dat') as src:context = src.read()blocks = [cnt for cnt in context.split('>') if len(cnt) > 0]borders = [np.fromstring(block, dtype=float, sep=' ') for block in blocks]
这一步是读取CN-border-La.da文件,目的是读取里面每个点的经纬度,用于给底图加上行政边界
设置画图参数
fig = plt.figure(figsize=[8, 8])
ax = plt.axes(projection=ccrs.LambertConformal(central_latitude=90,central_longitude=105))
这一步是设置画图参数,和matplotlib画图没区别,解释一下其中几个参数的含义,说白了就是利用兰伯特投影方式画地图
projection:投影
LambertConformal:兰伯特投影
central_latitude:中央纬度
central_longitude:中央经度
画海洋、陆地、河流、湖泊
ax.add_feature(cfeature.OCEAN.with_scale('50m'))
ax.add_feature(cfeature.LAND.with_scale('50m'))
ax.add_feature(cfeature.RIVERS.with_scale('50m'))
ax.add_feature(cfeature.LAKES.with_scale('50m'))
这里利用的是cartopy自带的地图,分辨率50米,大概就是这个意思,我猜的,嘿嘿,不影响画图,当你看到离线地图包的时候就会发现还有10m,和110m的,共三种。
画国界
for line in borders:ax.plot(line[0::2], line[1::2], '-', color='gray',transform=ccrs.Geodetic())
这里就用到了当时上面文件里面的坐标点了,其实就是用点画线,line[0::2]就是X,line[1::2]就是Y,就是用xy画平面图,这样解释是否理解,有兴趣的可以print()一下就明白了,一组是经度,一组是纬度。
画经纬度
ax.gridlines(linestyle='--')
其实就是画网格线
设置区域
ax.set_extent([80, 130, 13, 55])
咱们画出来的是世界地图,这个来框处要显示的区域,经度80-130,纬度13-55,事实发现不是很匹配,不过大致也差不多,框出来的就是咱大中国,南海还不够,下面讲
画南海
sub_ax = fig.add_axes([0.741, 0.11, 0.14, 0.155], projection=ccrs.LambertConformal(central_latitude=90,central_longitude=115))
sub_ax.add_feature(cfeature.OCEAN.with_scale('50m'))
sub_ax.add_feature(cfeature.LAND.with_scale('50m'))
sub_ax.add_feature(cfeature.RIVERS.with_scale('50m'))
sub_ax.add_feature(cfeature.LAKES.with_scale('50m'))
for line in borders:sub_ax.plot(line[0::2], line[1::2], '-', color='gray',transform=ccrs.Geodetic())
sub_ax.set_extent([105, 125, 0, 25])
画南海我就不赘述了,因为和上面方法一样,无非就是再加一个ax然后画
显示地图
plt.show()
这个不用解释了吧
完整代码
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature#读取CN-border-La.dat文件
with open('CN-border-La.dat') as src:context = src.read()blocks = [cnt for cnt in context.split('>') if len(cnt) > 0]borders = [np.fromstring(block, dtype=float, sep=' ') for block in blocks]
#设置画图各种参数
fig = plt.figure(figsize=[8, 8])
# 设置投影类型和经纬度
ax = plt.axes(projection=ccrs.LambertConformal(central_latitude=90,central_longitude=105))
# 画海,陆地,河流,湖泊
ax.add_feature(cfeature.OCEAN.with_scale('50m'))
ax.add_feature(cfeature.LAND.with_scale('50m'))
ax.add_feature(cfeature.RIVERS.with_scale('50m'))
ax.add_feature(cfeature.LAKES.with_scale('50m'))
# 画国界
for line in borders:ax.plot(line[0::2], line[1::2], '-', color='gray',transform=ccrs.Geodetic())
# 画经纬度网格
ax.gridlines(linestyle='--')
# 框出区域
ax.set_extent([80, 130, 13, 55])
# 画南海,这一步是新建一个ax,设置投影
sub_ax = fig.add_axes([0.741, 0.11, 0.14, 0.155],projection=ccrs.LambertConformal(central_latitude=90,central_longitude=115))
# 画海,陆地,河流,湖泊
sub_ax.add_feature(cfeature.OCEAN.with_scale('50m'))
sub_ax.add_feature(cfeature.LAND.with_scale('50m'))
sub_ax.add_feature(cfeature.RIVERS.with_scale('50m'))
sub_ax.add_feature(cfeature.LAKES.with_scale('50m'))
# 画边界
for line in borders:sub_ax.plot(line[0::2], line[1::2], '-', color='gray',transform=ccrs.Geodetic())
# 框区域
sub_ax.set_extent([105, 125, 0, 25])
# 显示
plt.show()