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_data.py
ADDED
@@ -0,0 +1,293 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# coding=utf-8
|
3
|
+
"""
|
4
|
+
Author: Liu Kun && 16031215@qq.com
|
5
|
+
Date: 2024-09-17 17:12:47
|
6
|
+
LastEditors: Liu Kun && 16031215@qq.com
|
7
|
+
LastEditTime: 2024-12-13 19:11:08
|
8
|
+
FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_data.py
|
9
|
+
Description:
|
10
|
+
EditPlatform: vscode
|
11
|
+
ComputerInfo: XPS 15 9510
|
12
|
+
SystemInfo: Windows 11
|
13
|
+
Python Version: 3.11
|
14
|
+
"""
|
15
|
+
|
16
|
+
import itertools
|
17
|
+
import multiprocessing as mp
|
18
|
+
from concurrent.futures import ThreadPoolExecutor
|
19
|
+
|
20
|
+
import numpy as np
|
21
|
+
import salem
|
22
|
+
import xarray as xr
|
23
|
+
from scipy.interpolate import griddata
|
24
|
+
from scipy.interpolate import interp1d
|
25
|
+
|
26
|
+
__all__ = ["interp_along_dim", "interp_2d", "ensure_list", "mask_shapefile"]
|
27
|
+
|
28
|
+
|
29
|
+
def ensure_list(input_data):
|
30
|
+
"""
|
31
|
+
Ensures that the input is converted into a list.
|
32
|
+
|
33
|
+
If the input is already a list, it returns it directly.
|
34
|
+
If the input is a string, it wraps it in a list and returns.
|
35
|
+
For other types of input, it converts them to a string and then wraps in a list.
|
36
|
+
|
37
|
+
:param input_data: The input which can be a list, a string, or any other type.
|
38
|
+
:return: A list containing the input or the string representation of the input.
|
39
|
+
"""
|
40
|
+
if isinstance(input_data, list):
|
41
|
+
return input_data
|
42
|
+
elif isinstance(input_data, str):
|
43
|
+
return [input_data]
|
44
|
+
else:
|
45
|
+
# For non-list and non-string inputs, convert to string and wrap in a list
|
46
|
+
return [str(input_data)]
|
47
|
+
|
48
|
+
|
49
|
+
def interp_along_dim(tgt_coords, src_coords, src_data, axis=-1, interp_method="linear", extrap_method="linear"):
|
50
|
+
"""
|
51
|
+
在指定维度上执行插值和外插操作。
|
52
|
+
|
53
|
+
Parameters:
|
54
|
+
-----------
|
55
|
+
tgt_coords: 1d array
|
56
|
+
目标坐标点数组,必须是一维数组。
|
57
|
+
|
58
|
+
src_coords: 1d or nd array
|
59
|
+
源坐标点数组。可以是一维数组(将被广播到与src_data匹配的形状)或与src_data相同形状的多维数组。
|
60
|
+
|
61
|
+
src_data: nd array
|
62
|
+
源数据数组,包含要从src_coords插值到tgt_coords的现象值。
|
63
|
+
|
64
|
+
axis: int (default -1)
|
65
|
+
要在src_data上执行插值的轴。默认为最后一个轴。
|
66
|
+
|
67
|
+
interp_method: str (default "linear")
|
68
|
+
核心插值方法。
|
69
|
+
可选值包括:
|
70
|
+
- "linear": 线性插值(默认)
|
71
|
+
- "nearest": 最近邻插值
|
72
|
+
- "zero": 零阶插值
|
73
|
+
- "slinear": 样条一阶插值
|
74
|
+
- "quadratic": 二阶插值
|
75
|
+
- "cubic": 三阶插值
|
76
|
+
- "previous": 使用前一个点的值
|
77
|
+
- "next": 使用后一个点的值
|
78
|
+
更多选项参考scipy.interpolate.interp1d的kind参数。
|
79
|
+
|
80
|
+
extrap_method: str (default "linear")
|
81
|
+
核心外插方法,用于处理超出源坐标范围的目标坐标点。
|
82
|
+
支持与interp_method相同的选项:
|
83
|
+
- "linear": 线性外插(默认)
|
84
|
+
- "nearest": 最近邻外插
|
85
|
+
- "zero": 零阶外插
|
86
|
+
- "slinear": 样条一阶外插
|
87
|
+
- "quadratic": 二阶外插
|
88
|
+
- "cubic": 三阶外插
|
89
|
+
- "previous": 使用最近的前一个点的值
|
90
|
+
- "next": 使用最近的后一个点的值
|
91
|
+
|
92
|
+
Returns:
|
93
|
+
--------
|
94
|
+
array
|
95
|
+
插值后的数据数组,形状将与src_data相同,但在axis轴上长度为len(tgt_coords)。
|
96
|
+
|
97
|
+
Examples:
|
98
|
+
---------
|
99
|
+
1D插值示例:
|
100
|
+
>>> tgt_coords = np.array([1, 2, 3, 4])
|
101
|
+
>>> src_coords = np.array([0, 1, 2, 3, 4, 5])
|
102
|
+
>>> src_data = np.array([0, 1, 4, 9, 16, 25])
|
103
|
+
>>> interp_along_dim(tgt_coords, src_coords, src_data)
|
104
|
+
array([ 1., 4., 9., 16.])
|
105
|
+
|
106
|
+
多维插值示例:
|
107
|
+
>>> src_data = np.array([[0, 1, 4], [10, 20, 30]])
|
108
|
+
>>> interp_along_dim(np.array([0.5, 1.5]), np.array([0, 1, 2]), src_data, axis=1)
|
109
|
+
array([[ 0.5, 2.5],
|
110
|
+
[15. , 25. ]])
|
111
|
+
"""
|
112
|
+
tgt_coords = np.asarray(tgt_coords)
|
113
|
+
if tgt_coords.ndim != 1:
|
114
|
+
raise ValueError("tgt_coords must be a 1d array.")
|
115
|
+
|
116
|
+
src_coords = np.asarray(src_coords)
|
117
|
+
src_data = np.asarray(src_data)
|
118
|
+
|
119
|
+
# 处理1维的简单情况
|
120
|
+
if src_data.ndim == 1 and src_coords.ndim == 1:
|
121
|
+
if len(src_coords) != len(src_data):
|
122
|
+
raise ValueError("For 1D data, src_coords and src_data must have the same length")
|
123
|
+
|
124
|
+
interpolator = interp1d(src_coords, src_data, kind=interp_method, fill_value="extrapolate", bounds_error=False)
|
125
|
+
return interpolator(tgt_coords)
|
126
|
+
|
127
|
+
# 多维情况的处理
|
128
|
+
if src_coords.ndim == 1:
|
129
|
+
# Expand src_coords to match src_data dimensions along the specified axis
|
130
|
+
shape = [1] * src_data.ndim
|
131
|
+
shape[axis] = src_coords.shape[0]
|
132
|
+
src_coords = np.reshape(src_coords, shape)
|
133
|
+
src_coords = np.broadcast_to(src_coords, src_data.shape)
|
134
|
+
elif src_coords.shape != src_data.shape:
|
135
|
+
raise ValueError("src_coords and src_data must have the same shape.")
|
136
|
+
|
137
|
+
def apply_interp_extrap(arr):
|
138
|
+
xp = np.moveaxis(src_coords, axis, 0)
|
139
|
+
# 根据维度正确获取坐标
|
140
|
+
if xp.ndim > 1:
|
141
|
+
xp = xp[:, 0] # 多维情况
|
142
|
+
else:
|
143
|
+
xp = xp # 1维情况
|
144
|
+
|
145
|
+
arr = np.moveaxis(arr, axis, 0)
|
146
|
+
interpolator = interp1d(xp, arr, kind=interp_method, fill_value="extrapolate", bounds_error=False)
|
147
|
+
interpolated = interpolator(tgt_coords)
|
148
|
+
if extrap_method != interp_method:
|
149
|
+
mask_extrap = (tgt_coords < xp.min()) | (tgt_coords > xp.max())
|
150
|
+
if np.any(mask_extrap):
|
151
|
+
extrap_interpolator = interp1d(xp, arr, kind=extrap_method, fill_value="extrapolate", bounds_error=False)
|
152
|
+
interpolated[mask_extrap] = extrap_interpolator(tgt_coords[mask_extrap])
|
153
|
+
return np.moveaxis(interpolated, 0, axis)
|
154
|
+
|
155
|
+
result = np.apply_along_axis(apply_interp_extrap, axis, src_data)
|
156
|
+
|
157
|
+
return result
|
158
|
+
|
159
|
+
|
160
|
+
def interp_2d(target_x, target_y, origin_x, origin_y, data, method="linear", parallel=True):
|
161
|
+
"""
|
162
|
+
Perform 2D interpolation on the last two dimensions of a multi-dimensional array.
|
163
|
+
|
164
|
+
Parameters:
|
165
|
+
- target_x (array-like): 1D or 2D array of target grid's x-coordinates.
|
166
|
+
- target_y (array-like): 1D or 2D array of target grid's y-coordinates.
|
167
|
+
- origin_x (array-like): 1D or 2D array of original grid's x-coordinates.
|
168
|
+
- origin_y (array-like): 1D or 2D array of original grid's y-coordinates.
|
169
|
+
- data (numpy.ndarray): Multi-dimensional array where the last two dimensions correspond to the original grid.
|
170
|
+
- method (str, optional): Interpolation method, default is 'linear'. Other options include 'nearest', 'cubic', etc.
|
171
|
+
- parallel (bool, optional): Flag to enable parallel processing. Default is True.
|
172
|
+
|
173
|
+
Returns:
|
174
|
+
- interpolated_data (numpy.ndarray): Interpolated data with the same leading dimensions as the input data, but with the last two dimensions corresponding to the target grid.
|
175
|
+
|
176
|
+
Raises:
|
177
|
+
- ValueError: If the shape of the data does not match the shape of the origin_x or origin_y grids.
|
178
|
+
|
179
|
+
Usage:
|
180
|
+
- Interpolate a 2D array:
|
181
|
+
result = interp_2d(target_x, target_y, origin_x, origin_y, data_2d)
|
182
|
+
- Interpolate a 3D array (where the last two dimensions are spatial):
|
183
|
+
result = interp_2d(target_x, target_y, origin_x, origin_y, data_3d)
|
184
|
+
- Interpolate a 4D array (where the last two dimensions are spatial):
|
185
|
+
result = interp_2d(target_x, target_y, origin_x, origin_y, data_4d)
|
186
|
+
"""
|
187
|
+
|
188
|
+
def interp_single(data_slice, target_points, origin_points, method):
|
189
|
+
return griddata(origin_points, data_slice.ravel(), target_points, method=method).reshape(target_y.shape)
|
190
|
+
|
191
|
+
# 确保目标网格和初始网格都是二维的
|
192
|
+
if len(target_y.shape) == 1:
|
193
|
+
target_x, target_y = np.meshgrid(target_x, target_y)
|
194
|
+
if len(origin_y.shape) == 1:
|
195
|
+
origin_x, origin_y = np.meshgrid(origin_x, origin_y)
|
196
|
+
|
197
|
+
# 根据经纬度网格判断输入数据的形状是否匹配
|
198
|
+
if origin_x.shape != data.shape[-2:] or origin_y.shape != data.shape[-2:]:
|
199
|
+
raise ValueError("Shape of data does not match shape of origin_x or origin_y.")
|
200
|
+
|
201
|
+
# 创建网格和展平数据
|
202
|
+
target_x, target_y = np.array(target_x), np.array(target_y)
|
203
|
+
origin_x, origin_y = np.array(origin_x), np.array(origin_y)
|
204
|
+
target_points = np.column_stack((target_y.ravel(), target_x.ravel()))
|
205
|
+
origin_points = np.column_stack((origin_y.ravel(), origin_x.ravel()))
|
206
|
+
|
207
|
+
# 根据是否并行选择不同的执行方式
|
208
|
+
if parallel:
|
209
|
+
with ThreadPoolExecutor(max_workers=mp.cpu_count() - 2) as executor:
|
210
|
+
if len(data.shape) == 2:
|
211
|
+
interpolated_data = list(executor.map(interp_single, [data], [target_points], [origin_points], [method]))
|
212
|
+
elif len(data.shape) == 3:
|
213
|
+
interpolated_data = list(executor.map(interp_single, [data[i] for i in range(data.shape[0])], [target_points] * data.shape[0], [origin_points] * data.shape[0], [method] * data.shape[0]))
|
214
|
+
elif len(data.shape) == 4:
|
215
|
+
index_combinations = list(itertools.product(range(data.shape[0]), range(data.shape[1])))
|
216
|
+
interpolated_data = list(executor.map(interp_single, [data[i, j] for i, j in index_combinations], [target_points] * len(index_combinations), [origin_points] * len(index_combinations), [method] * len(index_combinations)))
|
217
|
+
interpolated_data = np.array(interpolated_data).reshape(data.shape[0], data.shape[1], *target_y.shape)
|
218
|
+
else:
|
219
|
+
if len(data.shape) == 2:
|
220
|
+
interpolated_data = interp_single(data, target_points, origin_points, method)
|
221
|
+
elif len(data.shape) == 3:
|
222
|
+
interpolated_data = np.stack([interp_single(data[i], target_points, origin_points, method) for i in range(data.shape[0])])
|
223
|
+
elif len(data.shape) == 4:
|
224
|
+
interpolated_data = np.stack([np.stack([interp_single(data[i, j], target_points, origin_points, method) for j in range(data.shape[1])]) for i in range(data.shape[0])])
|
225
|
+
|
226
|
+
return np.squeeze(np.array(interpolated_data))
|
227
|
+
|
228
|
+
|
229
|
+
def mask_shapefile(data: np.ndarray, lons: np.ndarray, lats: np.ndarray, shapefile_path: str) -> xr.DataArray:
|
230
|
+
"""
|
231
|
+
Masks a 2D data array using a shapefile.
|
232
|
+
|
233
|
+
Parameters:
|
234
|
+
- data: 2D numpy array of data to be masked.
|
235
|
+
- lons: 1D numpy array of longitudes.
|
236
|
+
- lats: 1D numpy array of latitudes.
|
237
|
+
- shapefile_path: Path to the shapefile used for masking.
|
238
|
+
|
239
|
+
Returns:
|
240
|
+
- Masked xarray DataArray.
|
241
|
+
"""
|
242
|
+
"""
|
243
|
+
https://cloud.tencent.com/developer/article/1701896
|
244
|
+
"""
|
245
|
+
try:
|
246
|
+
# import geopandas as gpd
|
247
|
+
# shp_f = gpd.read_file(shapefile_path)
|
248
|
+
shp_f = salem.read_shapefile(shapefile_path)
|
249
|
+
data_da = xr.DataArray(data, coords=[("latitude", lats), ("longitude", lons)])
|
250
|
+
masked_data = data_da.salem.roi(shape=shp_f)
|
251
|
+
return masked_data
|
252
|
+
except Exception as e:
|
253
|
+
print(f"An error occurred: {e}")
|
254
|
+
return None
|
255
|
+
|
256
|
+
|
257
|
+
if __name__ == "__main__":
|
258
|
+
pass
|
259
|
+
""" import time
|
260
|
+
|
261
|
+
import matplotlib.pyplot as plt
|
262
|
+
|
263
|
+
# 测试数据
|
264
|
+
origin_x = np.linspace(0, 10, 11)
|
265
|
+
origin_y = np.linspace(0, 10, 11)
|
266
|
+
target_x = np.linspace(0, 10, 101)
|
267
|
+
target_y = np.linspace(0, 10, 101)
|
268
|
+
data = np.random.rand(11, 11)
|
269
|
+
|
270
|
+
# 高维插值
|
271
|
+
origin_x = np.linspace(0, 10, 11)
|
272
|
+
origin_y = np.linspace(0, 10, 11)
|
273
|
+
target_x = np.linspace(0, 10, 101)
|
274
|
+
target_y = np.linspace(0, 10, 101)
|
275
|
+
data = np.random.rand(10, 10, 11, 11)
|
276
|
+
|
277
|
+
start = time.time()
|
278
|
+
interpolated_data = interp_2d(target_x, target_y, origin_x, origin_y, data, parallel=False)
|
279
|
+
print(f"Interpolation time: {time.time()-start:.2f}s")
|
280
|
+
|
281
|
+
print(interpolated_data.shape)
|
282
|
+
|
283
|
+
# 高维插值多线程
|
284
|
+
start = time.time()
|
285
|
+
interpolated_data = interp_2d(target_x, target_y, origin_x, origin_y, data)
|
286
|
+
print(f"Interpolation time: {time.time()-start:.2f}s")
|
287
|
+
|
288
|
+
print(interpolated_data.shape)
|
289
|
+
print(interpolated_data[0, 0, :, :].shape)
|
290
|
+
plt.figure()
|
291
|
+
plt.contourf(target_x, target_y, interpolated_data[0, 0, :, :])
|
292
|
+
plt.colorbar()
|
293
|
+
plt.show() """
|