oafuncs 0.0.81__py2.py3-none-any.whl → 0.0.82__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/oa_data.py +107 -28
- oafuncs/oa_down/hycom_3hourly.py +151 -34
- oafuncs/oa_draw.py +148 -96
- oafuncs/oa_file.py +61 -50
- oafuncs/oa_nc.py +82 -114
- {oafuncs-0.0.81.dist-info → oafuncs-0.0.82.dist-info}/METADATA +1 -1
- oafuncs-0.0.82.dist-info/RECORD +24 -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/RECORD +0 -51
- {oafuncs-0.0.81.dist-info → oafuncs-0.0.82.dist-info}/LICENSE.txt +0 -0
- {oafuncs-0.0.81.dist-info → oafuncs-0.0.82.dist-info}/WHEEL +0 -0
- {oafuncs-0.0.81.dist-info → oafuncs-0.0.82.dist-info}/top_level.txt +0 -0
oafuncs/oa_file.py
CHANGED
@@ -1,38 +1,39 @@
|
|
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 15:07:13
|
6
6
|
LastEditors: Liu Kun && 16031215@qq.com
|
7
|
-
LastEditTime: 2024-12-
|
7
|
+
LastEditTime: 2024-12-13 16:28:56
|
8
8
|
FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_file.py
|
9
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 glob
|
18
17
|
import os
|
19
18
|
import re
|
20
19
|
import shutil
|
21
20
|
|
22
|
-
__all__ = [
|
21
|
+
__all__ = ["find_file", "link_file", "copy_file", "rename_file", "make_folder", "clear_folder", "remove_empty_folders", "remove", "file_size"]
|
23
22
|
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
# ** 查找文件,支持通配符
|
25
|
+
def find_file(parent_path, fname, mode="path"):
|
26
|
+
"""
|
27
|
+
description:
|
28
28
|
param {*} parent_path: The parent path where the files are located
|
29
29
|
param {*} fname: The file name pattern to search for
|
30
30
|
param {*} mode: 'path' to return the full path of the files, 'file' to return only the file names
|
31
31
|
return {*} A list of file paths or file names if files are found, None otherwise
|
32
|
-
|
32
|
+
"""
|
33
|
+
|
33
34
|
def natural_sort_key(s):
|
34
35
|
"""生成一个用于自然排序的键"""
|
35
|
-
return [int(text) if text.isdigit() else text.lower() for text in re.split(
|
36
|
+
return [int(text) if text.isdigit() else text.lower() for text in re.split("([0-9]+)", s)]
|
36
37
|
|
37
38
|
# 将parent_path和fname结合成完整的搜索路径
|
38
39
|
search_pattern = os.path.join(str(parent_path), fname)
|
@@ -48,7 +49,7 @@ def find_file(parent_path, fname, mode='path'):
|
|
48
49
|
matched_files = sorted(matched_files, key=natural_sort_key)
|
49
50
|
|
50
51
|
# 根据mode参数决定返回的内容
|
51
|
-
if mode ==
|
52
|
+
if mode == "file":
|
52
53
|
# 只返回文件名
|
53
54
|
result = [os.path.basename(file) for file in matched_files]
|
54
55
|
else: # 默认为'path'
|
@@ -58,8 +59,9 @@ def find_file(parent_path, fname, mode='path'):
|
|
58
59
|
return result
|
59
60
|
|
60
61
|
|
62
|
+
# ** 创建符号链接,支持通配符
|
61
63
|
def link_file(src_pattern, dst):
|
62
|
-
|
64
|
+
"""
|
63
65
|
# 描述:创建符号链接,支持通配符
|
64
66
|
# 使用示例
|
65
67
|
# link_file(r'/data/hejx/liukun/era5/*', r'/data/hejx/liukun/Test/')
|
@@ -67,12 +69,12 @@ def link_file(src_pattern, dst):
|
|
67
69
|
# link_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test')
|
68
70
|
param {*} src_pattern # 源文件或目录
|
69
71
|
param {*} dst # 目标文件或目录
|
70
|
-
|
72
|
+
"""
|
71
73
|
src_pattern = str(src_pattern)
|
72
74
|
# 使用glob.glob来处理可能包含通配符的src
|
73
75
|
src_files = glob.glob(src_pattern)
|
74
76
|
if not src_files:
|
75
|
-
raise FileNotFoundError(
|
77
|
+
raise FileNotFoundError("文件不存在: {}".format(src_pattern))
|
76
78
|
|
77
79
|
# 判断dst是路径还是包含文件名的路径
|
78
80
|
if os.path.isdir(dst):
|
@@ -84,7 +86,7 @@ def link_file(src_pattern, dst):
|
|
84
86
|
if os.path.exists(dst_file):
|
85
87
|
os.remove(dst_file)
|
86
88
|
os.symlink(src_file, dst_file)
|
87
|
-
print(f
|
89
|
+
print(f"创建符号链接: {src_file} -> {dst_file}")
|
88
90
|
else:
|
89
91
|
# 如果dst包含文件名,则创建链接后重命名
|
90
92
|
dst_dir = os.path.dirname(dst)
|
@@ -95,23 +97,24 @@ def link_file(src_pattern, dst):
|
|
95
97
|
if os.path.exists(dst_file):
|
96
98
|
os.remove(dst_file)
|
97
99
|
os.symlink(src_file, dst_file)
|
98
|
-
print(f
|
100
|
+
print(f"创建符号链接并重命名: {src_file} -> {dst_file}")
|
99
101
|
|
100
102
|
|
103
|
+
# ** 复制文件或目录,支持通配符
|
101
104
|
def copy_file(src_pattern, dst):
|
102
|
-
|
105
|
+
"""
|
103
106
|
# 描述:复制文件或目录,支持通配符
|
104
107
|
# 使用示例
|
105
108
|
# copy_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test/py.o')
|
106
109
|
# copy_file(r'/data/hejx/liukun/era5/py.o*', r'/data/hejx/liukun/Test')
|
107
110
|
param {*} src_pattern # 源文件或目录
|
108
111
|
param {*} dst # 目标文件或目录
|
109
|
-
|
112
|
+
"""
|
110
113
|
src_pattern = str(src_pattern)
|
111
114
|
# 使用glob.glob来处理可能包含通配符的src
|
112
115
|
src_files = glob.glob(src_pattern)
|
113
116
|
if not src_files:
|
114
|
-
raise FileNotFoundError(
|
117
|
+
raise FileNotFoundError("文件不存在: {}".format(src_pattern))
|
115
118
|
|
116
119
|
# 判断dst是路径还是包含文件名的路径
|
117
120
|
if os.path.isdir(dst):
|
@@ -129,7 +132,7 @@ def copy_file(src_pattern, dst):
|
|
129
132
|
shutil.copytree(src_file, dst_file, symlinks=True)
|
130
133
|
else:
|
131
134
|
shutil.copy2(src_file, dst_file)
|
132
|
-
print(f
|
135
|
+
print(f"复制文件或目录: {src_file} -> {dst_file}")
|
133
136
|
else:
|
134
137
|
# 如果dst包含文件名,则复制后重命名
|
135
138
|
dst_dir = os.path.dirname(dst)
|
@@ -146,11 +149,12 @@ def copy_file(src_pattern, dst):
|
|
146
149
|
shutil.copytree(src_file, dst_file, symlinks=True)
|
147
150
|
else:
|
148
151
|
shutil.copy2(src_file, dst_file)
|
149
|
-
print(f
|
152
|
+
print(f"复制文件或目录并重命名: {src_file} -> {dst_file}")
|
150
153
|
|
151
154
|
|
155
|
+
# ** 重命名文件,支持通配符
|
152
156
|
def rename_file(directory, old_str, new_str):
|
153
|
-
|
157
|
+
"""
|
154
158
|
# 描述:重命名目录下的文件,支持通配符
|
155
159
|
# 使用示例
|
156
160
|
directory_path = r"E:\windfarm\CROCO_FILES"
|
@@ -160,7 +164,7 @@ def rename_file(directory, old_str, new_str):
|
|
160
164
|
param {*} directory # 目录
|
161
165
|
param {*} old_str # 要替换的字符串
|
162
166
|
param {*} new_str # 新字符串
|
163
|
-
|
167
|
+
"""
|
164
168
|
# 获取目录下的所有文件
|
165
169
|
files = os.listdir(directory)
|
166
170
|
|
@@ -187,7 +191,7 @@ def rename_file(directory, old_str, new_str):
|
|
187
191
|
|
188
192
|
# ** 创建子文件夹(可选清空)
|
189
193
|
def make_folder(rootpath: str, folder_name: str, clear=0) -> str:
|
190
|
-
|
194
|
+
"""
|
191
195
|
# 描述:创建子文件夹(可选清空)
|
192
196
|
# 使用示例
|
193
197
|
rootpath = r'E:\Data\2024\09\17'
|
@@ -195,23 +199,22 @@ def make_folder(rootpath: str, folder_name: str, clear=0) -> str:
|
|
195
199
|
newpath = make_folder(rootpath, folder_name, clear=1)
|
196
200
|
param {*} rootpath # 根目录
|
197
201
|
param {*} folder_name # 文件夹名称
|
198
|
-
|
202
|
+
"""
|
199
203
|
folder_path = os.path.join(str(rootpath), str(folder_name))
|
200
204
|
if clear:
|
201
205
|
shutil.rmtree(folder_path, ignore_errors=True)
|
202
206
|
os.makedirs(folder_path, exist_ok=True)
|
203
207
|
return folder_path
|
204
208
|
|
205
|
-
# ** 清空文件夹
|
206
|
-
|
207
209
|
|
210
|
+
# ** 清空文件夹
|
208
211
|
def clear_folder(folder_path):
|
209
|
-
|
212
|
+
"""
|
210
213
|
# 描述:清空文件夹
|
211
214
|
# 使用示例
|
212
215
|
clear_folder(r'E:\Data\2024\09\17\var1')
|
213
216
|
param {*} folder_path # 文件夹路径
|
214
|
-
|
217
|
+
"""
|
215
218
|
folder_path = str(folder_path)
|
216
219
|
if os.path.exists(folder_path):
|
217
220
|
try:
|
@@ -223,21 +226,21 @@ def clear_folder(folder_path):
|
|
223
226
|
os.unlink(file_path) # 删除文件或链接
|
224
227
|
elif os.path.isdir(file_path):
|
225
228
|
shutil.rmtree(file_path) # 删除子文件夹
|
226
|
-
print(f
|
229
|
+
print(f"成功清空文件夹: {folder_path}")
|
227
230
|
except Exception as e:
|
228
|
-
print(f
|
231
|
+
print(f"清空文件夹失败: {folder_path}")
|
229
232
|
print(e)
|
230
233
|
|
231
234
|
|
232
235
|
# ** 清理空文件夹
|
233
236
|
def remove_empty_folders(path, print_info=1):
|
234
|
-
|
237
|
+
"""
|
235
238
|
# 描述:清理空文件夹
|
236
239
|
# 使用示例
|
237
240
|
remove_empty_folders(r'E:\Data\2024\09\17', print_info=1)
|
238
241
|
param {*} path # 文件夹路径
|
239
242
|
param {*} print_info # 是否打印信息
|
240
|
-
|
243
|
+
"""
|
241
244
|
path = str(path)
|
242
245
|
# 遍历当前目录下的所有文件夹和文件
|
243
246
|
for root, dirs, files in os.walk(path, topdown=False):
|
@@ -263,14 +266,14 @@ def remove_empty_folders(path, print_info=1):
|
|
263
266
|
|
264
267
|
# ** 删除相关文件,可使用通配符
|
265
268
|
def remove(pattern):
|
266
|
-
|
269
|
+
"""
|
267
270
|
# 描述:删除相关文件,可使用通配符
|
268
271
|
remove(r'E:\Code\Python\Model\WRF\Radar2\bzip2-radar-0*')
|
269
272
|
# or
|
270
273
|
os.chdir(r'E:\Code\Python\Model\WRF\Radar2')
|
271
274
|
remove('bzip2-radar-0*')
|
272
275
|
param {*} pattern # 文件路径或通配符
|
273
|
-
|
276
|
+
"""
|
274
277
|
# 使用glob.glob来获取所有匹配的文件
|
275
278
|
# 可以使用通配符*来匹配所有文件
|
276
279
|
pattern = str(pattern)
|
@@ -279,16 +282,17 @@ def remove(pattern):
|
|
279
282
|
if os.path.exists(file_path):
|
280
283
|
try:
|
281
284
|
shutil.rmtree(file_path)
|
282
|
-
print(f
|
285
|
+
print(f"成功删除文件: {file_path}")
|
283
286
|
except Exception as e:
|
284
|
-
print(f
|
287
|
+
print(f"删除文件失败: {file_path}")
|
285
288
|
print(e)
|
286
289
|
else:
|
287
|
-
print(f
|
290
|
+
print(f"文件不存在: {file_path}")
|
288
291
|
|
289
292
|
|
290
|
-
|
291
|
-
|
293
|
+
# ** 获取文件大小
|
294
|
+
def file_size(file_path, unit="KB"):
|
295
|
+
"""
|
292
296
|
Description: 获取文件大小
|
293
297
|
|
294
298
|
Args:
|
@@ -297,7 +301,7 @@ def file_size(file_path, unit='KB'):
|
|
297
301
|
|
298
302
|
Returns:
|
299
303
|
文件大小(单位:PB、TB、GB、MB、KB)
|
300
|
-
|
304
|
+
"""
|
301
305
|
# 检查文件是否存在
|
302
306
|
if not os.path.exists(file_path):
|
303
307
|
return "文件不存在"
|
@@ -306,13 +310,7 @@ def file_size(file_path, unit='KB'):
|
|
306
310
|
file_size = os.path.getsize(file_path)
|
307
311
|
|
308
312
|
# 单位转换字典
|
309
|
-
unit_dict = {
|
310
|
-
'PB': 1024**5,
|
311
|
-
'TB': 1024**4,
|
312
|
-
'GB': 1024**3,
|
313
|
-
'MB': 1024**2,
|
314
|
-
'KB': 1024
|
315
|
-
}
|
313
|
+
unit_dict = {"PB": 1024**5, "TB": 1024**4, "GB": 1024**3, "MB": 1024**2, "KB": 1024}
|
316
314
|
|
317
315
|
# 检查传入的单位是否合法
|
318
316
|
if unit not in unit_dict:
|
@@ -324,9 +322,22 @@ def file_size(file_path, unit='KB'):
|
|
324
322
|
return converted_size
|
325
323
|
|
326
324
|
|
327
|
-
|
325
|
+
# ** 计算文件夹下指定相关文件的平均大小
|
326
|
+
def mean_size(parent_path,fname):
|
327
|
+
flist = find_file(parent_path, fname)
|
328
|
+
if flist:
|
329
|
+
size_list = [file_size(f) for f in flist if file_size(f) != 0]
|
330
|
+
if size_list:
|
331
|
+
min_size, max_size = min(size_list), max(size_list)
|
332
|
+
mean_size = sum(size_list) / len(size_list)
|
333
|
+
else:
|
334
|
+
mean_size, min_size, max_size = 0, 0, 0
|
335
|
+
return mean_size, min_size, max_size
|
336
|
+
|
337
|
+
|
338
|
+
if __name__ == "__main__":
|
328
339
|
# newpath = make_folder('D:/Data/2024/09/17/', 'var1', clear=1)
|
329
340
|
# print(newpath)
|
330
341
|
pass
|
331
342
|
|
332
|
-
remove(r
|
343
|
+
remove(r"I:\Delete\test\*")
|
oafuncs/oa_nc.py
CHANGED
@@ -19,7 +19,7 @@ import netCDF4 as nc
|
|
19
19
|
import numpy as np
|
20
20
|
import xarray as xr
|
21
21
|
|
22
|
-
__all__ = ["get_var", "extract5nc", "write2nc", "merge5nc", "modify_var_value", "modify_var_attr", "rename_var_or_dim", "check_ncfile", "
|
22
|
+
__all__ = ["get_var", "extract5nc", "write2nc", "merge5nc", "modify_var_value", "modify_var_attr", "rename_var_or_dim", "check_ncfile", "convert_longitude", "nc_isel"]
|
23
23
|
|
24
24
|
|
25
25
|
def get_var(file, *vars):
|
@@ -79,21 +79,32 @@ def _numpy_to_nc_type(numpy_type):
|
|
79
79
|
"uint32": "u4",
|
80
80
|
"uint64": "u8",
|
81
81
|
}
|
82
|
-
|
82
|
+
# 确保传入的是字符串类型,如果不是,则转换为字符串
|
83
|
+
numpy_type_str = str(numpy_type) if not isinstance(numpy_type, str) else numpy_type
|
84
|
+
return numpy_to_nc.get(numpy_type_str, "f4") # 默认使用 'float32'
|
83
85
|
|
84
86
|
|
85
87
|
def _calculate_scale_and_offset(data, n=16):
|
86
|
-
|
87
|
-
|
88
|
+
if not isinstance(data, np.ndarray):
|
89
|
+
raise ValueError("Input data must be a NumPy array.")
|
90
|
+
|
91
|
+
# 使用 nan_to_num 来避免 NaN 值对 min 和 max 的影响
|
92
|
+
data_min = np.nanmin(data)
|
93
|
+
data_max = np.nanmax(data)
|
94
|
+
|
95
|
+
if np.isnan(data_min) or np.isnan(data_max):
|
96
|
+
raise ValueError("Input data contains NaN values, which are not allowed.")
|
97
|
+
|
98
|
+
scale_factor = (data_max - data_min) / (2**n - 1)
|
88
99
|
add_offset = data_min + 2 ** (n - 1) * scale_factor
|
89
|
-
|
100
|
+
|
90
101
|
return scale_factor, add_offset
|
91
102
|
|
92
103
|
|
93
|
-
def write2nc(file, data, varname=None, coords=None, mode=
|
104
|
+
def write2nc(file, data, varname=None, coords=None, mode="w", scale_offset_switch=True, compile_switch=True):
|
94
105
|
"""
|
95
106
|
description: 写入数据到nc文件
|
96
|
-
|
107
|
+
|
97
108
|
参数:
|
98
109
|
file: 文件路径
|
99
110
|
data: 数据
|
@@ -102,115 +113,66 @@ def write2nc(file, data, varname=None, coords=None, mode='w', scale_offset_switc
|
|
102
113
|
mode: 写入模式,'w'为写入,'a'为追加
|
103
114
|
scale_offset_switch: 是否使用scale_factor和add_offset,默认为True
|
104
115
|
compile_switch: 是否使用压缩参数,默认为True
|
105
|
-
|
116
|
+
|
106
117
|
example: write2nc(r'test.nc', data, 'data', {'time': np.linspace(0, 120, 100), 'lev': np.linspace(0, 120, 50)}, 'a')
|
107
118
|
"""
|
108
|
-
#
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
mode = "w"
|
117
|
-
|
118
|
-
complete = False
|
119
|
-
if varname is None and coords is None:
|
120
|
-
try:
|
121
|
-
data.to_netcdf(file)
|
122
|
-
complete = True
|
123
|
-
# 不能在这里return
|
124
|
-
except AttributeError:
|
125
|
-
raise ValueError("If varname and coords are None, data must be a DataArray.")
|
126
|
-
|
127
|
-
if complete:
|
128
|
-
return
|
129
|
-
|
130
|
-
kwargs = {'zlib': True, 'complevel': 4} # 压缩参数
|
131
|
-
# kwargs = {"compression": 'zlib', "complevel": 4} # 压缩参数
|
119
|
+
# 设置压缩参数
|
120
|
+
kwargs = {"zlib": True, "complevel": 4} if compile_switch else {}
|
121
|
+
|
122
|
+
# 检查文件存在性并根据模式决定操作
|
123
|
+
if mode == "w" and os.path.exists(file):
|
124
|
+
os.remove(file)
|
125
|
+
elif mode == "a" and not os.path.exists(file):
|
126
|
+
mode = "w"
|
132
127
|
|
133
128
|
# 打开 NetCDF 文件
|
134
129
|
with nc.Dataset(file, mode, format="NETCDF4") as ncfile:
|
135
|
-
#
|
130
|
+
# 如果 data 是 DataArray 并且没有提供 varname 和 coords
|
131
|
+
if varname is None and coords is None and isinstance(data, xr.DataArray):
|
132
|
+
data.to_netcdf(file, mode=mode)
|
133
|
+
return
|
134
|
+
|
135
|
+
# 添加坐标
|
136
136
|
for dim, coord_data in coords.items():
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
# 返回字典,字典、列表、元组若为空,都表示False
|
141
|
-
if dim in ncfile.dimensions:
|
142
|
-
# del nc.dimensions[dim]
|
143
|
-
if len(coord_data) != len(ncfile.dimensions[dim]):
|
144
|
-
raise ValueError("Length of coordinate does not match the dimension length.")
|
145
|
-
else:
|
146
|
-
add_coords = False
|
147
|
-
print(f"Warning: Coordinate '{dim}' already exists. Replacing it.")
|
148
|
-
ncfile.variables[dim][:] = np.array(coord_data)
|
149
|
-
if add_coords:
|
150
|
-
# 创建新坐标
|
151
|
-
ncfile.createDimension(dim, len(coord_data))
|
152
|
-
if compile_switch:
|
153
|
-
ncfile.createVariable(dim, _numpy_to_nc_type(coord_data.dtype), (dim,), **kwargs)
|
137
|
+
if dim in ncfile.dimensions:
|
138
|
+
if len(coord_data) != len(ncfile.dimensions[dim]):
|
139
|
+
raise ValueError(f"Length of coordinate '{dim}' does not match the dimension length.")
|
154
140
|
else:
|
155
|
-
ncfile.
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
141
|
+
ncfile.variables[dim][:] = np.array(coord_data)
|
142
|
+
else:
|
143
|
+
ncfile.createDimension(dim, len(coord_data))
|
144
|
+
var = ncfile.createVariable(dim, _numpy_to_nc_type(coord_data.dtype), (dim,), **kwargs)
|
145
|
+
var[:] = np.array(coord_data)
|
146
|
+
|
147
|
+
# 如果坐标数据有属性,则添加到 NetCDF 变量
|
148
|
+
if isinstance(coord_data, xr.DataArray) and coord_data.attrs:
|
149
|
+
for attr_name, attr_value in coord_data.attrs.items():
|
150
|
+
var.setncattr(attr_name, attr_value)
|
151
|
+
|
152
|
+
# 添加或更新变量
|
166
153
|
if varname in ncfile.variables:
|
167
|
-
print(f"Warning: Variable '{varname}' already exists.")
|
168
154
|
if data.shape != ncfile.variables[varname].shape:
|
169
|
-
raise ValueError("Shape of data does not match the variable shape.")
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
print(f"Warning: Variable '{varname}' already exists. Replacing it.")
|
175
|
-
|
176
|
-
if add_var:
|
177
|
-
# 创建变量及其维度
|
178
|
-
dim_names = tuple(coords.keys()) # 使用coords传入的维度名称
|
155
|
+
raise ValueError(f"Shape of data does not match the variable shape for '{varname}'.")
|
156
|
+
ncfile.variables[varname][:] = np.array(data)
|
157
|
+
else:
|
158
|
+
# 创建变量
|
159
|
+
dim_names = tuple(coords.keys())
|
179
160
|
if scale_offset_switch:
|
180
161
|
scale_factor, add_offset = _calculate_scale_and_offset(np.array(data))
|
181
|
-
|
182
|
-
|
183
|
-
|
162
|
+
dtype = "i2"
|
163
|
+
var = ncfile.createVariable(varname, dtype, dim_names, fill_value=-32767, **kwargs)
|
164
|
+
var.setncattr("scale_factor", scale_factor)
|
165
|
+
var.setncattr("add_offset", add_offset)
|
184
166
|
else:
|
185
167
|
dtype = _numpy_to_nc_type(data.dtype)
|
186
|
-
|
187
|
-
|
188
|
-
ncfile.createVariable(varname, dtype, dim_names, **kwargs)
|
189
|
-
else:
|
190
|
-
ncfile.createVariable(varname, dtype, dim_names)
|
191
|
-
|
192
|
-
if scale_offset_switch: # 需要在写入数据之前设置scale_factor和add_offset
|
193
|
-
ncfile.variables[varname].setncattr('scale_factor', scale_factor)
|
194
|
-
ncfile.variables[varname].setncattr('add_offset', add_offset)
|
195
|
-
ncfile.variables[varname].setncattr('_FillValue', _FillValue)
|
196
|
-
ncfile.variables[varname].setncattr('missing_value', missing_value)
|
197
|
-
|
198
|
-
# ncfile.createVariable('data', 'f4', ('time','lev'))
|
199
|
-
|
200
|
-
# 写入数据
|
201
|
-
ncfile.variables[varname][:] = np.array(data)
|
168
|
+
var = ncfile.createVariable(varname, dtype, dim_names, **kwargs)
|
169
|
+
var[:] = np.array(data)
|
202
170
|
|
203
|
-
#
|
204
|
-
if
|
205
|
-
raise ValueError("Number of dimensions does not match the data shape.")
|
206
|
-
# 判断data是否带有属性信息,如果有,写入属性信息
|
207
|
-
if isinstance(data, xr.DataArray):
|
208
|
-
current_var = ncfile.variables[varname]
|
209
|
-
if data.attrs:
|
171
|
+
# 添加属性
|
172
|
+
if isinstance(data, xr.DataArray) and data.attrs:
|
210
173
|
for key, value in data.attrs.items():
|
211
|
-
if key in ["scale_factor", "add_offset", "_FillValue", "missing_value"]
|
212
|
-
|
213
|
-
current_var.setncattr(key, value)
|
174
|
+
if key not in ["scale_factor", "add_offset", "_FillValue", "missing_value"] or not scale_offset_switch:
|
175
|
+
var.setncattr(key, value)
|
214
176
|
|
215
177
|
|
216
178
|
def merge5nc(file_list, var_name=None, dim_name=None, target_filename=None):
|
@@ -230,6 +192,9 @@ def merge5nc(file_list, var_name=None, dim_name=None, target_filename=None):
|
|
230
192
|
merge5nc(file_list, var_name=['data1', 'data2'], dim_name='time', target_filename='merged.nc')
|
231
193
|
merge5nc(file_list, var_name=None, dim_name='time', target_filename='merged.nc')
|
232
194
|
"""
|
195
|
+
if isinstance(file_list, str):
|
196
|
+
file_list = [file_list]
|
197
|
+
|
233
198
|
# 初始化变量名列表
|
234
199
|
var_names = None
|
235
200
|
|
@@ -398,25 +363,28 @@ def check_ncfile(ncfile, if_delete=False):
|
|
398
363
|
return False
|
399
364
|
|
400
365
|
|
401
|
-
def
|
366
|
+
def convert_longitude(ds, lon_name="longitude", convert=180):
|
402
367
|
"""
|
403
|
-
|
368
|
+
将经度数组转换为指定的范围。
|
404
369
|
|
405
370
|
参数:
|
406
|
-
|
371
|
+
ds (xarray.Dataset): 包含经度数据的xarray数据集。
|
372
|
+
lon_name (str): 经度变量的名称,默认为"longitude"。
|
373
|
+
convert (int): 转换目标范围,可以是180或360,默认为180。
|
407
374
|
|
408
375
|
返回值:
|
409
|
-
|
376
|
+
xarray.Dataset: 经度转换后的xarray数据集。
|
410
377
|
"""
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
ds = ds.assign_coords(
|
419
|
-
|
378
|
+
to_which = int(convert)
|
379
|
+
if to_which not in [180, 360]:
|
380
|
+
raise ValueError("to_which must be '180' or '360'")
|
381
|
+
|
382
|
+
if to_which == 180:
|
383
|
+
ds = ds.assign_coords({lon_name: (ds[lon_name] + 180) % 360 - 180})
|
384
|
+
elif to_which == 360:
|
385
|
+
ds = ds.assign_coords({lon_name: (ds[lon_name] + 360) % 360})
|
386
|
+
|
387
|
+
return ds.sortby(lon_name)
|
420
388
|
|
421
389
|
|
422
390
|
def nc_isel(ncfile, dim_name, slice_list):
|
@@ -0,0 +1,24 @@
|
|
1
|
+
oafuncs/__init__.py,sha256=glcIlhQ9xSK4WtL58dq7Od2S3JPqsuEyhUQ-VWO8hOc,1426
|
2
|
+
oafuncs/oa_cmap.py,sha256=N-jt5CjRTXIjur6QAh90L8hAr9n3D-1HRSkKT98hUx8,6449
|
3
|
+
oafuncs/oa_data.py,sha256=DUKc--EyQfIcxAwy2Rv_oDMuE5uw9CVrt0bMAfVog98,12482
|
4
|
+
oafuncs/oa_draw.py,sha256=ccwFS3Y4DmzLLcqSrX-Ee-vCdWd78D1UcaSdTWoDC9Q,20950
|
5
|
+
oafuncs/oa_file.py,sha256=FkEYm-JfbQoJZHoY28El412k19JiQeNhO67ybcOhORg,12222
|
6
|
+
oafuncs/oa_help.py,sha256=ppNktmtNzs15R20MD1bM7yImlTQ_ngMwvoIglePOKXA,1000
|
7
|
+
oafuncs/oa_nc.py,sha256=Gj0xLfqgQI3hNnr9SED1WFj2JU4GsJj2on_8EVdSk20,15595
|
8
|
+
oafuncs/oa_python.py,sha256=XPTP3o7zTFzfJR_YhsKfQksa3bSYwXsne9YxlJplCEA,3994
|
9
|
+
oafuncs/oa_down/User_Agent-list.txt,sha256=pazxSip8_lphEBOPHG902zmIBUg8sBKXgmqp_g6j_E4,661062
|
10
|
+
oafuncs/oa_down/__init__.py,sha256=nY5X7gM1jw7DJxyooR2UJSq4difkw-flz2Ucr_OuDbA,540
|
11
|
+
oafuncs/oa_down/hycom_3hourly.py,sha256=7YLtN1SqugcGQ1ZdUznUDspdJGZONphBq6LoxihIdyw,62938
|
12
|
+
oafuncs/oa_down/literature.py,sha256=dT3-7-beEzQ9mTP8LNV9Gf3q5Z1Pqqjc6FOS010HZeQ,17833
|
13
|
+
oafuncs/oa_down/test_ua.py,sha256=0IQq3NjqfNr7KkyjS_U-a4mYu-r-E7gzawwo4IfEa6Y,10851
|
14
|
+
oafuncs/oa_sign/__init__.py,sha256=QKqTFrJDFK40C5uvk48GlRRbGFzO40rgkYwu6dYxatM,563
|
15
|
+
oafuncs/oa_sign/meteorological.py,sha256=mLbupsZSq427HTfVbZMvIlFzDHwSzQAbK3X19o8anFY,6525
|
16
|
+
oafuncs/oa_sign/ocean.py,sha256=xrW-rWD7xBWsB5PuCyEwQ1Q_RDKq2KCLz-LOONHgldU,5932
|
17
|
+
oafuncs/oa_sign/scientific.py,sha256=a4JxOBgm9vzNZKpJ_GQIQf7cokkraV5nh23HGbmTYKw,5064
|
18
|
+
oafuncs/oa_tool/__init__.py,sha256=IKOlqpWlb4cMDCtq2VKR_RTxQHDNqR_vfqqsOsp_lKQ,466
|
19
|
+
oafuncs/oa_tool/email.py,sha256=4lJxV_KUzhxgLYfVwYTqp0qxRugD7fvsZkXDe5WkUKo,3052
|
20
|
+
oafuncs-0.0.82.dist-info/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
|
21
|
+
oafuncs-0.0.82.dist-info/METADATA,sha256=wKkzaYKFDa8_O_EhelPy0RIiD0H93MHhZlEMNI2V2QE,22429
|
22
|
+
oafuncs-0.0.82.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109
|
23
|
+
oafuncs-0.0.82.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
|
24
|
+
oafuncs-0.0.82.dist-info/RECORD,,
|