Bootstrap

小白学习cartopy画地图的第一天(中国行政区域图,含南海)

小白学习cartopy画地图的第一天(中国行政区域图,含南海)

这是地图小白的我学习用cartopy画地图的第一天,慢慢摸索慢慢学习,一步一步学会使用cartopy。后面会持续更新。其中很多是从各个博主公众号中学习来的知识,难免雷同,在此先感谢(公众号:气象学家)
CN-border-La.dat可以在作者主页下载,自己找找
在这里插入图片描述

第一步是安装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()

最后如果地图有错请各位仁兄一定要告诉我

;