Pytorch可视化_cartopy+matplotlib_绘制雷达图像

学会用python画图:

1读取天气雷达组网拼图数据(包含数据和程序),数据放大了10倍存储
2 使用cartopy绘制二维图,网站https://scitools.org.uk/cartopy/docs/latest/
3 要求带行政边界
4 线宽2,主刻度和次要刻度也为2
5 要求带颜色条,放在图的右边,颜色条上面要标出单位dBZ
6 字号18-22
7 保存为svg格式,或tiff格式(tiff格式要求dpi>=200)

工作:

1.首先要知道画一个图像所需要的步骤:

在这里插入图片描述
参考链接:气象绘图基本操作

2.根据要求分析自己要做的工作
(1)用matplotlib创建一个子图
(2)用cartopy投影出2维地图
(3)下载相关的.shp/,dat文件(国内行政划分需要的文件)
(4)在投影里添加海岸线、国界、河流、湖泊、省界(省界由上一步下载的文件得出的)等元素
(5)设置子图内投影的经纬度范围
(6)添加经纬度坐标
(7)将雷达数据覆盖到图中
(8)设置雷达数据的色度条
(9)添加南海诸岛的子图
(10)显示图片

3.详细步骤:
(1)用matplotlib创建一个子图
(2)用cartopy投影出2维地图

1
2
3
4
5
6
    proj = ccrs.PlateCarree()           #创建投影,选择cartopy的platecarree投影
    fig = plt.figure(figsize=(21,31))   #创建页面,可以自己选择大小

    ax = fig.subplots(1, 1, subplot_kw={<!-- -->'projection': proj})    #创建子图
    ax.outline_patch.set_linewidth(2)                           #设置子图边框的linewidth
    ax.set_title('天气雷达组网拼图', fontsize=22, color='k',fontproperties=font_set)#设置title

(3)下载相关的.shp/,dat文件(国内行政划分需要的文件)
注:这里dat文件我已经下载放在了同一级文件夹下,直接打开读取数据即可。没有的需要自行去下载,网上搜一下会有资料。

1
2
3
4
5
    #读取dat文件
    with open(r'CN-border-La.dat') as src:
        context = ''.join([line for line in src if not line.startswith('#')])
        blocks = [cnt for cnt in context.split('>') if len(cnt) > 0]
        borders = [np.fromstring(block, dtype=float, sep=' ') for block in blocks]

(4)在投影里添加海岸线、国界、河流、湖泊、省界(省界由上一步下载的文件得出的)等元素

1
2
3
4
5
6
7
8
    #添加cartopy中的国界、海岸线、河流、湖泊
    ax.add_feature(cfeat.BORDERS.with_scale('50m'), linewidth=2, zorder=1)
    ax.add_feature(cfeat.COASTLINE.with_scale('50m'), linewidth=2,zorder=1)
    ax.add_feature(cfeat.RIVERS.with_scale('50m'), linewidth=2,zorder=1)
    ax.add_feature(cfeat.LAKES.with_scale('50m'), zorder=1)
    #添加中国行政边界、十段线
    for line in borders:
        ax.plot(line[0::2], line[1::2], '-', lw=2, color='k', alpha=0.9,transform=ccrs.Geodetic())

(5)设置子图内投影的经纬度范围

1
2
    #设置子图内投影的经纬度范围
    ax.set_extent([73.0, 135.0, 12.2, 54.2])

(6)添加经纬度坐标
这里运用网格线的方式添加坐标,不过网格线的linewidth设置为0,则只显示坐标。

1
2
3
4
5
6
7
8
9
10
    #经纬度网格线设置,这里linewidth=0把网格线去掉,只保留经纬度坐标
    gl = ax.gridlines(crs=ccrs.PlateCarree(),draw_labels=True,
    linewidth=0, color='k', alpha=0.5, linestyle='--')
    gl.top_labels = False  #关闭顶端标签
    gl.right_labels = False  #关闭右侧标签
    gl.xformatter = LONGITUDE_FORMATTER  #x轴设为经度格式
    gl.yformatter = LATITUDE_FORMATTER  #y轴设为纬度格式
    #设置坐标的字号
    gl.xlabel_style = {<!-- -->'fontsize':18}
    gl.ylabel_style = {<!-- -->'fontsize':18}

(7)将雷达数据覆盖到图中

