oafuncs 0.0.81__py2.py3-none-any.whl → 0.0.83__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oafuncs/data_store/OAFuncs.png +0 -0
- oafuncs/oa_cmap.py +1 -0
- oafuncs/oa_data.py +107 -28
- oafuncs/oa_down/__init__.py +5 -4
- oafuncs/oa_down/hycom_3hourly.py +152 -35
- oafuncs/oa_down/user_agent.py +34 -0
- oafuncs/oa_draw.py +165 -103
- oafuncs/oa_file.py +66 -53
- oafuncs/oa_help.py +19 -16
- oafuncs/oa_nc.py +82 -114
- oafuncs-0.0.83.dist-info/METADATA +91 -0
- oafuncs-0.0.83.dist-info/RECORD +26 -0
- oafuncs/oa_down/test.py +0 -151
- oafuncs/oa_s/__init__.py +0 -23
- oafuncs/oa_s/oa_cmap.py +0 -163
- oafuncs/oa_s/oa_data.py +0 -187
- oafuncs/oa_s/oa_draw.py +0 -451
- oafuncs/oa_s/oa_file.py +0 -332
- oafuncs/oa_s/oa_help.py +0 -39
- oafuncs/oa_s/oa_nc.py +0 -410
- oafuncs/oa_s/oa_python.py +0 -107
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/__init__.py" +0 -26
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_cmap.py" +0 -163
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_data.py" +0 -187
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_down/__init__.py" +0 -20
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_down/hycom_3hourly.py" +0 -1176
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_down/literature.py" +0 -332
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_down/test_ua.py" +0 -151
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_draw.py" +0 -451
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_file.py" +0 -332
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_help.py" +0 -39
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_nc.py" +0 -410
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_python.py" +0 -107
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_sign/__init__.py" +0 -21
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_sign/meteorological.py" +0 -168
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_sign/ocean.py" +0 -158
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_sign/scientific.py" +0 -139
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_tool/__init__.py" +0 -18
- oafuncs - /321/205/320/231/320/277/321/206/320/254/320/274/oa_tool/email.py" +0 -114
- oafuncs-0.0.81.dist-info/METADATA +0 -918
- oafuncs-0.0.81.dist-info/RECORD +0 -51
- {oafuncs-0.0.81.dist-info → oafuncs-0.0.83.dist-info}/LICENSE.txt +0 -0
- {oafuncs-0.0.81.dist-info → oafuncs-0.0.83.dist-info}/WHEEL +0 -0
- {oafuncs-0.0.81.dist-info → oafuncs-0.0.83.dist-info}/top_level.txt +0 -0
oafuncs/oa_draw.py
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
# coding=utf-8
|
3
|
-
|
3
|
+
"""
|
4
4
|
Author: Liu Kun && 16031215@qq.com
|
5
5
|
Date: 2024-09-17 17:26:11
|
6
6
|
LastEditors: Liu Kun && 16031215@qq.com
|
7
7
|
LastEditTime: 2024-11-21 13:10:47
|
8
8
|
FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_draw.py
|
9
|
-
Description:
|
9
|
+
Description:
|
10
10
|
EditPlatform: vscode
|
11
11
|
ComputerInfo: XPS 15 9510
|
12
12
|
SystemInfo: Windows 11
|
13
13
|
Python Version: 3.11
|
14
|
-
|
15
|
-
|
14
|
+
"""
|
16
15
|
|
17
16
|
import math
|
18
17
|
import warnings
|
@@ -26,22 +25,23 @@ import xarray as xr
|
|
26
25
|
from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter
|
27
26
|
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
28
27
|
|
29
|
-
__all__ = [
|
28
|
+
__all__ = ["fig_minus", "create_gif", "add_cartopy", "add_gridlines", 'MidpointNormalize', "add_lonlat_unit", "plot_contourf", "plot_contourf_lonlat", "plot_quiver", "plot_contourf_cartopy"]
|
29
|
+
|
30
|
+
warnings.filterwarnings("ignore")
|
30
31
|
|
31
|
-
warnings.filterwarnings('ignore')
|
32
32
|
|
33
33
|
def fig_minus(ax_x=None, ax_y=None, cbar=None, decimal=None, add_space=False):
|
34
|
-
|
34
|
+
"""
|
35
35
|
Description: 将坐标轴刻度中的负号替换为减号
|
36
|
-
|
36
|
+
|
37
37
|
param {*} ax_x : x轴
|
38
38
|
param {*} ax_y : y轴
|
39
39
|
param {*} cbar : colorbar
|
40
40
|
param {*} decimal : 小数位数
|
41
41
|
param {*} add_space : 是否在非负数前面加空格
|
42
|
-
|
42
|
+
|
43
43
|
return {*} ax_x or ax_y or cbar
|
44
|
-
|
44
|
+
"""
|
45
45
|
if ax_x is not None:
|
46
46
|
current_ticks = ax_x.get_xticks()
|
47
47
|
if ax_y is not None:
|
@@ -74,38 +74,39 @@ def fig_minus(ax_x=None, ax_y=None, cbar=None, decimal=None, add_space=False):
|
|
74
74
|
cbar.set_ticklabels(out_ticks)
|
75
75
|
return cbar
|
76
76
|
|
77
|
-
# ** 将生成图片/已有图片制作成动图
|
78
|
-
|
79
77
|
|
78
|
+
# ** 将生成图片/已有图片制作成动图
|
80
79
|
def create_gif(image_list: list, gif_name: str, duration=0.2): # 制作动图,默认间隔0.2
|
81
|
-
|
80
|
+
"""
|
82
81
|
func : 制作动图,将已有图片拼接
|
83
82
|
description : Gif格式动图
|
84
83
|
param {*} image_list 图片列表
|
85
84
|
param {*} gif_name 动图名称(含路径)
|
86
85
|
param {*} duration 动图间隔
|
87
86
|
return {*} 自动保存至指定路径(包含于动图名称中)
|
88
|
-
example :
|
89
|
-
|
87
|
+
example :
|
88
|
+
"""
|
90
89
|
import imageio.v2 as imageio
|
90
|
+
|
91
91
|
frames = []
|
92
92
|
for image_name in image_list:
|
93
93
|
frames.append(imageio.imread(image_name))
|
94
|
-
imageio.mimsave(gif_name, frames, format=
|
95
|
-
print(
|
94
|
+
imageio.mimsave(gif_name, frames, format="GIF", duration=duration)
|
95
|
+
print("Gif制作完成!")
|
96
96
|
return
|
97
97
|
|
98
98
|
|
99
99
|
# ** 转化经/纬度刻度
|
100
|
-
def
|
101
|
-
|
102
|
-
param {*}
|
103
|
-
param {*}
|
100
|
+
def add_lonlat_unit(lon=None, lat=None, decimal=2):
|
101
|
+
"""
|
102
|
+
param {*} lon : 经度列表
|
103
|
+
param {*} lat : 纬度列表
|
104
104
|
param {*} decimal : 小数位数
|
105
105
|
return {*} 转化后的经/纬度列表
|
106
|
-
example :
|
107
|
-
|
108
|
-
|
106
|
+
example : add_lonlat_unit(lon=lon, lat=lat, decimal=2)
|
107
|
+
"""
|
108
|
+
|
109
|
+
def _format_longitude(x_list):
|
109
110
|
out_list = []
|
110
111
|
for x in x_list:
|
111
112
|
if x > 180:
|
@@ -116,7 +117,7 @@ def xy2lonlat(xy, lonlat='lon', decimal=2):
|
|
116
117
|
out_list.append(f"{degrees:.{decimal}f}°{direction}" if x != 0 and x != 180 else f"{degrees}°")
|
117
118
|
return out_list if len(out_list) > 1 else out_list[0]
|
118
119
|
|
119
|
-
def
|
120
|
+
def _format_latitude(y_list):
|
120
121
|
out_list = []
|
121
122
|
for y in y_list:
|
122
123
|
if y > 90:
|
@@ -127,10 +128,78 @@ def xy2lonlat(xy, lonlat='lon', decimal=2):
|
|
127
128
|
out_list.append(f"{degrees:.{decimal}f}°{direction}" if y != 0 else f"{degrees}°")
|
128
129
|
return out_list if len(out_list) > 1 else out_list[0]
|
129
130
|
|
130
|
-
if
|
131
|
-
return
|
132
|
-
elif
|
133
|
-
return
|
131
|
+
if lon and lat:
|
132
|
+
return _format_longitude(lon), _format_latitude(lat)
|
133
|
+
elif lon:
|
134
|
+
return _format_longitude(lon)
|
135
|
+
elif lat:
|
136
|
+
return _format_latitude(lat)
|
137
|
+
|
138
|
+
|
139
|
+
# ** 添加网格线
|
140
|
+
def add_gridlines(ax, projection=ccrs.PlateCarree(), color="k", alpha=0.5, linestyle="--", linewidth=0.5):
|
141
|
+
# add gridlines
|
142
|
+
gl = ax.gridlines(crs=projection, draw_labels=True, linewidth=linewidth, color=color, alpha=alpha, linestyle=linestyle)
|
143
|
+
gl.right_labels = False
|
144
|
+
gl.top_labels = False
|
145
|
+
gl.xformatter = LongitudeFormatter(zero_direction_label=False)
|
146
|
+
gl.yformatter = LatitudeFormatter()
|
147
|
+
|
148
|
+
return ax, gl
|
149
|
+
|
150
|
+
|
151
|
+
# ** 添加地图
|
152
|
+
def add_cartopy(ax, lon=None, lat=None, projection=ccrs.PlateCarree(), gridlines=True, landcolor="lightgrey", oceancolor="lightblue", cartopy_linewidth=0.5):
|
153
|
+
|
154
|
+
# add coastlines
|
155
|
+
ax.add_feature(cfeature.LAND, facecolor=landcolor)
|
156
|
+
ax.add_feature(cfeature.OCEAN, facecolor=oceancolor)
|
157
|
+
ax.add_feature(cfeature.COASTLINE, linewidth=cartopy_linewidth)
|
158
|
+
ax.add_feature(cfeature.BORDERS, linewidth=cartopy_linewidth, linestyle=":")
|
159
|
+
|
160
|
+
# add gridlines
|
161
|
+
if gridlines:
|
162
|
+
ax, gl = add_gridlines(ax, projection)
|
163
|
+
|
164
|
+
# set longitude and latitude format
|
165
|
+
lon_formatter = LongitudeFormatter(zero_direction_label=False)
|
166
|
+
lat_formatter = LatitudeFormatter()
|
167
|
+
ax.xaxis.set_major_formatter(lon_formatter)
|
168
|
+
ax.yaxis.set_major_formatter(lat_formatter)
|
169
|
+
|
170
|
+
# set extent
|
171
|
+
if lon is not None and lat is not None:
|
172
|
+
lon_min, lon_max = lon.min(), lon.max()
|
173
|
+
lat_min, lat_max = lat.min(), lat.max()
|
174
|
+
ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=projection)
|
175
|
+
|
176
|
+
|
177
|
+
# ** 自定义归一化类,使得0值处为中心点
|
178
|
+
class MidpointNormalize(mpl.colors.Normalize):
|
179
|
+
"""
|
180
|
+
Description: 自定义归一化类,使得0值处为中心点
|
181
|
+
|
182
|
+
param {*} mpl.colors.Normalize : 继承Normalize类
|
183
|
+
return {*}
|
184
|
+
|
185
|
+
Example:
|
186
|
+
nrom = MidpointNormalize(vmin=-2, vmax=1, vcenter=0)
|
187
|
+
"""
|
188
|
+
|
189
|
+
def __init__(self, vmin=None, vmax=None, vcenter=None, clip=False):
|
190
|
+
self.vcenter = vcenter
|
191
|
+
super().__init__(vmin, vmax, clip)
|
192
|
+
|
193
|
+
def __call__(self, value, clip=None):
|
194
|
+
x, y = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1.0]
|
195
|
+
return np.ma.masked_array(np.interp(value, x, y, left=-np.inf, right=np.inf))
|
196
|
+
|
197
|
+
def inverse(self, value):
|
198
|
+
y, x = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1]
|
199
|
+
return np.interp(value, x, y, left=-np.inf, right=np.inf)
|
200
|
+
|
201
|
+
|
202
|
+
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
134
203
|
|
135
204
|
|
136
205
|
# ** 设置colorbar格式
|
@@ -142,32 +211,31 @@ class _MyFormatter(mpl.ticker.ScalarFormatter):
|
|
142
211
|
self.vmin = min(cticks)
|
143
212
|
self.vmax = max(cticks)
|
144
213
|
self.p_n = self.vmin < 0 and self.vmax > 0
|
145
|
-
self.magnitude_min = int(
|
146
|
-
math.modf(math.log10(min(abs(cticks[cticks != 0]))))[1])
|
214
|
+
self.magnitude_min = int(math.modf(math.log10(min(abs(cticks[cticks != 0]))))[1])
|
147
215
|
self.magnitude_max = int(math.modf(math.log10(max(abs(cticks))))[1])
|
148
216
|
# print(self.vmin, self.vmax)
|
149
217
|
|
150
218
|
def __call__(self, x, pos):
|
151
219
|
if ((abs(x) < 1e-2) or (abs(x) > 1e4)) and x != 0:
|
152
220
|
if self.magnitude_max - self.magnitude_min == 1 and (int(math.modf(math.log10(abs(x)))[1]) == self.magnitude_min):
|
153
|
-
a, b =
|
221
|
+
a, b = "{:.1e}".format(x).split("e")
|
154
222
|
a = float(a) / 10
|
155
223
|
b = int(b) + 1
|
156
224
|
else:
|
157
|
-
a, b =
|
225
|
+
a, b = "{:.2e}".format(x).split("e")
|
158
226
|
a = float(a)
|
159
227
|
b = int(b)
|
160
228
|
# return '${}{} \\times 10^{{{}}}$'.format(' ' if (self.p_n and x > 0) else '', a, b)
|
161
|
-
return
|
229
|
+
return "${}{:.2f}$".format(" " if (self.p_n and x > 0) else "", a)
|
162
230
|
elif x == 0:
|
163
|
-
return
|
231
|
+
return "0"
|
164
232
|
else:
|
165
233
|
return mpl.ticker.ScalarFormatter.__call__(self, x, pos)
|
166
234
|
|
167
235
|
|
168
236
|
# ** 绘制单张填色图
|
169
|
-
def plot_contourf(pic_data, picname=None, c_map=
|
170
|
-
|
237
|
+
def plot_contourf(pic_data, picname=None, c_map="rainbow", minmax=None, labels=None, ticks_space=None, ticks=None, figsize=(12, 9)):
|
238
|
+
"""
|
171
239
|
func : 绘制填色等值线图,单张
|
172
240
|
description : 绘制单张填色等值线图,输入参数为横纵坐标、等值数据、图例标注等
|
173
241
|
param {*}pic_data : 填色等值线图的等值数据
|
@@ -178,7 +246,7 @@ def plot_contourf(pic_data, picname=None, c_map='rainbow', minmax=None, labels=N
|
|
178
246
|
param {*}ticks_space : x、y轴刻度,以及所显示的标签,默认不显示
|
179
247
|
param {*}figsize : 图片大小,默认(12,9)
|
180
248
|
example : plot_contourf(pic_data, pictpath, var_name, c_map='bwr', labels=None, ticks_space=None, ticks=None, h=0, figsize=(12, 9))
|
181
|
-
|
249
|
+
"""
|
182
250
|
cmap = mpl.colormaps.get_cmap(c_map)
|
183
251
|
if minmax is not None:
|
184
252
|
value_min, value_max = minmax[0], minmax[1]
|
@@ -186,8 +254,7 @@ def plot_contourf(pic_data, picname=None, c_map='rainbow', minmax=None, labels=N
|
|
186
254
|
value_min, value_max = pic_data.nanmin(), pic_data.nanmax()
|
187
255
|
v_bry = max(abs(value_min), abs(value_max))
|
188
256
|
flag = (value_min < 0) and (value_max > 0)
|
189
|
-
norm = mpl.colors.TwoSlopeNorm(
|
190
|
-
vmin=-1 * v_bry, vcenter=0, vmax=v_bry) if flag else mpl.colors.Normalize(vmin=value_min, vmax=value_max)
|
257
|
+
norm = mpl.colors.TwoSlopeNorm(vmin=-1 * v_bry, vcenter=0, vmax=v_bry) if flag else mpl.colors.Normalize(vmin=value_min, vmax=value_max)
|
191
258
|
cticks = [num for num in np.linspace(-1 * v_bry if flag else value_min, v_bry if flag else value_max, 9)] if value_min != value_max else None
|
192
259
|
levels = np.linspace(-1 * v_bry, v_bry, 20) if flag else None if value_min == value_max else np.linspace(value_min, value_max, 20)
|
193
260
|
|
@@ -196,8 +263,8 @@ def plot_contourf(pic_data, picname=None, c_map='rainbow', minmax=None, labels=N
|
|
196
263
|
|
197
264
|
fig, ax = plt.subplots(figsize=figsize)
|
198
265
|
flag_lc = levels is not None and cticks is not None
|
199
|
-
CS = ax.contourf(x, y, pic_data, cmap=cmap, norm=norm, levels=levels, extend=
|
200
|
-
cb = fig.colorbar(CS, ax=ax, orientation=
|
266
|
+
CS = ax.contourf(x, y, pic_data, cmap=cmap, norm=norm, levels=levels, extend="both") if flag_lc else ax.contourf(x, y, pic_data, cmap=cmap, norm=norm, extend="both")
|
267
|
+
cb = fig.colorbar(CS, ax=ax, orientation="vertical", shrink=1, format="%.3g", spacing="uniform", ticks=cticks) if cticks is not None else fig.colorbar(CS, ax=ax, orientation="vertical", shrink=1, format="%.3g", spacing="uniform")
|
201
268
|
"""%.3g采用的是自动调整格式,也可设置为%.3f,则改为3位小数"""
|
202
269
|
|
203
270
|
# 将格式化器设置为自定义的函数
|
@@ -209,20 +276,16 @@ def plot_contourf(pic_data, picname=None, c_map='rainbow', minmax=None, labels=N
|
|
209
276
|
cb.update_ticks()
|
210
277
|
|
211
278
|
if labels is not None:
|
212
|
-
cb.set_label(labels[
|
213
|
-
plt.xlabel(labels[
|
214
|
-
plt.ylabel(labels[
|
279
|
+
cb.set_label(labels["c"])
|
280
|
+
plt.xlabel(labels["x"])
|
281
|
+
plt.ylabel(labels["y"])
|
215
282
|
if ticks_space is not None and ticks is not None:
|
216
|
-
plt.xticks(np.arange(0, len(x[0, :]) +
|
217
|
-
|
218
|
-
plt.yticks(np.arange(0, len(y[:, 0]) +
|
219
|
-
1e-5, ticks_space['y']), ticks['y'])
|
283
|
+
plt.xticks(np.arange(0, len(x[0, :]) + 1e-5, ticks_space["x"]), ticks["x"])
|
284
|
+
plt.yticks(np.arange(0, len(y[:, 0]) + 1e-5, ticks_space["y"]), ticks["y"])
|
220
285
|
|
221
|
-
plt.title(
|
222
|
-
pic_data.min(), pic_data.max()))
|
286
|
+
plt.title("Min: {:.3g}, Max: {:.3g}".format(pic_data.min(), pic_data.max()))
|
223
287
|
|
224
|
-
plt.savefig(
|
225
|
-
picname, bbox_inches='tight') if picname is not None else plt.show()
|
288
|
+
plt.savefig(picname, bbox_inches="tight") if picname is not None else plt.show()
|
226
289
|
# plt.show()
|
227
290
|
plt.clf()
|
228
291
|
# 关闭当前figure
|
@@ -230,8 +293,8 @@ def plot_contourf(pic_data, picname=None, c_map='rainbow', minmax=None, labels=N
|
|
230
293
|
|
231
294
|
|
232
295
|
# ** 画等高线图,带经纬度坐标轴
|
233
|
-
def plot_contourf_lonlat(data, lon, lat, interval=5, picname=None, c_map=
|
234
|
-
|
296
|
+
def plot_contourf_lonlat(data, lon, lat, interval=5, picname=None, c_map="rainbow"):
|
297
|
+
"""
|
235
298
|
param {*} data : 二维数据
|
236
299
|
param {*} lon : 经度
|
237
300
|
param {*} lat : 纬度
|
@@ -239,7 +302,7 @@ def plot_contourf_lonlat(data, lon, lat, interval=5, picname=None, c_map='rainbo
|
|
239
302
|
param {*} picname : 图片保存的文件名(含路径)
|
240
303
|
param {*} c_map : 颜色映射,默认rainbow
|
241
304
|
return {*} 无返回值
|
242
|
-
|
305
|
+
"""
|
243
306
|
if len(lon.shape) == 2:
|
244
307
|
lon = lon[0, :]
|
245
308
|
if len(lat.shape) == 2:
|
@@ -267,14 +330,13 @@ def plot_contourf_lonlat(data, lon, lat, interval=5, picname=None, c_map='rainbo
|
|
267
330
|
plt.xticks(np.arange(0, len(lon), x_space), [format_longitude(lon[i]) for i in range(0, len(lon), x_space)])
|
268
331
|
plt.yticks(np.arange(0, len(lat), y_space), [format_latitude(lat[i]) for i in range(0, len(lat), y_space)])
|
269
332
|
plt.colorbar()
|
270
|
-
plt.savefig(
|
271
|
-
picname, bbox_inches='tight') if picname is not None else plt.show()
|
333
|
+
plt.savefig(picname, bbox_inches="tight") if picname is not None else plt.show()
|
272
334
|
plt.close()
|
273
335
|
|
274
336
|
|
275
337
|
# ** 绘制矢量场
|
276
|
-
def plot_quiver(u, v, lon, lat, picname=None, cmap=
|
277
|
-
|
338
|
+
def plot_quiver(u, v, lon, lat, picname=None, cmap="coolwarm", scale=0.25, width=0.002, x_space=5, y_space=5):
|
339
|
+
"""
|
278
340
|
param {*} u : 二维数据
|
279
341
|
param {*} v : 二维数据
|
280
342
|
param {*} lon : 经度, 1D or 2D
|
@@ -286,7 +348,7 @@ def plot_quiver(u, v, lon, lat, picname=None, cmap='coolwarm', scale=0.25, width
|
|
286
348
|
param {*} x_space : x轴间隔
|
287
349
|
param {*} y_space : y轴间隔
|
288
350
|
return {*} 无返回值
|
289
|
-
|
351
|
+
"""
|
290
352
|
# 创建新的网格位置变量(lat_c, lon_c)
|
291
353
|
if len(lon.shape) == 1 and len(lat.shape) == 1:
|
292
354
|
lon_c, lat_c = np.meshgrid(lon, lat)
|
@@ -307,29 +369,32 @@ def plot_quiver(u, v, lon, lat, picname=None, cmap='coolwarm', scale=0.25, width
|
|
307
369
|
|
308
370
|
# 使用 plt.quiver 函数绘制矢量图
|
309
371
|
# 通过设置 quiver 函数的 pivot 参数来指定箭头的位置
|
310
|
-
quiver_plot = plt.quiver(
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
372
|
+
quiver_plot = plt.quiver(
|
373
|
+
lon_c[::y_space, ::x_space],
|
374
|
+
lat_c[::y_space, ::x_space],
|
375
|
+
u[::y_space, ::x_space],
|
376
|
+
v[::y_space, ::x_space],
|
377
|
+
S[::y_space, ::x_space], # 矢量的大小,可以不要
|
378
|
+
pivot="middle",
|
379
|
+
scale=scale,
|
380
|
+
# color=color, # 矢量的颜色,单色
|
381
|
+
cmap=cmap, # 矢量的颜色,多色
|
382
|
+
width=width,
|
383
|
+
)
|
320
384
|
# plt.quiverkey(quiver_plot, X=0.90, Y=0.975, U=1, label='1 m/s', labelpos='E', fontproperties={'size': 10})
|
321
|
-
plt.quiverkey(quiver_plot, X=0.87, Y=0.975, U=mean_S, label=f
|
385
|
+
plt.quiverkey(quiver_plot, X=0.87, Y=0.975, U=mean_S, label=f"{mean_S:.2f} m/s", labelpos="E", fontproperties={"size": 10})
|
322
386
|
plt.colorbar(quiver_plot)
|
323
|
-
plt.xlabel(
|
324
|
-
plt.ylabel(
|
387
|
+
plt.xlabel("X")
|
388
|
+
plt.ylabel("Y")
|
325
389
|
|
326
|
-
plt.savefig(picname, bbox_inches=
|
390
|
+
plt.savefig(picname, bbox_inches="tight") if picname is not None else plt.show()
|
327
391
|
plt.clf()
|
328
392
|
plt.close()
|
329
393
|
|
330
394
|
|
331
|
-
|
332
|
-
|
395
|
+
# ** 绘制填色图(带经纬度)
|
396
|
+
def plot_contourf_cartopy(data, lon, lat, picname=None, cmap="rainbow", cn_fill_num=20, fig_size=(12, 9), title="Cartopy", land_color="green", ocean_color="lightgrey"):
|
397
|
+
"""
|
333
398
|
param {*} data : 二维数据
|
334
399
|
param {*} lon : 经度
|
335
400
|
param {*} lat : 纬度
|
@@ -341,7 +406,7 @@ def plot_contourf_cartopy(data, lon, lat, picname=None, cmap='rainbow', cn_fill_
|
|
341
406
|
param {*} land_color : 陆地颜色
|
342
407
|
param {*} ocean_color : 海洋颜色
|
343
408
|
return {*} 无返回值
|
344
|
-
|
409
|
+
"""
|
345
410
|
if len(lon.shape) == 2:
|
346
411
|
lon = lon[0, :]
|
347
412
|
if len(lat.shape) == 2:
|
@@ -381,37 +446,33 @@ def plot_contourf_cartopy(data, lon, lat, picname=None, cmap='rainbow', cn_fill_
|
|
381
446
|
cticks = cbar_ticks
|
382
447
|
norm = mpl.colors.BoundaryNorm(cticks, cmap.N)
|
383
448
|
|
384
|
-
cnplot = ax.contourf(X, Y, data, levels=levels, cmap=cmap, norm=norm, transform=proj, extend=
|
449
|
+
cnplot = ax.contourf(X, Y, data, levels=levels, cmap=cmap, norm=norm, transform=proj, extend="both", alpha=1, zorder=0)
|
385
450
|
# cllevels = np.linspace(data_min, data_max, 9)
|
386
451
|
# clplot = ax.contour(X, Y, data, levels=levels[9::10], colors='k', linewidths=0.5, transform=proj, zorder=1, alpha=0.8, linestyle='--')
|
387
452
|
# 添加色标,并选择位置
|
388
453
|
divider = make_axes_locatable(ax)
|
389
454
|
location = 3
|
390
455
|
if location == 1: # 左侧
|
391
|
-
cax = divider.new_horizontal(
|
392
|
-
size="5%", pad=1, axes_class=plt.Axes, pack_start=True)
|
456
|
+
cax = divider.new_horizontal(size="5%", pad=1, axes_class=plt.Axes, pack_start=True)
|
393
457
|
fig.add_axes(cax)
|
394
|
-
cbar = plt.colorbar(
|
395
|
-
cnplot, cax=cax, orientation='vertical', extend='both')
|
458
|
+
cbar = plt.colorbar(cnplot, cax=cax, orientation="vertical", extend="both")
|
396
459
|
elif location == 2: # 下方
|
397
|
-
cax = divider.new_vertical(
|
398
|
-
size="5%", pad=0.3, axes_class=plt.Axes, pack_start=True)
|
460
|
+
cax = divider.new_vertical(size="5%", pad=0.3, axes_class=plt.Axes, pack_start=True)
|
399
461
|
fig.add_axes(cax)
|
400
|
-
cbar = plt.colorbar(
|
401
|
-
cnplot, cax=cax, orientation='horizontal', extend='both')
|
462
|
+
cbar = plt.colorbar(cnplot, cax=cax, orientation="horizontal", extend="both")
|
402
463
|
elif location == 3: # 右侧
|
403
464
|
cax = divider.new_horizontal(size="5%", pad=0.1, axes_class=plt.Axes)
|
404
465
|
fig.add_axes(cax)
|
405
466
|
# cbar = plt.colorbar(cnplot, cax=cax, orientation='vertical', extend='both', format='%.0f')
|
406
|
-
cbar = fig.colorbar(mpl.cm.ScalarMappable(cmap=cmap, norm=norm), cax=cax, orientation=
|
407
|
-
cax.yaxis.set_ticks_position(
|
408
|
-
cax.yaxis.set_label_position(
|
467
|
+
cbar = fig.colorbar(mpl.cm.ScalarMappable(cmap=cmap, norm=norm), cax=cax, orientation="vertical", extend="both", format="%.3f")
|
468
|
+
cax.yaxis.set_ticks_position("right")
|
469
|
+
cax.yaxis.set_label_position("right")
|
409
470
|
else: # 上方
|
410
471
|
cax = divider.new_vertical(size="5%", pad=0.2, axes_class=plt.Axes)
|
411
472
|
fig.add_axes(cax)
|
412
|
-
cbar = plt.colorbar(cnplot, cax=cax, orientation=
|
473
|
+
cbar = plt.colorbar(cnplot, cax=cax, orientation="horizontal", extend="both")
|
413
474
|
cbar.ax.tick_params(labelsize=10)
|
414
|
-
cbar.ax.xaxis.set_tick_params(direction=
|
475
|
+
cbar.ax.xaxis.set_tick_params(direction="in", width=1, length=2)
|
415
476
|
# 添加cbar_ticks
|
416
477
|
# cbar.set_ticks(np.arange(round(levels[0]), round(levels[-1]), round((levels[-1]-levels[0])/9))) # 设置色标刻度
|
417
478
|
# cbar.set_ticks(cbar_ticks) # 设置色标刻度
|
@@ -421,31 +482,32 @@ def plot_contourf_cartopy(data, lon, lat, picname=None, cmap='rainbow', cn_fill_
|
|
421
482
|
# cbar.set_ticks(np.arange(round(levels[0]), round(levels[-1]), round((levels[-1]-levels[0])/9))) # 设置色标刻度
|
422
483
|
|
423
484
|
# 单独设置label
|
424
|
-
cbar.set_label(title, fontsize=10, weight=
|
485
|
+
cbar.set_label(title, fontsize=10, weight="bold")
|
425
486
|
# cax.set_position([0.1, 0.2, 0.02, 0.6]) # 调整色标位置
|
426
|
-
fig.savefig(picname, bbox_inches=
|
487
|
+
fig.savefig(picname, bbox_inches="tight", dpi=600) if picname is not None else plt.show()
|
427
488
|
plt.close()
|
428
489
|
|
429
490
|
|
430
|
-
|
491
|
+
|
492
|
+
if __name__ == "__main__":
|
431
493
|
# ** 绘制填色图
|
432
494
|
data = np.random.randn(100, 100)
|
433
|
-
picname =
|
434
|
-
plot_contourf(data, picname, c_map=
|
495
|
+
picname = "test.png"
|
496
|
+
plot_contourf(data, picname, c_map="rainbow", minmax=None, labels=None, ticks_space=None, ticks=None, figsize=(12, 9))
|
435
497
|
# ** 绘制矢量场
|
436
498
|
u = np.random.randn(100, 100)
|
437
499
|
v = np.random.randn(100, 100)
|
438
500
|
lon = np.linspace(0, 360, 100)
|
439
501
|
lat = np.linspace(-90, 90, 100)
|
440
|
-
picname =
|
441
|
-
plot_quiver(u, v, lon, lat, picname, cmap=
|
502
|
+
picname = "test.png"
|
503
|
+
plot_quiver(u, v, lon, lat, picname, cmap="coolwarm", scale=0.25, width=0.002, x_space=5, y_space=5)
|
442
504
|
# ** 绘制经纬度填色图
|
443
505
|
data = np.random.randn(100, 100)
|
444
506
|
lon = np.linspace(0, 360, 100)
|
445
507
|
lat = np.linspace(-90, 90, 100)
|
446
|
-
picname =
|
447
|
-
plot_contourf_lonlat(data, lon, lat, interval=5, picname=picname, c_map=
|
508
|
+
picname = "test.png"
|
509
|
+
plot_contourf_lonlat(data, lon, lat, interval=5, picname=picname, c_map="rainbow")
|
448
510
|
# ** 制作动图
|
449
|
-
image_list = [
|
450
|
-
gif_name =
|
511
|
+
image_list = ["test1.png", "test2.png", "test3.png"]
|
512
|
+
gif_name = "test.gif"
|
451
513
|
create_gif(image_list, gif_name, duration=0.2)
|