[Python] python绘图 | 中国地图最正确的使用方式(九段线;南海子图

[复制链接]

前言

5 G6 c6 E3 _1 u+ y# m0 j

海洋、气象、地球科学相关的分析必然少不了地图的可视化。Python中我常用的绘制地图和空间信息分析的库是Cartopy。

Cartopy有一个非常严重的问题,那就是自带的中国国界数据有问题,这也是很多国外开源库的普遍问题。在做中国区域的分析时,由于九段线的位置很偏南,因此最标准的做法是同时绘制南海区域的子图。在做一些站点展示的时候,如果只单独画上几个站点总觉得很丑,可以加上一些地形背景。

综上,今天想要用一个小例子解决这3个问题:

  • 正确的中国国界线及九段线绘制

  • 南海小地图绘制

  • 全球地形图添加


    + p4 g# S3 v9 Z3 W
准备工作
  • 获取正确的中国矢量文件:公众号后台留言“中国行政区划”5 r- [! f4 r, ?7 l9 P: ]+ h, F" p% `
    (这个矢量文件来自资源环境平台,并和权威机构的标准地图做了比对,吻合一致。)

  • 获取全球地形图像:公众号后台留言“全球地形”; G+ u2 ^. ?7 f3 E, w
    (提供的是全球50m分辨率的tif图,如果对分辨率要求不高可以直接使用stock_img())


    0 e' T5 @! Z$ _+ `- {$ G( o( q  ~
代码
[Python] 纯文本查看 复制代码
# -*- coding: utf-8 -*-
importnumpy asnp
importpandas aspd
importcartopy
importcartopy.crs asccrs
importcartopy.feature ascfeat
fromcartopy.mpl.gridliner importLONGITUDE_FORMATTER, LATITUDE_FORMATTER
fromcartopy.io.shapereader importReader, natural_earth
importmatplotlib.pyplot asplt
importmatplotlib.ticker asmticker
frommatplotlib.image importimread
defcreate_map():
shp_path = './cn_shp/Province_9/'
# --创建画图空间
proj = ccrs.PlateCarree()  # 创建坐标系
fig = plt.figure(figsize=(6, 8), dpi=400)  # 创建页面
ax = fig.subplots(1, 1, subplot_kw={'projection': proj})  
# --设置地图属性
provinces = cfeat.ShapelyFeature(
Reader(shp_path + 'Province_9.shp').geometries(),
proj, edgecolor='k',
facecolor='none'
)
# 加载省界线
ax.add_feature(provinces, linewidth=0.6, zorder=2)
# 加载分辨率为50的海岸线
ax.add_feature(cfeat.COASTLINE.with_scale('50m'), linewidth=0.6, zorder=10)
# 加载分辨率为50的河流~
ax.add_feature(cfeat.RIVERS.with_scale('50m'), zorder=10)
# 加载分辨率为50的湖泊
ax.add_feature(cfeat.LAKES.with_scale('50m'), zorder=10)
ax.set_extent([105, 133, 15, 45])
# ax.stock_img()
ax.imshow(
imread('./NE1_50M_SR_W.tif'),
origin='upper',
transform=proj,
extent=[-180, 180, -90, 90]
)
# --设置网格点属性
gl = ax.gridlines(
crs=ccrs.PlateCarree(),
draw_labels=True,
linewidth=1.2,
color='k',
alpha=0.5,
linestyle='--'
)
gl.xlabels_top = False# 关闭顶端的经纬度标签
gl.ylabels_right = False# 关闭右侧的经纬度标签
gl.xformatter = LONGITUDE_FORMATTER  # x轴设为经度的格式
gl.yformatter = LATITUDE_FORMATTER  # y轴设为纬度的格式
gl.xlocator = mticker.FixedLocator(np.arange(95, 145+ 5, 5))
gl.ylocator = mticker.FixedLocator(np.arange(-5, 45+ 5, 5))
# --设置小地图
left, bottom, width, height = 0.67, 0.15, 0.23, 0.27
ax2 = fig.add_axes(
[left, bottom, width, height], 
projection=proj
)
ax2.add_feature(provinces, linewidth=0.6, zorder=2)
ax2.add_feature(cfeat.COASTLINE.with_scale('50m'), linewidth=0.6, zorder=10)
ax2.add_feature(cfeat.RIVERS.with_scale('50m'), zorder=10)
ax2.add_feature(cfeat.LAKES.with_scale('50m'), zorder=10)
ax2.set_extent([105, 125, 0, 25])
# ax2.stock_img()
ax2.imshow(
imread('./NE1_50M_SR_W.tif'),
origin='upper',
transform=proj,
extent=[-180, 180, -90, 90]
)
returnax
defmain():
ax = create_map()
title = f'distribution of station around China'
ax.set_title(title, fontsize=18)
df = pd.read_csv('buyo_position.csv')
df['lon'] = df['lon'].astype(np.float64)
df['lat'] = df['lat'].astype(np.float64)
ax.scatter(
df['lon'].values,
df['lat'].values,
marker='o',
s=10,
color ="blue"
)
fori, j, k inlist(zip(df['lon'].values, df['lat'].values, df['name'].values)):
ax.text(i - 0.8, j + 0.2, k, fontsize=6)
plt.savefig('station_distribute_map.png')
if__name__ == '__main__':
main()

[p=null, 2, center]

5f26a8f43bc286f9ea70a26e6cf3ac00.png

资源获取地址:
游客,如果您要查看本帖隐藏内容请回复

0 E1 L. S/ z. R/ O


2 L, ^; c. j/ o, Q7 o& A& \2 u
( c9 J/ q. h# g, e7 r2 K7 E# @, l! `
回复

举报 使用道具

相关帖子

全部回帖
学习一下
发表于 2022-1-20 09:19:57

举报 回复 使用道具

懒得打字?点击右侧快捷回复 【吾爱海洋论坛发文有奖】
您需要登录后才可以回帖 登录 | 立即注册
胡知恩
活跃在2022-5-26
快速回复 返回顶部 返回列表