1
2
3
4
5
6
7
8
9
10
    color_max = int(ref['data_arr'].max())+1
    color_min = 0
    n_gap = 5
    levels = np.arange(color_min,color_max+10,n_gap)

    #设置雷达反射率图覆盖范围
    X = np.linspace(ref['llon'], ref['ulon'], 6200)
    Y = np.linspace(ref['llat'], ref['ulat'], 4200)
    X, Y = np.meshgrid(X, Y)
    cb = plt.contourf( X, Y,ref['data_arr'],levels=levels,cmap='jet')

(8)设置雷达数据的色度条
注:这里色度条的大小,位置设置还没有完全学会,后面会了的话来修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    #设置colorbar 左 下 宽 高
    l = 0.86
    b = 0.23
    w = 0.025
    h = 0.55
    #对应 l,b,w,h;设置colorbar位置;
    rect = [l,b,w,h]
    cbar_ax = fig.add_axes(rect)
    cbar = plt.colorbar( cax=cbar_ax)

    #重新设置色度条的显示间隔
    cbar.set_ticks(np.arange(color_min,color_max+10,n_gap))
    cbar.outline.set_linewidth(2)      #设置色度条边框linewidth
    cbar.ax.tick_params(labelsize=18)  #设置色度条字体大小。
    cbar.set_label("dBZ",fontsize=18)  #设置色度条单位

(9)添加南海诸岛的子图
注:南海诸岛的设置与以上设置流程大致相同,是否可以用同一文件的行政界限进行设置,我还没做,感觉可以用上面读出来的数据再显示一个图层贴上去。有空再做。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    # --设置南海子图
    # --设置地图属性,读取shp文件
    shp_path = 'cn_shp3641/'
    provinces = cfeat.ShapelyFeature(
        Reader(shp_path + 'Province_9.shp').geometries(),
        proj, edgecolor='k',
        facecolor='none'
    )

    #设置南海子图的坐标
    left, bottom, width, height = 0.67, 0.14, 0.21, 0.23
    ax2 = fig.add_axes(
        [left, bottom, width, height],
        projection=proj
    )

    #添加南海子图的详细内容
    ax2.add_feature(provinces, linewidth=2,alpha=0.9, zorder=1)
    ax2.add_feature(cfeat.COASTLINE.with_scale('50m'), linewidth=2,zorder=1)    #加载分辨率为50的海岸线
    ax2.add_feature(cfeat.RIVERS.with_scale('50m'), linewidth=2,zorder=1)       #加载分辨率为50的河流
    ax2.add_feature(cfeat.LAKES.with_scale('50m'), zorder=1)                    #加载分辨率为50的湖泊

    #设置南海子图的坐标范围,和边框linewidth
    ax2.set_extent([105, 125, 0, 25])
    ax2.outline_patch.set_linewidth(2)

(10)显示图片

1
    plt.show()

附上完整代码,有需要的可以参考,但具体的数据文件、行政边界文件需要自己寻找。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#加载所需包

import math
import time
import cartopy.crs as ccrs
import cartopy.feature as cfeat
from cartopy.mpl.gridliner import LATITUDE_FORMATTER, LONGITUDE_FORMATTER
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from cartopy.io.shapereader import Reader, natural_earth
#导入数据处理模块
from mosaic_parse import MosaicParser

#设置title的中文字体
font_set = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=22)

