oafuncs 0.0.85__py2.py3-none-any.whl → 0.0.87__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 +96 -47
- oafuncs/oa_data.py +88 -4
- oafuncs/oa_draw.py +64 -252
- oafuncs/oa_help.py +102 -7
- oafuncs/oa_nc.py +134 -86
- {oafuncs-0.0.85.dist-info → oafuncs-0.0.87.dist-info}/METADATA +3 -3
- {oafuncs-0.0.85.dist-info → oafuncs-0.0.87.dist-info}/RECORD +11 -11
- {oafuncs-0.0.85.dist-info → oafuncs-0.0.87.dist-info}/LICENSE.txt +0 -0
- {oafuncs-0.0.85.dist-info → oafuncs-0.0.87.dist-info}/WHEEL +0 -0
- {oafuncs-0.0.85.dist-info → oafuncs-0.0.87.dist-info}/top_level.txt +0 -0
oafuncs/data_store/OAFuncs.png
CHANGED
Binary file
|
oafuncs/oa_cmap.py
CHANGED
@@ -16,17 +16,23 @@ Python Version: 3.11
|
|
16
16
|
import matplotlib as mpl
|
17
17
|
import matplotlib.pyplot as plt
|
18
18
|
import numpy as np
|
19
|
+
from rich import print
|
19
20
|
|
20
|
-
__all__ = ["show", "
|
21
|
+
__all__ = ["show", "to_color", "create", "create_rgbtxt", "get"]
|
21
22
|
|
22
23
|
# ** 将cmap用填色图可视化(官网摘抄函数)
|
23
|
-
def show(colormaps
|
24
|
+
def show(colormaps):
|
24
25
|
"""
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
Description:
|
27
|
+
Helper function to plot data with associated colormap.
|
28
|
+
Parameters:
|
29
|
+
colormaps : list of colormaps, or a single colormap; can be a string or a colormap object.
|
30
|
+
Example:
|
31
|
+
cmap = ListedColormap(["darkorange", "gold", "lawngreen", "lightseagreen"])
|
32
|
+
show([cmap]); show("viridis"); show(["viridis", "cividis"])
|
29
33
|
"""
|
34
|
+
if isinstance(colormaps, str) or isinstance(colormaps, mpl.colors.Colormap):
|
35
|
+
colormaps = [colormaps]
|
30
36
|
np.random.seed(19680801)
|
31
37
|
data = np.random.randn(30, 30)
|
32
38
|
n = len(colormaps)
|
@@ -38,12 +44,17 @@ def show(colormaps: list):
|
|
38
44
|
|
39
45
|
|
40
46
|
# ** 将cmap转为list,即多个颜色的列表
|
41
|
-
def
|
47
|
+
def to_color(cmap, n=256):
|
42
48
|
"""
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
49
|
+
Description:
|
50
|
+
Convert a colormap to a list of colors
|
51
|
+
Parameters:
|
52
|
+
cmap : str; the name of the colormap
|
53
|
+
n : int, optional; the number of colors
|
54
|
+
Return:
|
55
|
+
out_colors : list of colors
|
56
|
+
Example:
|
57
|
+
out_colors = to_color('viridis', 256)
|
47
58
|
"""
|
48
59
|
c_map = mpl.colormaps.get_cmap(cmap)
|
49
60
|
out_colors = [c_map(i) for i in np.linspace(0, 1, n)]
|
@@ -51,16 +62,22 @@ def cmap2colors(cmap, n=256):
|
|
51
62
|
|
52
63
|
|
53
64
|
# ** 自制cmap,多色,可带位置
|
54
|
-
def
|
65
|
+
def create(colors: list, nodes=None, under=None, over=None): # 利用颜色快速配色
|
55
66
|
"""
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
67
|
+
Description:
|
68
|
+
Create a custom colormap
|
69
|
+
Parameters:
|
70
|
+
colors : list of colors
|
71
|
+
nodes : list of positions
|
72
|
+
under : color
|
73
|
+
over : color
|
74
|
+
Return:
|
75
|
+
cmap : colormap
|
76
|
+
Example:
|
77
|
+
cmap = create(['#C2B7F3','#B3BBF2','#B0CBF1','#ACDCF0','#A8EEED'])
|
78
|
+
cmap = create(['aliceblue','skyblue','deepskyblue'],[0.0,0.5,1.0])
|
63
79
|
"""
|
80
|
+
|
64
81
|
if nodes is None: # 采取自动分配比例
|
65
82
|
cmap_color = mpl.colors.LinearSegmentedColormap.from_list("mycmap", colors)
|
66
83
|
else: # 按照提供比例分配
|
@@ -73,17 +90,30 @@ def create_cmap(colors: list, nodes=None, under=None, over=None): # 利用颜
|
|
73
90
|
|
74
91
|
|
75
92
|
# ** 根据RGB的txt文档制作色卡(利用Grads调色盘)
|
76
|
-
def
|
93
|
+
def create_rgbtxt(rgbtxt_file,split_mark=','): # 根据RGB的txt文档制作色卡/根据rgb值制作
|
77
94
|
"""
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
95
|
+
Description
|
96
|
+
-----------
|
97
|
+
Make a color card according to the RGB txt document, each line in the txt file is an RGB value, separated by commas, such as: 251,251,253
|
98
|
+
|
99
|
+
Parameters
|
100
|
+
----------
|
101
|
+
rgbtxt_file : str, the path of txt file
|
102
|
+
split_mark : str, optional, default is ','; the split mark of rgb value
|
103
|
+
|
104
|
+
Returns
|
105
|
+
-------
|
106
|
+
cmap : colormap
|
107
|
+
|
108
|
+
Example
|
109
|
+
-------
|
110
|
+
cmap=create_rgbtxt(path,split_mark=',')
|
111
|
+
|
112
|
+
txt example
|
113
|
+
-----------
|
114
|
+
251,251,253
|
115
|
+
225,125,25
|
116
|
+
250,205,255
|
87
117
|
"""
|
88
118
|
with open(rgbtxt_file) as fid:
|
89
119
|
data = fid.readlines()
|
@@ -94,27 +124,36 @@ def create_cmap_rgbtxt(rgbtxt_file,split_mark=','): # 根据RGB的txt文档制
|
|
94
124
|
rgb[i][1] = data[i].split(split_mark)[1]
|
95
125
|
rgb[i][2] = data[i].split(split_mark)[2]
|
96
126
|
max_rgb = np.max(rgb)
|
97
|
-
if max_rgb > 2: #
|
127
|
+
if max_rgb > 2: # if the value is greater than 2, it is normalized to 0-1
|
98
128
|
rgb = rgb / 255.0
|
99
|
-
|
100
|
-
return
|
129
|
+
my_cmap = mpl.colors.ListedColormap(rgb, name="my_color")
|
130
|
+
return my_cmap
|
101
131
|
|
102
132
|
|
103
133
|
# ** 选择cmap
|
104
|
-
def
|
134
|
+
def get(cmap_name=None, query=False):
|
105
135
|
"""
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
136
|
+
Description:
|
137
|
+
Choosing a colormap from the list of available colormaps or a custom colormap
|
138
|
+
Parameters:
|
139
|
+
cmap_name : str, optional; the name of the colormap
|
140
|
+
query : bool, optional; whether to query the available colormap names
|
141
|
+
Return:
|
142
|
+
cmap : colormap
|
143
|
+
Example:
|
144
|
+
cmap = get('viridis')
|
145
|
+
cmap = get('diverging_1')
|
146
|
+
cmap = get('cold_1')
|
147
|
+
cmap = get('warm_1')
|
148
|
+
cmap = get('colorful_1')
|
110
149
|
"""
|
111
150
|
|
112
151
|
my_cmap_dict = {
|
113
|
-
"diverging_1":
|
114
|
-
"cold_1":
|
115
|
-
"warm_1":
|
116
|
-
# "land_1": create_custom(["#3E6436", "#678A59", "#91A176", "#B8A87D", "#D9CBB2"], under="#A6CEE3", over="#FFFFFF"),
|
117
|
-
# "ocean_1": create_custom(["#126697", "#2D88B3", "#4EA1C9", "#78B9D8", "#A6CEE3"], under="#8470FF", over="#3E6436"),
|
152
|
+
"diverging_1": create(["#4e00b3", "#0000FF", "#00c0ff", "#a1d3ff", "#DCDCDC", "#FFD39B", "#FF8247", "#FF0000", "#FF5F9E"]),
|
153
|
+
"cold_1": create(["#4e00b3", "#0000FF", "#00c0ff", "#a1d3ff", "#DCDCDC"]),
|
154
|
+
"warm_1": create(["#DCDCDC", "#FFD39B", "#FF8247", "#FF0000", "#FF5F9E"]),
|
155
|
+
# "land_1": create_custom(["#3E6436", "#678A59", "#91A176", "#B8A87D", "#D9CBB2"], under="#A6CEE3", over="#FFFFFF"),
|
156
|
+
# "ocean_1": create_custom(["#126697", "#2D88B3", "#4EA1C9", "#78B9D8", "#A6CEE3"], under="#8470FF", over="#3E6436"),
|
118
157
|
# "ocean_land_1": create_custom(
|
119
158
|
# [
|
120
159
|
# "#126697", # 深蓝(深海)
|
@@ -130,11 +169,21 @@ def choose_cmap(cmap_name=None, query=False):
|
|
130
169
|
# "#3E6436", # 深绿(高山)
|
131
170
|
# ]
|
132
171
|
# ),
|
133
|
-
"colorful_1":
|
172
|
+
"colorful_1": create(["#6d00db", "#9800cb", "#F2003C", "#ff4500", "#ff7f00", "#FE28A2", "#FFC0CB", "#DDA0DD", "#40E0D0", "#1a66f2", "#00f7fb", "#8fff88", "#E3FF00"]),
|
134
173
|
}
|
135
174
|
if query:
|
175
|
+
print("Available cmap names:")
|
176
|
+
print('-' * 20)
|
177
|
+
print('Defined by myself:')
|
136
178
|
for key, _ in my_cmap_dict.items():
|
137
179
|
print(key)
|
180
|
+
print('-' * 20)
|
181
|
+
print('Matplotlib built-in:')
|
182
|
+
print(mpl.colormaps())
|
183
|
+
print("-" * 20)
|
184
|
+
|
185
|
+
if cmap_name is None:
|
186
|
+
return
|
138
187
|
|
139
188
|
if cmap_name in my_cmap_dict:
|
140
189
|
return my_cmap_dict[cmap_name]
|
@@ -149,16 +198,16 @@ if __name__ == "__main__":
|
|
149
198
|
# ** 测试自制cmap
|
150
199
|
colors = ["#C2B7F3", "#B3BBF2", "#B0CBF1", "#ACDCF0", "#A8EEED"]
|
151
200
|
nodes = [0.0, 0.2, 0.4, 0.6, 1.0]
|
152
|
-
c_map =
|
201
|
+
c_map = create(colors, nodes)
|
153
202
|
show([c_map])
|
154
203
|
|
155
204
|
# ** 测试自制diverging型cmap
|
156
|
-
diverging_cmap =
|
205
|
+
diverging_cmap = create(["#4e00b3", "#0000FF", "#00c0ff", "#a1d3ff", "#DCDCDC", "#FFD39B", "#FF8247", "#FF0000", "#FF5F9E"])
|
157
206
|
show([diverging_cmap])
|
158
207
|
|
159
208
|
# ** 测试根据RGB的txt文档制作色卡
|
160
209
|
file_path = "E:/python/colorbar/test.txt"
|
161
|
-
cmap_rgb =
|
210
|
+
cmap_rgb = create_rgbtxt(file_path)
|
162
211
|
|
163
212
|
# ** 测试将cmap转为list
|
164
|
-
out_colors =
|
213
|
+
out_colors = to_color("viridis", 256)
|
oafuncs/oa_data.py
CHANGED
@@ -15,12 +15,12 @@ Python Version: 3.11
|
|
15
15
|
|
16
16
|
import itertools
|
17
17
|
import multiprocessing as mp
|
18
|
-
from concurrent.futures import ThreadPoolExecutor
|
18
|
+
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
|
19
19
|
|
20
20
|
import numpy as np
|
21
21
|
from scipy.interpolate import griddata
|
22
22
|
|
23
|
-
__all__ = ["interp_2d"]
|
23
|
+
__all__ = ["interp_2d","ParallelExecutor"]
|
24
24
|
|
25
25
|
|
26
26
|
def interp_2d(target_x, target_y, origin_x, origin_y, data, method="linear", parallel=True):
|
@@ -90,6 +90,73 @@ def interp_2d(target_x, target_y, origin_x, origin_y, data, method="linear", par
|
|
90
90
|
return np.array(interpolated_data)
|
91
91
|
|
92
92
|
|
93
|
+
class ParallelExecutor:
|
94
|
+
"""
|
95
|
+
通用并行计算类,支持多进程和多线程模式。
|
96
|
+
|
97
|
+
使用说明:
|
98
|
+
1. 创建实例时选择模式:
|
99
|
+
- mode="process" 使用多进程(适合 CPU 密集型任务)。
|
100
|
+
- mode="thread" 使用多线程(适合 IO 密集型任务)。
|
101
|
+
|
102
|
+
2. 调用 run 方法:
|
103
|
+
- 参数 func:需要并行执行的函数。
|
104
|
+
- 参数 param_list:参数列表,每个元素是传递给 func 的参数元组。
|
105
|
+
|
106
|
+
示例:
|
107
|
+
# 示例 1:计算平方
|
108
|
+
def compute_square(x):
|
109
|
+
return x * x
|
110
|
+
|
111
|
+
params = [(i,) for i in range(10)]
|
112
|
+
executor = ParallelExecutor(mode="process", max_workers=4)
|
113
|
+
results = executor.run(compute_square, params)
|
114
|
+
print("Results:", results)
|
115
|
+
|
116
|
+
# 示例 2:计算两数之和
|
117
|
+
def compute_sum(a, b):
|
118
|
+
return a + b
|
119
|
+
|
120
|
+
params = [(1, 2), (3, 4), (5, 6)]
|
121
|
+
executor = ParallelExecutor(mode="thread", max_workers=2)
|
122
|
+
results = executor.run(compute_sum, params)
|
123
|
+
print("Results:", results)
|
124
|
+
|
125
|
+
参数:
|
126
|
+
mode (str): 并行模式,"process" 表示多进程,"thread" 表示多线程。
|
127
|
+
max_workers (int): 最大并行工作数,默认为 CPU 核心数减 2。
|
128
|
+
"""
|
129
|
+
|
130
|
+
def __init__(self, mode="process", max_workers=mp.cpu_count() - 2):
|
131
|
+
self.mode = mode
|
132
|
+
self.max_workers = max_workers
|
133
|
+
self.executor = ProcessPoolExecutor if mode == "process" else ThreadPoolExecutor
|
134
|
+
|
135
|
+
def run(self, func, param_list):
|
136
|
+
"""
|
137
|
+
并行运行指定函数,并确保结果顺序与输入参数顺序一致。
|
138
|
+
|
139
|
+
参数:
|
140
|
+
func (callable): 需要并行执行的函数。
|
141
|
+
param_list (list): 参数列表,每个元素是传递给 func 的参数元组。
|
142
|
+
|
143
|
+
返回:
|
144
|
+
results (list): 按输入顺序返回的结果。
|
145
|
+
"""
|
146
|
+
results = [None] * len(param_list) # 预分配结果数组
|
147
|
+
|
148
|
+
with self.executor(max_workers=self.max_workers) as executor:
|
149
|
+
# 提交任务并保存其索引
|
150
|
+
future_to_index = {executor.submit(func, *params): idx for idx, params in enumerate(param_list)}
|
151
|
+
|
152
|
+
for future in future_to_index:
|
153
|
+
idx = future_to_index[future] # 获取原始索引
|
154
|
+
results[idx] = future.result() # 将结果存放到对应位置
|
155
|
+
|
156
|
+
return results
|
157
|
+
|
158
|
+
|
159
|
+
# ---------------------------------------------------------------------------------- not used below ----------------------------------------------------------------------------------
|
93
160
|
# ** 高维插值函数,插值最后两个维度
|
94
161
|
def interp_2d_20241213(target_x, target_y, origin_x, origin_y, data, method="linear"):
|
95
162
|
"""
|
@@ -228,8 +295,25 @@ def interp_2d_parallel_20241213(target_x, target_y, origin_x, origin_y, data, me
|
|
228
295
|
return interpolated_data
|
229
296
|
|
230
297
|
|
298
|
+
def _test_sum(a,b):
|
299
|
+
return a+b
|
300
|
+
|
301
|
+
|
231
302
|
if __name__ == "__main__":
|
232
|
-
|
303
|
+
# 参数列表:每个参数是元组
|
304
|
+
params_list = [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
|
305
|
+
|
306
|
+
# 创建并行执行器
|
307
|
+
executor = ParallelExecutor()
|
308
|
+
|
309
|
+
# 并行运行
|
310
|
+
results = executor.run(_test_sum, params_list)
|
311
|
+
|
312
|
+
# 验证结果顺序
|
313
|
+
print("Params:", params_list)
|
314
|
+
print("Results:", results)
|
315
|
+
pass
|
316
|
+
""" import time
|
233
317
|
|
234
318
|
import matplotlib.pyplot as plt
|
235
319
|
|
@@ -263,4 +347,4 @@ if __name__ == "__main__":
|
|
263
347
|
plt.figure()
|
264
348
|
plt.contourf(target_x, target_y, interpolated_data[0, 0, :, :])
|
265
349
|
plt.colorbar()
|
266
|
-
plt.show()
|
350
|
+
plt.show() """
|
oafuncs/oa_draw.py
CHANGED
@@ -13,7 +13,7 @@ SystemInfo: Windows 11
|
|
13
13
|
Python Version: 3.11
|
14
14
|
"""
|
15
15
|
|
16
|
-
|
16
|
+
|
17
17
|
import warnings
|
18
18
|
|
19
19
|
import cartopy.crs as ccrs
|
@@ -23,9 +23,8 @@ import matplotlib.pyplot as plt
|
|
23
23
|
import numpy as np
|
24
24
|
import xarray as xr
|
25
25
|
from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter
|
26
|
-
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
27
26
|
|
28
|
-
__all__ = ["fig_minus", "
|
27
|
+
__all__ = ["fig_minus", "gif", "add_cartopy", "add_gridlines", "MidpointNormalize", "add_lonlat_unit", "contour", "contourf", "quiver"]
|
29
28
|
|
30
29
|
warnings.filterwarnings("ignore")
|
31
30
|
|
@@ -76,15 +75,18 @@ def fig_minus(ax_x=None, ax_y=None, cbar=None, decimal=None, add_space=False):
|
|
76
75
|
|
77
76
|
|
78
77
|
# ** 将生成图片/已有图片制作成动图
|
79
|
-
def
|
78
|
+
def gif(image_list: list, gif_name: str, duration=0.2): # 制作动图,默认间隔0.2
|
80
79
|
"""
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
80
|
+
Description
|
81
|
+
Make gif from images
|
82
|
+
Parameters
|
83
|
+
image_list : list, list of images
|
84
|
+
gif_name : str, name of gif
|
85
|
+
duration : float, duration of each frame
|
86
|
+
Returns
|
87
|
+
None
|
88
|
+
Example
|
89
|
+
gif(["1.png", "2.png"], "test.gif", duration=0.2)
|
88
90
|
"""
|
89
91
|
import imageio.v2 as imageio
|
90
92
|
|
@@ -150,7 +152,6 @@ def add_gridlines(ax, projection=ccrs.PlateCarree(), color="k", alpha=0.5, lines
|
|
150
152
|
|
151
153
|
# ** 添加地图
|
152
154
|
def add_cartopy(ax, lon=None, lat=None, projection=ccrs.PlateCarree(), gridlines=True, landcolor="lightgrey", oceancolor="lightblue", cartopy_linewidth=0.5):
|
153
|
-
|
154
155
|
# add coastlines
|
155
156
|
ax.add_feature(cfeature.LAND, facecolor=landcolor)
|
156
157
|
ax.add_feature(cfeature.OCEAN, facecolor=oceancolor)
|
@@ -201,141 +202,68 @@ class MidpointNormalize(mpl.colors.Normalize):
|
|
201
202
|
|
202
203
|
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
203
204
|
|
204
|
-
|
205
|
-
|
206
|
-
class _MyFormatter(mpl.ticker.ScalarFormatter):
|
207
|
-
def __init__(self, cticks, fmt=None, useOffset=True, useMathText=True):
|
208
|
-
mpl.ticker.ScalarFormatter.__init__(self, useOffset, useMathText)
|
209
|
-
self.cticks = cticks
|
210
|
-
self.fmt = fmt
|
211
|
-
self.vmin = min(cticks)
|
212
|
-
self.vmax = max(cticks)
|
213
|
-
self.p_n = self.vmin < 0 and self.vmax > 0
|
214
|
-
self.magnitude_min = int(math.modf(math.log10(min(abs(cticks[cticks != 0]))))[1])
|
215
|
-
self.magnitude_max = int(math.modf(math.log10(max(abs(cticks))))[1])
|
216
|
-
# print(self.vmin, self.vmax)
|
217
|
-
|
218
|
-
def __call__(self, x, pos):
|
219
|
-
if ((abs(x) < 1e-2) or (abs(x) > 1e4)) and x != 0:
|
220
|
-
if self.magnitude_max - self.magnitude_min == 1 and (int(math.modf(math.log10(abs(x)))[1]) == self.magnitude_min):
|
221
|
-
a, b = "{:.1e}".format(x).split("e")
|
222
|
-
a = float(a) / 10
|
223
|
-
b = int(b) + 1
|
224
|
-
else:
|
225
|
-
a, b = "{:.2e}".format(x).split("e")
|
226
|
-
a = float(a)
|
227
|
-
b = int(b)
|
228
|
-
# return '${}{} \\times 10^{{{}}}$'.format(' ' if (self.p_n and x > 0) else '', a, b)
|
229
|
-
return "${}{:.2f}$".format(" " if (self.p_n and x > 0) else "", a)
|
230
|
-
elif x == 0:
|
231
|
-
return "0"
|
232
|
-
else:
|
233
|
-
return mpl.ticker.ScalarFormatter.__call__(self, x, pos)
|
234
|
-
|
235
|
-
|
236
|
-
# ** 绘制单张填色图
|
237
|
-
def plot_contourf(pic_data, picname=None, c_map="rainbow", minmax=None, labels=None, ticks_space=None, ticks=None, figsize=(12, 9)):
|
205
|
+
# ** 绘制填色图
|
206
|
+
def contourf(data,x=None,y=None,cmap='coolwarm',show=True,store=None,cartopy=False):
|
238
207
|
"""
|
239
|
-
|
240
|
-
|
241
|
-
param
|
242
|
-
param
|
243
|
-
param
|
244
|
-
param
|
245
|
-
param
|
246
|
-
param
|
247
|
-
param
|
248
|
-
|
208
|
+
Description: 绘制填色图
|
209
|
+
|
210
|
+
param {*} data : 二维数据
|
211
|
+
param {*} x : x轴坐标
|
212
|
+
param {*} y : y轴坐标
|
213
|
+
param {*} cmap : 颜色映射
|
214
|
+
param {*} show : 是否显示
|
215
|
+
param {*} store : 是否保存
|
216
|
+
param {*} cartopy : 是否使用cartopy
|
217
|
+
|
218
|
+
return {*}
|
249
219
|
"""
|
250
|
-
|
251
|
-
if
|
252
|
-
|
220
|
+
data = np.array(data)
|
221
|
+
if x is None or y is None:
|
222
|
+
x = np.arange(data.shape[1])
|
223
|
+
y = np.arange(data.shape[0])
|
224
|
+
if cartopy:
|
225
|
+
fig, ax = plt.subplots(subplot_kw={'projection': ccrs.PlateCarree()})
|
226
|
+
add_cartopy(ax, lon=x, lat=y)
|
227
|
+
ax.contourf(x, y, data, transform=ccrs.PlateCarree(), cmap=cmap)
|
253
228
|
else:
|
254
|
-
|
255
|
-
|
256
|
-
|
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)
|
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
|
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)
|
260
|
-
|
261
|
-
shape = np.array(pic_data).shape
|
262
|
-
x, y = np.meshgrid(np.arange(shape[1]), np.arange(shape[0]))
|
263
|
-
|
264
|
-
fig, ax = plt.subplots(figsize=figsize)
|
265
|
-
flag_lc = levels is not None and cticks is not None
|
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")
|
268
|
-
"""%.3g采用的是自动调整格式,也可设置为%.3f,则改为3位小数"""
|
269
|
-
|
270
|
-
# 将格式化器设置为自定义的函数
|
271
|
-
class_cticks = np.array(cb.get_ticks())
|
272
|
-
# print(class_cticks)
|
273
|
-
cct = abs(class_cticks[class_cticks != 0])
|
274
|
-
if (min(cct) < 1e-2) or max(cct) > 1e4: # 判断是否需要采用科学计数法
|
275
|
-
cb.formatter = _MyFormatter(class_cticks)
|
276
|
-
cb.update_ticks()
|
277
|
-
|
278
|
-
if labels is not None:
|
279
|
-
cb.set_label(labels["c"])
|
280
|
-
plt.xlabel(labels["x"])
|
281
|
-
plt.ylabel(labels["y"])
|
282
|
-
if ticks_space is not None and ticks is not None:
|
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"])
|
285
|
-
|
286
|
-
plt.title("Min: {:.3g}, Max: {:.3g}".format(pic_data.min(), pic_data.max()))
|
287
|
-
|
288
|
-
plt.savefig(picname, bbox_inches="tight") if picname is not None else plt.show()
|
289
|
-
# plt.show()
|
290
|
-
plt.clf()
|
291
|
-
# 关闭当前figure
|
229
|
+
plt.contourf(x, y, data, cmap=cmap)
|
230
|
+
plt.colorbar()
|
231
|
+
plt.savefig(store, dpi=600, bbox_inches="tight") if store else plt.show()
|
292
232
|
plt.close()
|
293
233
|
|
294
234
|
|
295
|
-
# **
|
296
|
-
def
|
235
|
+
# ** 绘制等值线图
|
236
|
+
def contour(data, x=None, y=None, cmap="coolwarm", show=True, store=None, cartopy=False):
|
297
237
|
"""
|
298
|
-
|
299
|
-
|
300
|
-
param
|
301
|
-
param
|
302
|
-
param
|
303
|
-
param
|
304
|
-
|
238
|
+
Description: 绘制等值线图
|
239
|
+
|
240
|
+
param {*} data : 二维数据
|
241
|
+
param {*} x : x轴坐标
|
242
|
+
param {*} y : y轴坐标
|
243
|
+
param {*} cmap : 颜色映射
|
244
|
+
param {*} show : 是否显示
|
245
|
+
param {*} store : 是否保存
|
246
|
+
param {*} cartopy : 是否使用cartopy
|
247
|
+
|
248
|
+
return {*}
|
305
249
|
"""
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
return f"{degrees}°{direction}" if x != 0 and x != 180 else f"{degrees}°"
|
319
|
-
|
320
|
-
def format_latitude(y):
|
321
|
-
if y > 90:
|
322
|
-
y -= 180
|
323
|
-
degrees = int(abs(y))
|
324
|
-
direction = "N" if y >= 0 else "S"
|
325
|
-
return f"{degrees}°{direction}" if y != 0 else f"{degrees}°"
|
326
|
-
|
327
|
-
plt.contourf(data, cmap=c_map)
|
328
|
-
x_space = int(len(lon) * interval / (lon[-1] - lon[0]))
|
329
|
-
y_space = int(len(lat) * interval / (lat[-1] - lat[0]))
|
330
|
-
plt.xticks(np.arange(0, len(lon), x_space), [format_longitude(lon[i]) for i in range(0, len(lon), x_space)])
|
331
|
-
plt.yticks(np.arange(0, len(lat), y_space), [format_latitude(lat[i]) for i in range(0, len(lat), y_space)])
|
332
|
-
plt.colorbar()
|
333
|
-
plt.savefig(picname, bbox_inches="tight") if picname is not None else plt.show()
|
250
|
+
data = np.array(data)
|
251
|
+
if x is None or y is None:
|
252
|
+
x = np.arange(data.shape[1])
|
253
|
+
y = np.arange(data.shape[0])
|
254
|
+
if cartopy:
|
255
|
+
fig, ax = plt.subplots(subplot_kw={"projection": ccrs.PlateCarree()})
|
256
|
+
add_cartopy(ax, lon=x, lat=y)
|
257
|
+
cr = ax.contour(x, y, data, transform=ccrs.PlateCarree(), cmap=cmap)
|
258
|
+
else:
|
259
|
+
cr = plt.contour(x, y, data, cmap=cmap)
|
260
|
+
plt.clabel(cr, inline=True, fontsize=10)
|
261
|
+
plt.savefig(store, dpi=600, bbox_inches="tight") if store else plt.show()
|
334
262
|
plt.close()
|
335
263
|
|
336
264
|
|
337
265
|
# ** 绘制矢量场
|
338
|
-
def
|
266
|
+
def quiver(u, v, lon, lat, picname=None, cmap="coolwarm", scale=0.25, width=0.002, x_space=5, y_space=5):
|
339
267
|
"""
|
340
268
|
param {*} u : 二维数据
|
341
269
|
param {*} v : 二维数据
|
@@ -392,122 +320,6 @@ def plot_quiver(u, v, lon, lat, picname=None, cmap="coolwarm", scale=0.25, width
|
|
392
320
|
plt.close()
|
393
321
|
|
394
322
|
|
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
|
-
"""
|
398
|
-
param {*} data : 二维数据
|
399
|
-
param {*} lon : 经度
|
400
|
-
param {*} lat : 纬度
|
401
|
-
param {*} picname : 图片保存的文件名(含路径)
|
402
|
-
param {*} cmap : 颜色映射,默认rainbow
|
403
|
-
param {*} cn_fill_num : 等值线数量
|
404
|
-
param {*} fig_size : 图片大小,默认(12,9)
|
405
|
-
param {*} title : 图片标题
|
406
|
-
param {*} land_color : 陆地颜色
|
407
|
-
param {*} ocean_color : 海洋颜色
|
408
|
-
return {*} 无返回值
|
409
|
-
"""
|
410
|
-
if len(lon.shape) == 2:
|
411
|
-
lon = lon[0, :]
|
412
|
-
if len(lat.shape) == 2:
|
413
|
-
lat = lat[:, 0]
|
414
|
-
|
415
|
-
data_max = np.nanmax(data)
|
416
|
-
data_min = np.nanmin(data)
|
417
|
-
levels = np.linspace(data_min, data_max, cn_fill_num)
|
418
|
-
cbar_ticks = np.linspace(data_min, data_max, 9)
|
419
|
-
|
420
|
-
fig = plt.figure(figsize=fig_size)
|
421
|
-
proj = ccrs.PlateCarree()
|
422
|
-
ax = fig.add_subplot(1, 1, 1, projection=proj)
|
423
|
-
|
424
|
-
ax.set_extent([lon[0], lon[-1], lat[0], lat[-1]], crs=proj)
|
425
|
-
|
426
|
-
ax.add_feature(cfeature.LAND, facecolor=land_color, edgecolor="k")
|
427
|
-
ax.add_feature(cfeature.COASTLINE, linewidth=0.5)
|
428
|
-
# ax.add_feature(cfeature.BORDERS, linewidth=0.5, linestyle=":") # 加载国界线
|
429
|
-
|
430
|
-
ax.set_xticks(np.arange(lon[0], lon[-1] + 1e-5, 5), crs=proj)
|
431
|
-
ax.set_yticks(np.arange(lat[0], lat[-1] + 1e-5, 5), crs=proj)
|
432
|
-
lon_formatter = LongitudeFormatter(zero_direction_label=True)
|
433
|
-
ax.xaxis.set_major_formatter(lon_formatter)
|
434
|
-
lat_formatter = LatitudeFormatter()
|
435
|
-
ax.yaxis.set_major_formatter(lat_formatter)
|
436
|
-
# plt.title(title, fontsize=16)
|
437
|
-
|
438
|
-
cmap = plt.get_cmap(cmap)
|
439
|
-
X, Y = np.meshgrid(lon, lat)
|
440
|
-
|
441
|
-
# Fill color for land and ocean
|
442
|
-
# ax.background_patch.set_facecolor(ocean_color)
|
443
|
-
ax.patch.set_facecolor(ocean_color)
|
444
|
-
ax.add_feature(cfeature.LAND, facecolor=land_color)
|
445
|
-
|
446
|
-
cticks = cbar_ticks
|
447
|
-
norm = mpl.colors.BoundaryNorm(cticks, cmap.N)
|
448
|
-
|
449
|
-
cnplot = ax.contourf(X, Y, data, levels=levels, cmap=cmap, norm=norm, transform=proj, extend="both", alpha=1, zorder=0)
|
450
|
-
# cllevels = np.linspace(data_min, data_max, 9)
|
451
|
-
# clplot = ax.contour(X, Y, data, levels=levels[9::10], colors='k', linewidths=0.5, transform=proj, zorder=1, alpha=0.8, linestyle='--')
|
452
|
-
# 添加色标,并选择位置
|
453
|
-
divider = make_axes_locatable(ax)
|
454
|
-
location = 3
|
455
|
-
if location == 1: # 左侧
|
456
|
-
cax = divider.new_horizontal(size="5%", pad=1, axes_class=plt.Axes, pack_start=True)
|
457
|
-
fig.add_axes(cax)
|
458
|
-
cbar = plt.colorbar(cnplot, cax=cax, orientation="vertical", extend="both")
|
459
|
-
elif location == 2: # 下方
|
460
|
-
cax = divider.new_vertical(size="5%", pad=0.3, axes_class=plt.Axes, pack_start=True)
|
461
|
-
fig.add_axes(cax)
|
462
|
-
cbar = plt.colorbar(cnplot, cax=cax, orientation="horizontal", extend="both")
|
463
|
-
elif location == 3: # 右侧
|
464
|
-
cax = divider.new_horizontal(size="5%", pad=0.1, axes_class=plt.Axes)
|
465
|
-
fig.add_axes(cax)
|
466
|
-
# cbar = plt.colorbar(cnplot, cax=cax, orientation='vertical', extend='both', format='%.0f')
|
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")
|
470
|
-
else: # 上方
|
471
|
-
cax = divider.new_vertical(size="5%", pad=0.2, axes_class=plt.Axes)
|
472
|
-
fig.add_axes(cax)
|
473
|
-
cbar = plt.colorbar(cnplot, cax=cax, orientation="horizontal", extend="both")
|
474
|
-
cbar.ax.tick_params(labelsize=10)
|
475
|
-
cbar.ax.xaxis.set_tick_params(direction="in", width=1, length=2)
|
476
|
-
# 添加cbar_ticks
|
477
|
-
# cbar.set_ticks(np.arange(round(levels[0]), round(levels[-1]), round((levels[-1]-levels[0])/9))) # 设置色标刻度
|
478
|
-
# cbar.set_ticks(cbar_ticks) # 设置色标刻度
|
479
|
-
|
480
|
-
cbar.set_ticks(cticks)
|
481
|
-
# cbar.ax.ticks = np.linspace(data_min, data_max, 8)
|
482
|
-
# cbar.set_ticks(np.arange(round(levels[0]), round(levels[-1]), round((levels[-1]-levels[0])/9))) # 设置色标刻度
|
483
|
-
|
484
|
-
# 单独设置label
|
485
|
-
cbar.set_label(title, fontsize=10, weight="bold")
|
486
|
-
# cax.set_position([0.1, 0.2, 0.02, 0.6]) # 调整色标位置
|
487
|
-
fig.savefig(picname, bbox_inches="tight", dpi=600) if picname is not None else plt.show()
|
488
|
-
plt.close()
|
489
|
-
|
490
|
-
|
491
323
|
|
492
324
|
if __name__ == "__main__":
|
493
|
-
|
494
|
-
data = np.random.randn(100, 100)
|
495
|
-
picname = "test.png"
|
496
|
-
plot_contourf(data, picname, c_map="rainbow", minmax=None, labels=None, ticks_space=None, ticks=None, figsize=(12, 9))
|
497
|
-
# ** 绘制矢量场
|
498
|
-
u = np.random.randn(100, 100)
|
499
|
-
v = np.random.randn(100, 100)
|
500
|
-
lon = np.linspace(0, 360, 100)
|
501
|
-
lat = np.linspace(-90, 90, 100)
|
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)
|
504
|
-
# ** 绘制经纬度填色图
|
505
|
-
data = np.random.randn(100, 100)
|
506
|
-
lon = np.linspace(0, 360, 100)
|
507
|
-
lat = np.linspace(-90, 90, 100)
|
508
|
-
picname = "test.png"
|
509
|
-
plot_contourf_lonlat(data, lon, lat, interval=5, picname=picname, c_map="rainbow")
|
510
|
-
# ** 制作动图
|
511
|
-
image_list = ["test1.png", "test2.png", "test3.png"]
|
512
|
-
gif_name = "test.gif"
|
513
|
-
create_gif(image_list, gif_name, duration=0.2)
|
325
|
+
pass
|
oafuncs/oa_help.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
Author: Liu Kun && 16031215@qq.com
|
5
5
|
Date: 2024-10-06 19:25:29
|
6
6
|
LastEditors: Liu Kun && 16031215@qq.com
|
7
|
-
LastEditTime:
|
7
|
+
LastEditTime: 2025-01-01 21:09:58
|
8
8
|
FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_help.py
|
9
9
|
Description:
|
10
10
|
EditPlatform: vscode
|
@@ -14,29 +14,124 @@ Python Version: 3.12
|
|
14
14
|
"""
|
15
15
|
|
16
16
|
import oafuncs
|
17
|
+
import pkgutil
|
18
|
+
import importlib
|
19
|
+
from rich import print
|
17
20
|
|
18
|
-
__all__ = ["query", "use"]
|
21
|
+
__all__ = ["query", "use", "log"]
|
19
22
|
|
20
23
|
|
21
24
|
def query():
|
22
25
|
"""
|
23
|
-
|
24
|
-
|
26
|
+
Description:
|
27
|
+
Show the number of functions and the list of functions in the module.
|
28
|
+
Example:
|
29
|
+
query()
|
25
30
|
"""
|
26
31
|
funcs = [func for func in dir(oafuncs) if callable(getattr(oafuncs, func))]
|
27
32
|
print("函数数量:")
|
28
33
|
print(len(funcs))
|
29
34
|
print("函数列表:")
|
30
35
|
print(funcs)
|
36
|
+
|
37
|
+
# 判断同名函数个数
|
38
|
+
func_dict = dict()
|
39
|
+
for func in funcs:
|
40
|
+
func_dict[func] = 0
|
41
|
+
for module_info in pkgutil.iter_modules(oafuncs.__path__, oafuncs.__name__ + "."):
|
42
|
+
module = importlib.import_module(module_info.name)
|
43
|
+
for func in funcs:
|
44
|
+
if hasattr(module, func):
|
45
|
+
func_dict[func] += 1
|
46
|
+
print("同名函数:")
|
47
|
+
for func, count in func_dict.items():
|
48
|
+
if count > 1:
|
49
|
+
print(f"{func} : {count}")
|
31
50
|
|
32
51
|
|
33
|
-
def
|
52
|
+
def _use_single(func="get_var", module="oafuncs"):
|
34
53
|
"""
|
35
54
|
description: 查看函数的模块全路径和函数提示
|
36
55
|
param {func} : 函数名
|
37
56
|
example: use('get_var')
|
38
57
|
"""
|
58
|
+
module = importlib.import_module(module)
|
39
59
|
print("模块全路径:")
|
40
|
-
print(getattr(
|
60
|
+
print(getattr(module, func).__module__ + "." + func)
|
41
61
|
print("函数提示:")
|
42
|
-
print(getattr(
|
62
|
+
print(getattr(module, func).__doc__)
|
63
|
+
|
64
|
+
|
65
|
+
def use(func_name='log'):
|
66
|
+
"""
|
67
|
+
Description:
|
68
|
+
Show the full path and help of the function.
|
69
|
+
Args:
|
70
|
+
func_name: The name of the function.
|
71
|
+
Example:
|
72
|
+
use('log')
|
73
|
+
"""
|
74
|
+
found = False
|
75
|
+
# 假设oafuncs是一个包
|
76
|
+
if hasattr(oafuncs, "__path__"):
|
77
|
+
print("-" * 40) # 分隔线
|
78
|
+
# 遍历包内的所有模块
|
79
|
+
for module_info in pkgutil.iter_modules(oafuncs.__path__, oafuncs.__name__ + "."):
|
80
|
+
module_name = module_info.name
|
81
|
+
module = importlib.import_module(module_name)
|
82
|
+
if hasattr(module, func_name):
|
83
|
+
found = True
|
84
|
+
func_obj = getattr(module, func_name)
|
85
|
+
print(f"[bold purple]模块全路径:\n[bold green]{func_obj.__module__}.{func_name}\n")
|
86
|
+
help(func_obj)
|
87
|
+
""" doc = func_obj.__doc__
|
88
|
+
print("函数提示:")
|
89
|
+
if doc:
|
90
|
+
print(doc)
|
91
|
+
else:
|
92
|
+
print("无文档字符串") """
|
93
|
+
print("-" * 40) # 分隔线
|
94
|
+
else:
|
95
|
+
# 如果oafuncs只是一个模块,直接查找
|
96
|
+
if hasattr(oafuncs, func_name):
|
97
|
+
found = True
|
98
|
+
func_obj = getattr(oafuncs, func_name)
|
99
|
+
print(f"模块全路径:\n{func_obj.__module__}.{func_name}\n")
|
100
|
+
help(func_obj)
|
101
|
+
""" doc = func_obj.__doc__
|
102
|
+
print("函数提示:")
|
103
|
+
if doc:
|
104
|
+
print(doc)
|
105
|
+
else:
|
106
|
+
print("无文档字符串") """
|
107
|
+
if not found:
|
108
|
+
print(f"在oafuncs中没有找到名为 '{func_name}' 的函数。")
|
109
|
+
|
110
|
+
|
111
|
+
def log():
|
112
|
+
"""
|
113
|
+
Description:
|
114
|
+
Show the update log.
|
115
|
+
Example:
|
116
|
+
log()
|
117
|
+
"""
|
118
|
+
print("更新日志:")
|
119
|
+
print(
|
120
|
+
"""
|
121
|
+
2025-01-04
|
122
|
+
1. 下调Python支持版本到3.7,但未经过测试
|
123
|
+
2. 优化了部分函数说明
|
124
|
+
"""
|
125
|
+
)
|
126
|
+
print(
|
127
|
+
"""
|
128
|
+
2025-01-01
|
129
|
+
1. 添加了log函数,可以查看更新日志。
|
130
|
+
2. 修改部分函数名,尽可能简化函数名。
|
131
|
+
"""
|
132
|
+
)
|
133
|
+
|
134
|
+
|
135
|
+
if __name__ == "__main__":
|
136
|
+
# use("find_file")
|
137
|
+
query()
|
oafuncs/oa_nc.py
CHANGED
@@ -19,15 +19,20 @@ import netCDF4 as nc
|
|
19
19
|
import numpy as np
|
20
20
|
import xarray as xr
|
21
21
|
|
22
|
-
__all__ = ["get_var", "
|
22
|
+
__all__ = ["get_var", "extract", "save", "merge", "modify", "rename", "check_file", "convert_longitude", "isel"]
|
23
23
|
|
24
24
|
|
25
25
|
def get_var(file, *vars):
|
26
26
|
"""
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
Description:
|
28
|
+
Read variables from nc file
|
29
|
+
Parameters:
|
30
|
+
file: str, file path
|
31
|
+
*vars: str, variable name or variable names; should be in same size
|
32
|
+
Example:
|
33
|
+
datas = get_var(file_ecm, 'h', 't', 'u', 'v')
|
34
|
+
Return:
|
35
|
+
datas: list, variable data
|
31
36
|
"""
|
32
37
|
ds = xr.open_dataset(file)
|
33
38
|
datas = []
|
@@ -38,17 +43,17 @@ def get_var(file, *vars):
|
|
38
43
|
return datas
|
39
44
|
|
40
45
|
|
41
|
-
def
|
46
|
+
def extract(file, varname, only_value=True):
|
42
47
|
"""
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
Description:
|
49
|
+
Extract variables from nc file
|
50
|
+
Return the variable and coordinate dictionary
|
51
|
+
Parameters:
|
52
|
+
file: str, file path
|
53
|
+
varname: str, variable name
|
54
|
+
only_value: bool, whether to keep only the value of the variable and dimension
|
55
|
+
Example:
|
56
|
+
data, dimdict = extract('test.nc', 'h')
|
52
57
|
"""
|
53
58
|
ds = xr.open_dataset(file)
|
54
59
|
vardata = ds[varname]
|
@@ -101,20 +106,20 @@ def _calculate_scale_and_offset(data, n=16):
|
|
101
106
|
return scale_factor, add_offset
|
102
107
|
|
103
108
|
|
104
|
-
def
|
109
|
+
def save(file, data, varname=None, coords=None, mode="w", scale_offset_switch=True, compile_switch=True):
|
105
110
|
"""
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
111
|
+
Description:
|
112
|
+
Write data to NetCDF file
|
113
|
+
Parameters:
|
114
|
+
file: str, file path
|
115
|
+
data: data
|
116
|
+
varname: str, variable name
|
117
|
+
coords: dict, coordinates, key is the dimension name, value is the coordinate data
|
118
|
+
mode: str, write mode, 'w' for write, 'a' for append
|
119
|
+
scale_offset_switch: bool, whether to use scale_factor and add_offset, default is True
|
120
|
+
compile_switch: bool, whether to use compression parameters, default is True
|
121
|
+
Example:
|
122
|
+
save(r'test.nc', data, 'u', {'time': np.linspace(0, 120, 100), 'lev': np.linspace(0, 120, 50)}, 'a')
|
118
123
|
"""
|
119
124
|
# 设置压缩参数
|
120
125
|
kwargs = {"zlib": True, "complevel": 4} if compile_switch else {}
|
@@ -175,22 +180,23 @@ def write2nc(file, data, varname=None, coords=None, mode="w", scale_offset_switc
|
|
175
180
|
var.setncattr(key, value)
|
176
181
|
|
177
182
|
|
178
|
-
def
|
183
|
+
def merge(file_list, var_name=None, dim_name=None, target_filename=None):
|
179
184
|
"""
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
185
|
+
Description:
|
186
|
+
Merge variables from multiple NetCDF files along a specified dimension and write to a new file.
|
187
|
+
If var_name is a string, it is considered a single variable; if it is a list and has only one element, it is also a single variable;
|
188
|
+
If the list has more than one element, it is a multi-variable; if var_name is None, all variables are merged.
|
189
|
+
|
190
|
+
Parameters:
|
191
|
+
file_list: List of NetCDF file paths
|
192
|
+
var_name: Name of the variable to be extracted or a list of variable names, default is None, which means all variables are extracted
|
193
|
+
dim_name: Dimension name used for merging
|
194
|
+
target_filename: Target file name after merging
|
195
|
+
|
196
|
+
Example:
|
197
|
+
merge(file_list, var_name='u', dim_name='time', target_filename='merged.nc')
|
198
|
+
merge(file_list, var_name=['u', 'v'], dim_name='time', target_filename='merged.nc')
|
199
|
+
merge(file_list, var_name=None, dim_name='time', target_filename='merged.nc')
|
194
200
|
"""
|
195
201
|
if isinstance(file_list, str):
|
196
202
|
file_list = [file_list]
|
@@ -248,16 +254,18 @@ def merge5nc(file_list, var_name=None, dim_name=None, target_filename=None):
|
|
248
254
|
print(f'File "{target_filename}" has been created.')
|
249
255
|
|
250
256
|
|
251
|
-
def
|
252
|
-
"""
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
257
|
+
def _modify_var(nc_file_path, variable_name, new_value):
|
258
|
+
"""
|
259
|
+
Description:
|
260
|
+
Modify the value of a variable in a NetCDF file using the netCDF4 library.
|
261
|
+
|
262
|
+
Parameters:
|
263
|
+
nc_file_path (str): The path to the NetCDF file.
|
264
|
+
variable_name (str): The name of the variable to be modified.
|
265
|
+
new_value (numpy.ndarray): The new value of the variable.
|
266
|
+
|
267
|
+
Example:
|
268
|
+
modify_var('test.nc', 'u', np.random.rand(100, 50))
|
261
269
|
"""
|
262
270
|
try:
|
263
271
|
# Open the NetCDF file
|
@@ -272,16 +280,19 @@ def modify_var_value(nc_file_path, variable_name, new_value):
|
|
272
280
|
print(f"An error occurred while modifying variable {variable_name} in {nc_file_path}: {e}")
|
273
281
|
|
274
282
|
|
275
|
-
def
|
276
|
-
"""
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
283
|
+
def _modify_attr(nc_file_path, variable_name, attribute_name, attribute_value):
|
284
|
+
"""
|
285
|
+
Description:
|
286
|
+
Add or modify an attribute of a variable in a NetCDF file using the netCDF4 library.
|
287
|
+
|
288
|
+
Parameters:
|
289
|
+
nc_file_path (str): The path to the NetCDF file.
|
290
|
+
variable_name (str): The name of the variable to be modified.
|
291
|
+
attribute_name (str): The name of the attribute to be added or modified.
|
292
|
+
attribute_value (any): The value of the attribute.
|
293
|
+
|
294
|
+
Example:
|
295
|
+
modify_attr('test.nc', 'temperature', 'long_name', 'Temperature in Celsius')
|
285
296
|
"""
|
286
297
|
try:
|
287
298
|
ds = nc.Dataset(nc_file_path, "r+")
|
@@ -301,16 +312,39 @@ def modify_var_attr(nc_file_path, variable_name, attribute_name, attribute_value
|
|
301
312
|
raise RuntimeError(f"An error occurred: {e}")
|
302
313
|
|
303
314
|
|
304
|
-
def
|
315
|
+
def modify(nc_file,var_name,attr_name=None,new_value=None):
|
305
316
|
"""
|
306
|
-
|
317
|
+
Description:
|
318
|
+
Modify the value of a variable or the value of an attribute in a NetCDF file.
|
319
|
+
|
320
|
+
Parameters:
|
321
|
+
nc_file (str): The path to the NetCDF file.
|
322
|
+
var_name (str): The name of the variable to be modified.
|
323
|
+
attr_name (str): The name of the attribute to be modified. If None, the variable value will be modified.
|
324
|
+
new_value (any): The new value of the variable or attribute.
|
325
|
+
|
326
|
+
Example:
|
327
|
+
modify('test.nc', 'temperature', 'long_name', 'Temperature in Celsius')
|
328
|
+
modify('test.nc', 'temperature', None, np.random.rand(100, 50))
|
329
|
+
"""
|
330
|
+
if attr_name is None:
|
331
|
+
_modify_var(nc_file, var_name, new_value)
|
332
|
+
else:
|
333
|
+
_modify_attr(nc_file, var_name, attr_name, new_value)
|
334
|
+
|
335
|
+
|
336
|
+
def rename(ncfile_path, old_name, new_name):
|
337
|
+
"""
|
338
|
+
Description:
|
339
|
+
Rename a variable and/or dimension in a NetCDF file.
|
307
340
|
|
308
341
|
Parameters:
|
309
|
-
|
310
|
-
|
311
|
-
|
342
|
+
ncfile_path (str): The path to the NetCDF file.
|
343
|
+
old_name (str): The current name of the variable or dimension.
|
344
|
+
new_name (str): The new name to assign to the variable or dimension.
|
312
345
|
|
313
|
-
example:
|
346
|
+
example:
|
347
|
+
rename('test.nc', 'temperature', 'temp')
|
314
348
|
"""
|
315
349
|
try:
|
316
350
|
with nc.Dataset(ncfile_path, "r+") as dataset:
|
@@ -335,7 +369,18 @@ def rename_var_or_dim(ncfile_path, old_name, new_name):
|
|
335
369
|
print(f"An error occurred: {e}")
|
336
370
|
|
337
371
|
|
338
|
-
def
|
372
|
+
def check_file(ncfile, if_delete=False):
|
373
|
+
'''
|
374
|
+
Description:
|
375
|
+
Check if the NetCDF file is corrupted.
|
376
|
+
|
377
|
+
Parameters:
|
378
|
+
ncfile (str): The path to the NetCDF file.
|
379
|
+
if_delete (bool): Whether to delete the file if it is corrupted, default is False.
|
380
|
+
|
381
|
+
Returns:
|
382
|
+
bool: True if the file is not corrupted, False otherwise.
|
383
|
+
'''
|
339
384
|
if not os.path.exists(ncfile):
|
340
385
|
return False
|
341
386
|
|
@@ -365,19 +410,20 @@ def check_ncfile(ncfile, if_delete=False):
|
|
365
410
|
|
366
411
|
def convert_longitude(ds, lon_name="longitude", convert=180):
|
367
412
|
"""
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
413
|
+
Description:
|
414
|
+
Convert the longitude array to a specified range.
|
415
|
+
|
416
|
+
Parameters:
|
417
|
+
ds (xarray.Dataset): The xarray dataset containing the longitude data.
|
418
|
+
lon_name (str): The name of the longitude variable, default is "longitude".
|
419
|
+
convert (int): The target range to convert to, can be 180 or 360, default is 180.
|
420
|
+
|
421
|
+
Returns:
|
422
|
+
xarray.Dataset: The xarray dataset with the converted longitude.
|
377
423
|
"""
|
378
424
|
to_which = int(convert)
|
379
425
|
if to_which not in [180, 360]:
|
380
|
-
raise ValueError("
|
426
|
+
raise ValueError("convert value must be '180' or '360'")
|
381
427
|
|
382
428
|
if to_which == 180:
|
383
429
|
ds = ds.assign_coords({lon_name: (ds[lon_name] + 180) % 360 - 180})
|
@@ -387,18 +433,20 @@ def convert_longitude(ds, lon_name="longitude", convert=180):
|
|
387
433
|
return ds.sortby(lon_name)
|
388
434
|
|
389
435
|
|
390
|
-
def
|
436
|
+
def isel(ncfile, dim_name, slice_list):
|
391
437
|
"""
|
392
|
-
Description:
|
438
|
+
Description:
|
439
|
+
Choose the data by the index of the dimension
|
393
440
|
|
394
441
|
Parameters:
|
395
442
|
ncfile: str, the path of the netCDF file
|
396
443
|
dim_name: str, the name of the dimension
|
397
444
|
slice_list: list, the index of the dimension
|
398
445
|
|
399
|
-
|
400
|
-
|
401
|
-
|
446
|
+
Example:
|
447
|
+
slice_list = [[y*12+m for m in range(11,14)] for y in range(84)]
|
448
|
+
slice_list = [y * 12 + m for y in range(84) for m in range(11, 14)]
|
449
|
+
isel(ncfile, 'time', slice_list)
|
402
450
|
"""
|
403
451
|
ds = xr.open_dataset(ncfile)
|
404
452
|
slice_list = np.array(slice_list).flatten()
|
@@ -410,4 +458,4 @@ def nc_isel(ncfile, dim_name, slice_list):
|
|
410
458
|
|
411
459
|
if __name__ == "__main__":
|
412
460
|
data = np.random.rand(100, 50)
|
413
|
-
|
461
|
+
save(r"test.nc", data, "data", {"time": np.linspace(0, 120, 100), "lev": np.linspace(0, 120, 50)}, "a")
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: oafuncs
|
3
|
-
Version: 0.0.
|
4
|
-
Summary:
|
3
|
+
Version: 0.0.87
|
4
|
+
Summary: Oceanic and Atmospheric Functions
|
5
5
|
Home-page: https://github.com/Industry-Pays/OAFuncs
|
6
6
|
Author: Kun Liu
|
7
7
|
Author-email: liukun0312@stu.ouc.edu.cn
|
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
16
16
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
17
17
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
18
|
-
Requires-Python: >=3.
|
18
|
+
Requires-Python: >=3.7.0
|
19
19
|
Description-Content-Type: text/markdown
|
20
20
|
License-File: LICENSE.txt
|
21
21
|
Requires-Dist: matplotlib
|
@@ -1,12 +1,12 @@
|
|
1
1
|
oafuncs/__init__.py,sha256=glcIlhQ9xSK4WtL58dq7Od2S3JPqsuEyhUQ-VWO8hOc,1426
|
2
|
-
oafuncs/oa_cmap.py,sha256=
|
3
|
-
oafuncs/oa_data.py,sha256=
|
4
|
-
oafuncs/oa_draw.py,sha256=
|
2
|
+
oafuncs/oa_cmap.py,sha256=azVg9QR_IlG9lXCCXXVs1LS1kFci8yjxDmb_VA_TdTQ,7408
|
3
|
+
oafuncs/oa_data.py,sha256=2MkWCsESVPjZPnLnbQIwrBJUhcF9x-WXbZhni3I44ss,15617
|
4
|
+
oafuncs/oa_draw.py,sha256=PUk8DdGBUapCXrOVQ-d_DD6EccB_eHAX3r6jwrnQTk8,11126
|
5
5
|
oafuncs/oa_file.py,sha256=-AdRnFEtRTpIMXr5geYe5fEhyiMOFad5ethi_lF-Ogo,12277
|
6
|
-
oafuncs/oa_help.py,sha256=
|
7
|
-
oafuncs/oa_nc.py,sha256=
|
6
|
+
oafuncs/oa_help.py,sha256=DsX6rFPZ-ZMaexcyCXeGeB3h1zPScY6ijH-uLNVWidA,3988
|
7
|
+
oafuncs/oa_nc.py,sha256=b8pbiPSRDi7Te42UcnR0AlW1sQEVtn5VU9ERiAdX-yY,17501
|
8
8
|
oafuncs/oa_python.py,sha256=XPTP3o7zTFzfJR_YhsKfQksa3bSYwXsne9YxlJplCEA,3994
|
9
|
-
oafuncs/data_store/OAFuncs.png,sha256=
|
9
|
+
oafuncs/data_store/OAFuncs.png,sha256=w2pR7MUyeeWrT8BVTSy40EIRDIrfpdo1QvWvvjLOgjM,3258809
|
10
10
|
oafuncs/oa_down/User_Agent-list.txt,sha256=pazxSip8_lphEBOPHG902zmIBUg8sBKXgmqp_g6j_E4,661062
|
11
11
|
oafuncs/oa_down/__init__.py,sha256=pKPqxD0z09NEXWCemuemfgTct7Kcu3APPJqqB1FPXRM,565
|
12
12
|
oafuncs/oa_down/hycom_3hourly.py,sha256=wYOZrV5mZVSTfx6a5QLay8Jg2sL2x3sWKWmxwidRzMo,62928
|
@@ -19,8 +19,8 @@ oafuncs/oa_sign/ocean.py,sha256=xrW-rWD7xBWsB5PuCyEwQ1Q_RDKq2KCLz-LOONHgldU,5932
|
|
19
19
|
oafuncs/oa_sign/scientific.py,sha256=a4JxOBgm9vzNZKpJ_GQIQf7cokkraV5nh23HGbmTYKw,5064
|
20
20
|
oafuncs/oa_tool/__init__.py,sha256=IKOlqpWlb4cMDCtq2VKR_RTxQHDNqR_vfqqsOsp_lKQ,466
|
21
21
|
oafuncs/oa_tool/email.py,sha256=4lJxV_KUzhxgLYfVwYTqp0qxRugD7fvsZkXDe5WkUKo,3052
|
22
|
-
oafuncs-0.0.
|
23
|
-
oafuncs-0.0.
|
24
|
-
oafuncs-0.0.
|
25
|
-
oafuncs-0.0.
|
26
|
-
oafuncs-0.0.
|
22
|
+
oafuncs-0.0.87.dist-info/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
|
23
|
+
oafuncs-0.0.87.dist-info/METADATA,sha256=s_MdtiHoS3sPMPmK2J1se2gWXs34fA2tHSjQ4NqH-cs,3300
|
24
|
+
oafuncs-0.0.87.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109
|
25
|
+
oafuncs-0.0.87.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
|
26
|
+
oafuncs-0.0.87.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|