oafuncs 0.0.97.1__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/__init__.py +54 -0
- oafuncs/_script/__init__.py +27 -0
- oafuncs/_script/plot_dataset.py +299 -0
- oafuncs/data_store/OAFuncs.png +0 -0
- oafuncs/data_store/hycom_3hourly.png +0 -0
- oafuncs/oa_cmap.py +215 -0
- oafuncs/oa_data.py +293 -0
- oafuncs/oa_down/User_Agent-list.txt +6697 -0
- oafuncs/oa_down/__init__.py +22 -0
- oafuncs/oa_down/hycom_3hourly.py +1309 -0
- oafuncs/oa_down/hycom_3hourly_20250129.py +1307 -0
- oafuncs/oa_down/idm.py +50 -0
- oafuncs/oa_down/literature.py +288 -0
- oafuncs/oa_down/test_ua.py +151 -0
- oafuncs/oa_down/user_agent.py +31 -0
- oafuncs/oa_draw.py +326 -0
- oafuncs/oa_file.py +413 -0
- oafuncs/oa_help.py +144 -0
- oafuncs/oa_model/__init__.py +19 -0
- oafuncs/oa_model/roms/__init__.py +20 -0
- oafuncs/oa_model/roms/test.py +19 -0
- oafuncs/oa_model/wrf/__init__.py +18 -0
- oafuncs/oa_model/wrf/little_r.py +186 -0
- oafuncs/oa_nc.py +523 -0
- oafuncs/oa_python.py +108 -0
- oafuncs/oa_sign/__init__.py +21 -0
- oafuncs/oa_sign/meteorological.py +168 -0
- oafuncs/oa_sign/ocean.py +158 -0
- oafuncs/oa_sign/scientific.py +139 -0
- oafuncs/oa_tool/__init__.py +19 -0
- oafuncs/oa_tool/email.py +114 -0
- oafuncs/oa_tool/parallel.py +90 -0
- oafuncs/oa_tool/time.py +22 -0
- oafuncs-0.0.97.1.dist-info/LICENSE.txt +19 -0
- oafuncs-0.0.97.1.dist-info/METADATA +106 -0
- oafuncs-0.0.97.1.dist-info/RECORD +38 -0
- oafuncs-0.0.97.1.dist-info/WHEEL +5 -0
- oafuncs-0.0.97.1.dist-info/top_level.txt +1 -0
oafuncs/oa_nc.py
ADDED
@@ -0,0 +1,523 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# coding=utf-8
|
3
|
+
"""
|
4
|
+
Author: Liu Kun && 16031215@qq.com
|
5
|
+
Date: 2024-09-17 14:58:50
|
6
|
+
LastEditors: Liu Kun && 16031215@qq.com
|
7
|
+
LastEditTime: 2024-12-06 14:16:56
|
8
|
+
FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_nc.py
|
9
|
+
Description:
|
10
|
+
EditPlatform: vscode
|
11
|
+
ComputerInfo: XPS 15 9510
|
12
|
+
SystemInfo: Windows 11
|
13
|
+
Python Version: 3.11
|
14
|
+
"""
|
15
|
+
|
16
|
+
import os
|
17
|
+
|
18
|
+
import netCDF4 as nc
|
19
|
+
import numpy as np
|
20
|
+
import xarray as xr
|
21
|
+
from rich import print
|
22
|
+
|
23
|
+
from oafuncs._script.plot_dataset import func_plot_dataset
|
24
|
+
|
25
|
+
__all__ = ["get_var", "extract", "save", "merge", "modify", "rename", "check", "convert_longitude", "isel", "draw"]
|
26
|
+
|
27
|
+
|
28
|
+
def get_var(file, *vars):
|
29
|
+
"""
|
30
|
+
Description:
|
31
|
+
Read variables from nc file
|
32
|
+
Parameters:
|
33
|
+
file: str, file path
|
34
|
+
*vars: str, variable name or variable names; should be in same size
|
35
|
+
Example:
|
36
|
+
datas = get_var(file_ecm, 'h', 't', 'u', 'v')
|
37
|
+
Return:
|
38
|
+
datas: list, variable data
|
39
|
+
"""
|
40
|
+
ds = xr.open_dataset(file)
|
41
|
+
datas = []
|
42
|
+
for var in vars:
|
43
|
+
data = ds[var]
|
44
|
+
datas.append(data)
|
45
|
+
ds.close()
|
46
|
+
return datas
|
47
|
+
|
48
|
+
|
49
|
+
def extract(file, varname, only_value=True):
|
50
|
+
"""
|
51
|
+
Description:
|
52
|
+
Extract variables from nc file
|
53
|
+
Return the variable and coordinate dictionary
|
54
|
+
Parameters:
|
55
|
+
file: str, file path
|
56
|
+
varname: str, variable name
|
57
|
+
only_value: bool, whether to keep only the value of the variable and dimension
|
58
|
+
Example:
|
59
|
+
data, dimdict = extract('test.nc', 'h')
|
60
|
+
"""
|
61
|
+
ds = xr.open_dataset(file)
|
62
|
+
vardata = ds[varname]
|
63
|
+
ds.close()
|
64
|
+
dims = vardata.dims
|
65
|
+
dimdict = {}
|
66
|
+
for dim in dims:
|
67
|
+
if only_value:
|
68
|
+
dimdict[dim] = vardata[dim].values
|
69
|
+
else:
|
70
|
+
dimdict[dim] = ds[dim]
|
71
|
+
if only_value:
|
72
|
+
vardata = np.array(vardata)
|
73
|
+
return vardata, dimdict
|
74
|
+
|
75
|
+
|
76
|
+
def _numpy_to_nc_type(numpy_type):
|
77
|
+
"""将NumPy数据类型映射到NetCDF数据类型"""
|
78
|
+
numpy_to_nc = {
|
79
|
+
"float32": "f4",
|
80
|
+
"float64": "f8",
|
81
|
+
"int8": "i1",
|
82
|
+
"int16": "i2",
|
83
|
+
"int32": "i4",
|
84
|
+
"int64": "i8",
|
85
|
+
"uint8": "u1",
|
86
|
+
"uint16": "u2",
|
87
|
+
"uint32": "u4",
|
88
|
+
"uint64": "u8",
|
89
|
+
}
|
90
|
+
# 确保传入的是字符串类型,如果不是,则转换为字符串
|
91
|
+
numpy_type_str = str(numpy_type) if not isinstance(numpy_type, str) else numpy_type
|
92
|
+
return numpy_to_nc.get(numpy_type_str, "f4") # 默认使用 'float32'
|
93
|
+
|
94
|
+
|
95
|
+
def _calculate_scale_and_offset(data, n=16):
|
96
|
+
if not isinstance(data, np.ndarray):
|
97
|
+
raise ValueError("Input data must be a NumPy array.")
|
98
|
+
|
99
|
+
# 使用 nan_to_num 来避免 NaN 值对 min 和 max 的影响
|
100
|
+
data_min = np.nanmin(data)
|
101
|
+
data_max = np.nanmax(data)
|
102
|
+
|
103
|
+
if np.isnan(data_min) or np.isnan(data_max):
|
104
|
+
raise ValueError("Input data contains NaN values, which are not allowed.")
|
105
|
+
|
106
|
+
scale_factor = (data_max - data_min) / (2**n - 1)
|
107
|
+
add_offset = data_min + 2 ** (n - 1) * scale_factor
|
108
|
+
|
109
|
+
return scale_factor, add_offset
|
110
|
+
|
111
|
+
|
112
|
+
def save(file, data, varname=None, coords=None, mode="w", scale_offset_switch=True, compile_switch=True):
|
113
|
+
"""
|
114
|
+
Description:
|
115
|
+
Write data to NetCDF file
|
116
|
+
Parameters:
|
117
|
+
file: str, file path
|
118
|
+
data: data
|
119
|
+
varname: str, variable name
|
120
|
+
coords: dict, coordinates, key is the dimension name, value is the coordinate data
|
121
|
+
mode: str, write mode, 'w' for write, 'a' for append
|
122
|
+
scale_offset_switch: bool, whether to use scale_factor and add_offset, default is True
|
123
|
+
compile_switch: bool, whether to use compression parameters, default is True
|
124
|
+
Example:
|
125
|
+
save(r'test.nc', data, 'u', {'time': np.linspace(0, 120, 100), 'lev': np.linspace(0, 120, 50)}, 'a')
|
126
|
+
"""
|
127
|
+
# 设置压缩参数
|
128
|
+
kwargs = {"zlib": True, "complevel": 4} if compile_switch else {}
|
129
|
+
|
130
|
+
# 检查文件存在性并根据模式决定操作
|
131
|
+
if mode == "w" and os.path.exists(file):
|
132
|
+
os.remove(file)
|
133
|
+
elif mode == "a" and not os.path.exists(file):
|
134
|
+
mode = "w"
|
135
|
+
|
136
|
+
# 打开 NetCDF 文件
|
137
|
+
with nc.Dataset(file, mode, format="NETCDF4") as ncfile:
|
138
|
+
# 如果 data 是 DataArray 并且没有提供 varname 和 coords
|
139
|
+
if varname is None and coords is None and isinstance(data, xr.DataArray):
|
140
|
+
data.to_netcdf(file, mode=mode)
|
141
|
+
return
|
142
|
+
|
143
|
+
# 添加坐标
|
144
|
+
for dim, coord_data in coords.items():
|
145
|
+
if dim in ncfile.dimensions:
|
146
|
+
if len(coord_data) != len(ncfile.dimensions[dim]):
|
147
|
+
raise ValueError(f"Length of coordinate '{dim}' does not match the dimension length.")
|
148
|
+
else:
|
149
|
+
ncfile.variables[dim][:] = np.array(coord_data)
|
150
|
+
else:
|
151
|
+
ncfile.createDimension(dim, len(coord_data))
|
152
|
+
var = ncfile.createVariable(dim, _numpy_to_nc_type(coord_data.dtype), (dim,), **kwargs)
|
153
|
+
var[:] = np.array(coord_data)
|
154
|
+
|
155
|
+
# 如果坐标数据有属性,则添加到 NetCDF 变量
|
156
|
+
if isinstance(coord_data, xr.DataArray) and coord_data.attrs:
|
157
|
+
for attr_name, attr_value in coord_data.attrs.items():
|
158
|
+
var.setncattr(attr_name, attr_value)
|
159
|
+
|
160
|
+
# 添加或更新变量
|
161
|
+
if varname in ncfile.variables:
|
162
|
+
if data.shape != ncfile.variables[varname].shape:
|
163
|
+
raise ValueError(f"Shape of data does not match the variable shape for '{varname}'.")
|
164
|
+
ncfile.variables[varname][:] = np.array(data)
|
165
|
+
else:
|
166
|
+
# 创建变量
|
167
|
+
dim_names = tuple(coords.keys())
|
168
|
+
if scale_offset_switch:
|
169
|
+
scale_factor, add_offset = _calculate_scale_and_offset(np.array(data))
|
170
|
+
dtype = "i2"
|
171
|
+
var = ncfile.createVariable(varname, dtype, dim_names, fill_value=-32767, **kwargs)
|
172
|
+
var.setncattr("scale_factor", scale_factor)
|
173
|
+
var.setncattr("add_offset", add_offset)
|
174
|
+
else:
|
175
|
+
dtype = _numpy_to_nc_type(data.dtype)
|
176
|
+
var = ncfile.createVariable(varname, dtype, dim_names, **kwargs)
|
177
|
+
var[:] = np.array(data)
|
178
|
+
|
179
|
+
# 添加属性
|
180
|
+
if isinstance(data, xr.DataArray) and data.attrs:
|
181
|
+
for key, value in data.attrs.items():
|
182
|
+
if key not in ["scale_factor", "add_offset", "_FillValue", "missing_value"] or not scale_offset_switch:
|
183
|
+
var.setncattr(key, value)
|
184
|
+
|
185
|
+
|
186
|
+
def merge(file_list, var_name=None, dim_name=None, target_filename=None):
|
187
|
+
"""
|
188
|
+
Description:
|
189
|
+
Merge variables from multiple NetCDF files along a specified dimension and write to a new file.
|
190
|
+
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;
|
191
|
+
If the list has more than one element, it is a multi-variable; if var_name is None, all variables are merged.
|
192
|
+
|
193
|
+
Parameters:
|
194
|
+
file_list: List of NetCDF file paths
|
195
|
+
var_name: Name of the variable to be extracted or a list of variable names, default is None, which means all variables are extracted
|
196
|
+
dim_name: Dimension name used for merging
|
197
|
+
target_filename: Target file name after merging
|
198
|
+
|
199
|
+
Example:
|
200
|
+
merge(file_list, var_name='u', dim_name='time', target_filename='merged.nc')
|
201
|
+
merge(file_list, var_name=['u', 'v'], dim_name='time', target_filename='merged.nc')
|
202
|
+
merge(file_list, var_name=None, dim_name='time', target_filename='merged.nc')
|
203
|
+
"""
|
204
|
+
# 看看保存文件是单纯文件名还是包含路径的,如果有路径,需要确保路径存在
|
205
|
+
if target_filename is None:
|
206
|
+
target_filename = "merged.nc"
|
207
|
+
if not os.path.exists(os.path.dirname(str(target_filename))):
|
208
|
+
os.makedirs(os.path.dirname(str(target_filename)))
|
209
|
+
|
210
|
+
if isinstance(file_list, str):
|
211
|
+
file_list = [file_list]
|
212
|
+
|
213
|
+
# 初始化变量名列表
|
214
|
+
var_names = None
|
215
|
+
|
216
|
+
# 判断 var_name 是单变量、多变量还是合并所有变量
|
217
|
+
if var_name is None:
|
218
|
+
# 获取第一个文件中的所有变量名
|
219
|
+
ds = xr.open_dataset(file_list[0])
|
220
|
+
var_names = list(ds.variables.keys())
|
221
|
+
ds.close()
|
222
|
+
elif isinstance(var_name, str):
|
223
|
+
var_names = [var_name]
|
224
|
+
elif isinstance(var_name, list):
|
225
|
+
var_names = var_name
|
226
|
+
else:
|
227
|
+
raise ValueError("var_name must be a string, a list of strings, or None")
|
228
|
+
|
229
|
+
# 初始化合并数据字典
|
230
|
+
merged_data = {}
|
231
|
+
|
232
|
+
# 遍历文件列表
|
233
|
+
print("Reading file ...")
|
234
|
+
for i, file in enumerate(file_list):
|
235
|
+
# 更新track描述进度
|
236
|
+
# print(f"\rReading file {i + 1}/{len(file_list)}...", end="")
|
237
|
+
ds = xr.open_dataset(file)
|
238
|
+
for var_name in var_names:
|
239
|
+
var = ds[var_name]
|
240
|
+
# 如果变量包含合并维度,则合并它们
|
241
|
+
if dim_name in var.dims:
|
242
|
+
if var_name not in merged_data:
|
243
|
+
merged_data[var_name] = [var]
|
244
|
+
else:
|
245
|
+
merged_data[var_name].append(var)
|
246
|
+
# 如果变量不包含合并维度,则仅保留第一个文件中的值
|
247
|
+
else:
|
248
|
+
if var_name not in merged_data:
|
249
|
+
merged_data[var_name] = var
|
250
|
+
ds.close()
|
251
|
+
|
252
|
+
print("\nMerging data ...")
|
253
|
+
for var_name in merged_data:
|
254
|
+
if isinstance(merged_data[var_name], list):
|
255
|
+
merged_data[var_name] = xr.concat(merged_data[var_name], dim=dim_name)
|
256
|
+
|
257
|
+
merged_data = xr.Dataset(merged_data)
|
258
|
+
|
259
|
+
print("\nWriting data to file ...")
|
260
|
+
if os.path.exists(target_filename):
|
261
|
+
print("Warning: The target file already exists.")
|
262
|
+
print("Removing existing file ...")
|
263
|
+
os.remove(target_filename)
|
264
|
+
merged_data.to_netcdf(target_filename)
|
265
|
+
print(f'\nFile "{target_filename}" has been created.')
|
266
|
+
|
267
|
+
|
268
|
+
def _modify_var(nc_file_path, variable_name, new_value):
|
269
|
+
"""
|
270
|
+
Description:
|
271
|
+
Modify the value of a variable in a NetCDF file using the netCDF4 library.
|
272
|
+
|
273
|
+
Parameters:
|
274
|
+
nc_file_path (str): The path to the NetCDF file.
|
275
|
+
variable_name (str): The name of the variable to be modified.
|
276
|
+
new_value (numpy.ndarray): The new value of the variable.
|
277
|
+
|
278
|
+
Example:
|
279
|
+
modify_var('test.nc', 'u', np.random.rand(100, 50))
|
280
|
+
"""
|
281
|
+
try:
|
282
|
+
# Open the NetCDF file
|
283
|
+
dataset = nc.Dataset(nc_file_path, "r+")
|
284
|
+
# Get the variable to be modified
|
285
|
+
variable = dataset.variables[variable_name]
|
286
|
+
# Modify the value of the variable
|
287
|
+
variable[:] = new_value
|
288
|
+
dataset.close()
|
289
|
+
print(f"Successfully modified variable {variable_name} in {nc_file_path}.")
|
290
|
+
except Exception as e:
|
291
|
+
print(f"An error occurred while modifying variable {variable_name} in {nc_file_path}: {e}")
|
292
|
+
|
293
|
+
|
294
|
+
def _modify_attr(nc_file_path, variable_name, attribute_name, attribute_value):
|
295
|
+
"""
|
296
|
+
Description:
|
297
|
+
Add or modify an attribute of a variable in a NetCDF file using the netCDF4 library.
|
298
|
+
|
299
|
+
Parameters:
|
300
|
+
nc_file_path (str): The path to the NetCDF file.
|
301
|
+
variable_name (str): The name of the variable to be modified.
|
302
|
+
attribute_name (str): The name of the attribute to be added or modified.
|
303
|
+
attribute_value (any): The value of the attribute.
|
304
|
+
|
305
|
+
Example:
|
306
|
+
modify_attr('test.nc', 'temperature', 'long_name', 'Temperature in Celsius')
|
307
|
+
"""
|
308
|
+
try:
|
309
|
+
ds = nc.Dataset(nc_file_path, "r+")
|
310
|
+
if variable_name not in ds.variables:
|
311
|
+
raise ValueError(f"Variable '{variable_name}' not found in the NetCDF file.")
|
312
|
+
|
313
|
+
variable = ds.variables[variable_name]
|
314
|
+
if attribute_name in variable.ncattrs():
|
315
|
+
print(f"Warning: Attribute '{attribute_name}' already exists. Replacing it.")
|
316
|
+
variable.setncattr(attribute_name, attribute_value)
|
317
|
+
else:
|
318
|
+
print(f"Adding attribute '{attribute_name}'...")
|
319
|
+
variable.setncattr(attribute_name, attribute_value)
|
320
|
+
|
321
|
+
ds.close()
|
322
|
+
except Exception as e:
|
323
|
+
raise RuntimeError(f"An error occurred: {e}")
|
324
|
+
|
325
|
+
|
326
|
+
def modify(nc_file, var_name, attr_name=None, new_value=None):
|
327
|
+
"""
|
328
|
+
Description:
|
329
|
+
Modify the value of a variable or the value of an attribute in a NetCDF file.
|
330
|
+
|
331
|
+
Parameters:
|
332
|
+
nc_file (str): The path to the NetCDF file.
|
333
|
+
var_name (str): The name of the variable to be modified.
|
334
|
+
attr_name (str): The name of the attribute to be modified. If None, the variable value will be modified.
|
335
|
+
new_value (any): The new value of the variable or attribute.
|
336
|
+
|
337
|
+
Example:
|
338
|
+
modify('test.nc', 'temperature', 'long_name', 'Temperature in Celsius')
|
339
|
+
modify('test.nc', 'temperature', None, np.random.rand(100, 50))
|
340
|
+
"""
|
341
|
+
if attr_name is None:
|
342
|
+
_modify_var(nc_file, var_name, new_value)
|
343
|
+
else:
|
344
|
+
_modify_attr(nc_file, var_name, attr_name, new_value)
|
345
|
+
|
346
|
+
|
347
|
+
def rename(ncfile_path, old_name, new_name):
|
348
|
+
"""
|
349
|
+
Description:
|
350
|
+
Rename a variable and/or dimension in a NetCDF file.
|
351
|
+
|
352
|
+
Parameters:
|
353
|
+
ncfile_path (str): The path to the NetCDF file.
|
354
|
+
old_name (str): The current name of the variable or dimension.
|
355
|
+
new_name (str): The new name to assign to the variable or dimension.
|
356
|
+
|
357
|
+
example:
|
358
|
+
rename('test.nc', 'temperature', 'temp')
|
359
|
+
"""
|
360
|
+
try:
|
361
|
+
with nc.Dataset(ncfile_path, "r+") as dataset:
|
362
|
+
# If the old name is not found as a variable or dimension, print a message
|
363
|
+
if old_name not in dataset.variables and old_name not in dataset.dimensions:
|
364
|
+
print(f"Variable or dimension {old_name} not found in the file.")
|
365
|
+
|
366
|
+
# Attempt to rename the variable
|
367
|
+
if old_name in dataset.variables:
|
368
|
+
dataset.renameVariable(old_name, new_name)
|
369
|
+
print(f"Successfully renamed variable {old_name} to {new_name}.")
|
370
|
+
|
371
|
+
# Attempt to rename the dimension
|
372
|
+
if old_name in dataset.dimensions:
|
373
|
+
# Check if the new dimension name already exists
|
374
|
+
if new_name in dataset.dimensions:
|
375
|
+
raise ValueError(f"Dimension name {new_name} already exists in the file.")
|
376
|
+
dataset.renameDimension(old_name, new_name)
|
377
|
+
print(f"Successfully renamed dimension {old_name} to {new_name}.")
|
378
|
+
|
379
|
+
except Exception as e:
|
380
|
+
print(f"An error occurred: {e}")
|
381
|
+
|
382
|
+
|
383
|
+
def check(ncfile: str, delete_switch: bool = False) -> bool:
|
384
|
+
"""
|
385
|
+
Check if a NetCDF file is corrupted with enhanced error handling.
|
386
|
+
|
387
|
+
Handles HDF5 library errors gracefully without terminating program.
|
388
|
+
"""
|
389
|
+
is_valid = False
|
390
|
+
|
391
|
+
if not os.path.exists(ncfile):
|
392
|
+
print(f"[#ffeac5]Local file missing: [#009d88]{ncfile}")
|
393
|
+
# 提示:提示文件缺失也许是正常的,这只是检查文件是否存在于本地
|
394
|
+
print("[#d6d9fd]Note: File missing may be normal, this is just to check if the file exists locally.")
|
395
|
+
return False
|
396
|
+
|
397
|
+
try:
|
398
|
+
# # 深度验证文件结构
|
399
|
+
# with nc.Dataset(ncfile, "r") as ds:
|
400
|
+
# # 显式检查文件结构完整性
|
401
|
+
# ds.sync() # 强制刷新缓冲区
|
402
|
+
# ds.close() # 显式关闭后重新打开验证
|
403
|
+
|
404
|
+
# 二次验证确保变量可访问
|
405
|
+
with nc.Dataset(ncfile, "r") as ds_verify:
|
406
|
+
if not ds_verify.variables:
|
407
|
+
print(f"Empty variables: {ncfile}")
|
408
|
+
else:
|
409
|
+
# 尝试访问元数据
|
410
|
+
_ = ds_verify.__dict__
|
411
|
+
# 抽样检查第一个变量
|
412
|
+
for var in ds_verify.variables.values():
|
413
|
+
_ = var.shape # 触发实际数据访问
|
414
|
+
break
|
415
|
+
is_valid = True
|
416
|
+
|
417
|
+
except Exception as e: # 捕获所有异常类型
|
418
|
+
print(f"HDF5 validation failed for {ncfile}: {str(e)}")
|
419
|
+
error_type = type(e).__name__
|
420
|
+
if "HDF5" in error_type or "h5" in error_type.lower():
|
421
|
+
print(f"Critical HDF5 structure error detected in {ncfile}")
|
422
|
+
|
423
|
+
# 安全删除流程
|
424
|
+
if not is_valid:
|
425
|
+
if delete_switch:
|
426
|
+
try:
|
427
|
+
os.remove(ncfile)
|
428
|
+
print(f"Removed corrupted: {ncfile}")
|
429
|
+
except Exception as del_error:
|
430
|
+
print(f"Delete failed: {ncfile} - {str(del_error)}")
|
431
|
+
return False
|
432
|
+
|
433
|
+
return True
|
434
|
+
|
435
|
+
|
436
|
+
def convert_longitude(ds, lon_name="longitude", convert=180):
|
437
|
+
"""
|
438
|
+
Description:
|
439
|
+
Convert the longitude array to a specified range.
|
440
|
+
|
441
|
+
Parameters:
|
442
|
+
ds (xarray.Dataset): The xarray dataset containing the longitude data.
|
443
|
+
lon_name (str): The name of the longitude variable, default is "longitude".
|
444
|
+
convert (int): The target range to convert to, can be 180 or 360, default is 180.
|
445
|
+
|
446
|
+
Returns:
|
447
|
+
xarray.Dataset: The xarray dataset with the converted longitude.
|
448
|
+
"""
|
449
|
+
to_which = int(convert)
|
450
|
+
if to_which not in [180, 360]:
|
451
|
+
raise ValueError("convert value must be '180' or '360'")
|
452
|
+
|
453
|
+
if to_which == 180:
|
454
|
+
ds = ds.assign_coords({lon_name: (ds[lon_name] + 180) % 360 - 180})
|
455
|
+
elif to_which == 360:
|
456
|
+
ds = ds.assign_coords({lon_name: (ds[lon_name] + 360) % 360})
|
457
|
+
|
458
|
+
return ds.sortby(lon_name)
|
459
|
+
|
460
|
+
|
461
|
+
def isel(ncfile, dim_name, slice_list):
|
462
|
+
"""
|
463
|
+
Description:
|
464
|
+
Choose the data by the index of the dimension
|
465
|
+
|
466
|
+
Parameters:
|
467
|
+
ncfile: str, the path of the netCDF file
|
468
|
+
dim_name: str, the name of the dimension
|
469
|
+
slice_list: list, the index of the dimension
|
470
|
+
|
471
|
+
Example:
|
472
|
+
slice_list = [[y*12+m for m in range(11,14)] for y in range(84)]
|
473
|
+
slice_list = [y * 12 + m for y in range(84) for m in range(11, 14)]
|
474
|
+
isel(ncfile, 'time', slice_list)
|
475
|
+
"""
|
476
|
+
ds = xr.open_dataset(ncfile)
|
477
|
+
slice_list = np.array(slice_list).flatten()
|
478
|
+
slice_list = [int(i) for i in slice_list]
|
479
|
+
ds_new = ds.isel(**{dim_name: slice_list})
|
480
|
+
ds.close()
|
481
|
+
return ds_new
|
482
|
+
|
483
|
+
|
484
|
+
def draw(output_dir=None, dataset=None, ncfile=None, xyzt_dims=("longitude", "latitude", "level", "time"), plot_type="contourf",fixed_colorscale=False):
|
485
|
+
"""
|
486
|
+
Description:
|
487
|
+
Draw the data in the netCDF file
|
488
|
+
|
489
|
+
Parameters:
|
490
|
+
ncfile: str, the path of the netCDF file
|
491
|
+
output_dir: str, the path of the output directory
|
492
|
+
x_dim: str, the name of the x dimension
|
493
|
+
y_dim: str, the name of the y dimension
|
494
|
+
z_dim: str, the name of the z dimension
|
495
|
+
t_dim: str, the name of the t dimension
|
496
|
+
plot_type: str, the type of the plot, default is "contourf" (contourf, contour)
|
497
|
+
fixed_colorscale: bool, whether to use fixed colorscale, default is False
|
498
|
+
|
499
|
+
Example:
|
500
|
+
draw(ncfile, output_dir, x_dim="longitude", y_dim="latitude", z_dim="level", t_dim="time", fixed_colorscale=False)
|
501
|
+
"""
|
502
|
+
if output_dir is None:
|
503
|
+
output_dir = str(os.getcwd())
|
504
|
+
if isinstance(xyzt_dims, (list, tuple)):
|
505
|
+
xyzt_dims = tuple(xyzt_dims)
|
506
|
+
else:
|
507
|
+
raise ValueError("xyzt_dims must be a list or tuple")
|
508
|
+
if dataset is not None:
|
509
|
+
func_plot_dataset(dataset, output_dir, xyzt_dims, plot_type, fixed_colorscale)
|
510
|
+
else:
|
511
|
+
if ncfile is not None:
|
512
|
+
if check(ncfile):
|
513
|
+
ds = xr.open_dataset(ncfile)
|
514
|
+
func_plot_dataset(ds, output_dir, xyzt_dims, plot_type, fixed_colorscale)
|
515
|
+
else:
|
516
|
+
print(f"Invalid file: {ncfile}")
|
517
|
+
else:
|
518
|
+
print("No dataset or file provided.")
|
519
|
+
|
520
|
+
|
521
|
+
if __name__ == "__main__":
|
522
|
+
data = np.random.rand(100, 50)
|
523
|
+
save(r"test.nc", data, "data", {"time": np.linspace(0, 120, 100), "lev": np.linspace(0, 120, 50)}, "a")
|
oafuncs/oa_python.py
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# coding=utf-8
|
3
|
+
'''
|
4
|
+
Author: Liu Kun && 16031215@qq.com
|
5
|
+
Date: 2024-10-11 21:02:07
|
6
|
+
LastEditors: Liu Kun && 16031215@qq.com
|
7
|
+
LastEditTime: 2024-11-21 10:59:53
|
8
|
+
FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_python.py
|
9
|
+
Description:
|
10
|
+
EditPlatform: vscode
|
11
|
+
ComputerInfo: XPS 15 9510
|
12
|
+
SystemInfo: Windows 11
|
13
|
+
Python Version: 3.11
|
14
|
+
'''
|
15
|
+
|
16
|
+
import os
|
17
|
+
from rich import print
|
18
|
+
|
19
|
+
__all__ = ['install_lib', 'upgrade_lib']
|
20
|
+
|
21
|
+
|
22
|
+
def install_lib(libs=None, python_exe='python'):
|
23
|
+
'''
|
24
|
+
libs: list, 需要安装的库
|
25
|
+
python_exe: str, python版本;如在windows下,将python.exe复制为python312.exe,然后python_exe='python312'
|
26
|
+
'''
|
27
|
+
os.system(python_exe + " -m ensurepip")
|
28
|
+
os.system(python_exe + " -m pip install --upgrade pip")
|
29
|
+
if libs is None:
|
30
|
+
libs = [
|
31
|
+
# "oafuncs", # 自己的库,在这个函数不宜操作,避免报错
|
32
|
+
"requests", # 网页
|
33
|
+
"xlwt", # excel文件
|
34
|
+
"xlrd", # excel文件
|
35
|
+
"openpyxl", # excel文件
|
36
|
+
"netCDF4", # nc文件
|
37
|
+
"numpy", # 数组
|
38
|
+
"pandas", # 数据
|
39
|
+
"xarray", # 数组
|
40
|
+
"scipy", # 科学计算
|
41
|
+
# "scikit-learn", # 机器学习
|
42
|
+
"matplotlib", # 绘图
|
43
|
+
# "seaborn",
|
44
|
+
"imageio", # 图像
|
45
|
+
# "pylustrator", # 绘图
|
46
|
+
"Cartopy", # 绘图 #cartopy已经支持python3.11并且可以直接pip安装
|
47
|
+
"seawater", # 海洋计算
|
48
|
+
"cmaps", # 颜色
|
49
|
+
"colorcet", # 颜色
|
50
|
+
"cmasher", # 颜色
|
51
|
+
"tqdm", # 进度条
|
52
|
+
# "taichi", # 加速
|
53
|
+
"icecream", # 打印调试
|
54
|
+
# "pyperclip", # 系统剪切板
|
55
|
+
"rich", # 精美文本终端
|
56
|
+
# "stratify", # 大气海洋数据垂直插值
|
57
|
+
"dask", # 并行计算
|
58
|
+
"bs4", # 网页
|
59
|
+
"pathlib", # 路径
|
60
|
+
"opencv-contrib-python", # 图像处理
|
61
|
+
# "pydap", # 网络数据xarray下载
|
62
|
+
"gsw", # 海洋计算
|
63
|
+
"global_land_mask", # 陆地海洋掩码
|
64
|
+
# "cfgrib", # grib文件
|
65
|
+
# "ecmwflibs", # grib文件, 两个库都需要安装
|
66
|
+
"geopandas", # 矢量数据,shp文件
|
67
|
+
# "geopy", # 地理位置
|
68
|
+
# "flask", # 网页
|
69
|
+
"cdsapi", # 网络数据下载(era5)
|
70
|
+
# 以下不太重要
|
71
|
+
"lxml", # 网页
|
72
|
+
"keyboard", # 键盘
|
73
|
+
"zhdate", # 中国农历
|
74
|
+
"python-pptx", # ppt
|
75
|
+
"python-docx", # word
|
76
|
+
"ipywidgets", # jupyter显示进度条插件
|
77
|
+
"salem", # 地图投影,可部分替代wrf-python
|
78
|
+
"meteva", # 气象数据处理,中国气象局开发
|
79
|
+
"wget", # 下载
|
80
|
+
"pyautogui", # 鼠标键盘,自动连点脚本需要
|
81
|
+
]
|
82
|
+
try:
|
83
|
+
installed_libs = os.popen(python_exe + ' -m pip list').read()
|
84
|
+
lib_num = len(libs)
|
85
|
+
for i, lib in enumerate(libs):
|
86
|
+
# 判断库是否已经安装,已安装跳过
|
87
|
+
if lib in installed_libs:
|
88
|
+
print(lib, "早已安装")
|
89
|
+
continue
|
90
|
+
else:
|
91
|
+
os.system(python_exe + " -m " + "pip install " + lib)
|
92
|
+
print('-'*100)
|
93
|
+
print("安装成功", lib, "({}/{})".format(i+1, lib_num))
|
94
|
+
print('-'*100)
|
95
|
+
except Exception as e:
|
96
|
+
print("安装失败:", str(e))
|
97
|
+
|
98
|
+
|
99
|
+
def upgrade_lib(libs=None, python_exe='python'):
|
100
|
+
if libs is None:
|
101
|
+
installed_libs = os.popen(python_exe + ' -m pip list').read()
|
102
|
+
libs = installed_libs
|
103
|
+
try:
|
104
|
+
for lib in libs:
|
105
|
+
os.system(python_exe + " -m " + "pip install --upgrade " + lib)
|
106
|
+
print("升级成功")
|
107
|
+
except Exception as e:
|
108
|
+
print("升级失败:", str(e))
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# coding=utf-8
|
3
|
+
'''
|
4
|
+
Author: Liu Kun && 16031215@qq.com
|
5
|
+
Date: 2024-09-17 16:09:20
|
6
|
+
LastEditors: Liu Kun && 16031215@qq.com
|
7
|
+
LastEditTime: 2024-10-14 18:12:12
|
8
|
+
FilePath: \\Python\\My_Funcs\\OAFuncs\\OAFuncs\\oa_sign\\__init__.py
|
9
|
+
Description:
|
10
|
+
EditPlatform: vscode
|
11
|
+
ComputerInfo: XPS 15 9510
|
12
|
+
SystemInfo: Windows 11
|
13
|
+
Python Version: 3.11
|
14
|
+
'''
|
15
|
+
|
16
|
+
# from .love_ocean import sign as love_ocean
|
17
|
+
# from .meteorological_home import sign as meteorological_home
|
18
|
+
|
19
|
+
from .ocean import *
|
20
|
+
from .meteorological import *
|
21
|
+
from .scientific import *
|