#绘图函数
def plot_ref(ref):

    proj = ccrs.PlateCarree()           #创建投影,选择cartopy的platecarree投影
    fig = plt.figure(figsize=(21,31))   #创建页面,可以自己选择大小

    ax = fig.subplots(1, 1, subplot_kw={<!-- -->'projection': proj})    #创建子图
    ax.outline_patch.set_linewidth(2)                           #设置子图边框的linewidth
    ax.set_title('天气雷达组网拼图', fontsize=22, color='k',fontproperties=font_set)#设置title

    #读取dat文件
    with open(r'CN-border-La.dat') as src:
        context = ''.join([line for line in src if not line.startswith('#')])
        blocks = [cnt for cnt in context.split('>') if len(cnt) > 0]
        borders = [np.fromstring(block, dtype=float, sep=' ') for block in blocks]

    #添加cartopy中的国界、海岸线、河流、湖泊
    ax.add_feature(cfeat.BORDERS.with_scale('50m'), linewidth=2, zorder=1)
    ax.add_feature(cfeat.COASTLINE.with_scale('50m'), linewidth=2,zorder=1)
    ax.add_feature(cfeat.RIVERS.with_scale('50m'), linewidth=2,zorder=1)
    ax.add_feature(cfeat.LAKES.with_scale('50m'), zorder=1)
    #添加中国行政边界、十段线
    for line in borders:
        ax.plot(line[0::2], line[1::2], '-', lw=2, color='k', alpha=0.9,transform=ccrs.Geodetic())

    #设置子图内投影的经纬度范围
    ax.set_extent([73.0, 135.0, 12.2, 54.2])

    #经纬度网格线设置,这里linewidth=0把网格线去掉,只保留经纬度坐标
    gl = ax.gridlines(crs=ccrs.PlateCarree(),draw_labels=True,
    linewidth=0, color='k', alpha=0.5, linestyle='--')
    gl.top_labels = False  #关闭顶端标签
    gl.right_labels = False  #关闭右侧标签
    gl.xformatter = LONGITUDE_FORMATTER  #x轴设为经度格式
    gl.yformatter = LATITUDE_FORMATTER  #y轴设为纬度格式
    #设置坐标的字号
    gl.xlabel_style = {<!-- -->'fontsize':18}
    gl.ylabel_style = {<!-- -->'fontsize':18}

    #colorbar设置

    #设置色标的取值范围
    color_max = int(ref['data_arr'].max())+1
    color_min = 0
    n_gap = 5
    levels = np.arange(color_min,color_max+10,n_gap)

    #设置雷达反射率图覆盖范围
    X = np.linspace(ref['llon'], ref['ulon'], 6200)
    Y = np.linspace(ref['llat'], ref['ulat'], 4200)
    X, Y = np.meshgrid(X, Y)
    cb = plt.contourf( X, Y,ref['data_arr'],levels=levels,cmap='jet')

    #设置colorbar 左 下 宽 高
    l = 0.86
    b = 0.23
    w = 0.025
    h = 0.55
    #对应 l,b,w,h;设置colorbar位置;
    rect = [l,b,w,h]
    cbar_ax = fig.add_axes(rect)
    cbar = plt.colorbar( cax=cbar_ax)

    #重新设置色度条的显示间隔
    cbar.set_ticks(np.arange(color_min,color_max+10,n_gap))
    cbar.outline.set_linewidth(2)      #设置色度条边框linewidth
    cbar.ax.tick_params(labelsize=18)  #设置色度条字体大小。
    cbar.set_label("dBZ",fontsize=18)  #设置色度条单位


    # --设置南海子图
    # --设置地图属性,读取shp文件
    shp_path = 'cn_shp3641/'
    provinces = cfeat.ShapelyFeature(
        Reader(shp_path + 'Province_9.shp').geometries(),
        proj, edgecolor='k',
        facecolor='none'
    )

    #设置南海子图的坐标
    left, bottom, width, height = 0.67, 0.14, 0.21, 0.23
    ax2 = fig.add_axes(
        [left, bottom, width, height],
        projection=proj
    )

    #添加南海子图的详细内容
    ax2.add_feature(provinces, linewidth=2,alpha=0.9, zorder=1)
    ax2.add_feature(cfeat.COASTLINE.with_scale('50m'), linewidth=2,zorder=1)    #加载分辨率为50的海岸线
    ax2.add_feature(cfeat.RIVERS.with_scale('50m'), linewidth=2,zorder=1)       #加载分辨率为50的河流
    ax2.add_feature(cfeat.LAKES.with_scale('50m'), zorder=1)                    #加载分辨率为50的湖泊

    #设置南海子图的坐标范围,和边框linewidth
    ax2.set_extent([105, 125, 0, 25])
    ax2.outline_patch.set_linewidth(2)

    #保存
    #plt.savefig('./全国雷达组网拼图.png')
    #plt.savefig('./全国雷达组网拼图.tiff',dip=300)  # 指定分辨率保存
    plt.show()


numBlock = 0

#读取数据文件
filename = r'.\ACHN_CREF_20190720_140000.bin'
f = open(filename, 'rb')
buf = f.read()
print(len(buf))
f.close()

#解压数据
radar_parser = MosaicParser()
ref = radar_parser.parse(buf)

plot_ref(ref)

图像:
南海诸岛子图的位置有空的时候再调一下。
在这里插入图片描述