oafuncs 0.0.98.26__py3-none-any.whl → 0.0.98.27__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 +1 -88
- {oafuncs-0.0.98.26.dist-info → oafuncs-0.0.98.27.dist-info}/METADATA +1 -1
- {oafuncs-0.0.98.26.dist-info → oafuncs-0.0.98.27.dist-info}/RECORD +6 -7
- oafuncs/_script/data_interp_geo.py +0 -191
- {oafuncs-0.0.98.26.dist-info → oafuncs-0.0.98.27.dist-info}/WHEEL +0 -0
- {oafuncs-0.0.98.26.dist-info → oafuncs-0.0.98.27.dist-info}/licenses/LICENSE.txt +0 -0
- {oafuncs-0.0.98.26.dist-info → oafuncs-0.0.98.27.dist-info}/top_level.txt +0 -0
oafuncs/oa_data.py
CHANGED
@@ -1,18 +1,3 @@
|
|
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
1
|
from typing import Any, List, Union
|
17
2
|
|
18
3
|
import numpy as np
|
@@ -21,7 +6,7 @@ import xarray as xr
|
|
21
6
|
from rich import print
|
22
7
|
from scipy.interpolate import interp1d
|
23
8
|
|
24
|
-
__all__ = ["interp_along_dim", "interp_2d", "
|
9
|
+
__all__ = ["interp_along_dim", "interp_2d", "ensure_list", "mask_shapefile"]
|
25
10
|
|
26
11
|
|
27
12
|
def ensure_list(input_value: Any) -> List[str]:
|
@@ -150,8 +135,6 @@ def interp_2d(
|
|
150
135
|
>>> print(result.shape) # Expected output: (3, 3)
|
151
136
|
"""
|
152
137
|
from ._script.data_interp import interp_2d_func
|
153
|
-
|
154
|
-
source_data = np.asarray(source_data)
|
155
138
|
|
156
139
|
return interp_2d_func(
|
157
140
|
target_x_coordinates=target_x_coordinates,
|
@@ -163,76 +146,6 @@ def interp_2d(
|
|
163
146
|
)
|
164
147
|
|
165
148
|
|
166
|
-
def interp_2d_geo(
|
167
|
-
target_x_coordinates: Union[np.ndarray, List[float]],
|
168
|
-
target_y_coordinates: Union[np.ndarray, List[float]],
|
169
|
-
source_x_coordinates: Union[np.ndarray, List[float]],
|
170
|
-
source_y_coordinates: Union[np.ndarray, List[float]],
|
171
|
-
source_data: np.ndarray,
|
172
|
-
use_parallel: bool = True,
|
173
|
-
) -> np.ndarray:
|
174
|
-
"""
|
175
|
-
使用pyinterp进行地理插值,适用于全球尺度的地理数据与区域数据。
|
176
|
-
|
177
|
-
特点:
|
178
|
-
- 正确处理经度跨越日期线的情况
|
179
|
-
- 自动选择最佳插值策略
|
180
|
-
- 处理规则网格和非规则数据
|
181
|
-
- 支持多维数据并行处理
|
182
|
-
|
183
|
-
Args:
|
184
|
-
target_x_coordinates: 目标点经度 (-180 to 180 或 0 to 360)
|
185
|
-
target_y_coordinates: 目标点纬度 (-90 to 90)
|
186
|
-
source_x_coordinates: 源数据经度 (-180 to 180 或 0 to 360)
|
187
|
-
source_y_coordinates: 源数据纬度 (-90 to 90)
|
188
|
-
source_data: 多维数组,最后两个维度为空间维度
|
189
|
-
interpolation_method: 插值方法: 只会使用 'bicubic' 方法。
|
190
|
-
use_parallel: 是否使用并行处理,默认开启。
|
191
|
-
|
192
|
-
Returns:
|
193
|
-
np.ndarray: 插值后的数据数组
|
194
|
-
|
195
|
-
Examples:
|
196
|
-
>>> # 全球数据插值示例
|
197
|
-
>>> target_lon = np.arange(-180, 181, 1)
|
198
|
-
>>> target_lat = np.arange(-90, 91, 1)
|
199
|
-
>>> source_lon = np.arange(-180, 181, 5)
|
200
|
-
>>> source_lat = np.arange(-90, 91, 5)
|
201
|
-
>>> source_data = np.cos(np.deg2rad(source_lat.reshape(-1, 1))) * np.cos(np.deg2rad(source_lon))
|
202
|
-
>>> result = interp_2d_geo(target_lon, target_lat, source_lon, source_lat, source_data)
|
203
|
-
"""
|
204
|
-
# 使用importlib检查pyinterp是否可用,避免直接import导致的警告
|
205
|
-
import importlib.util
|
206
|
-
|
207
|
-
pyinterp_available = importlib.util.find_spec("pyinterp") is not None
|
208
|
-
|
209
|
-
if pyinterp_available:
|
210
|
-
# 只在pyinterp可用时才导入相关模块
|
211
|
-
from ._script.data_interp_geo import interp_2d_func_geo
|
212
|
-
|
213
|
-
return interp_2d_func_geo(
|
214
|
-
target_x_coordinates=target_x_coordinates,
|
215
|
-
target_y_coordinates=target_y_coordinates,
|
216
|
-
source_x_coordinates=source_x_coordinates,
|
217
|
-
source_y_coordinates=source_y_coordinates,
|
218
|
-
source_data=np.array(source_data),
|
219
|
-
use_parallel=use_parallel,
|
220
|
-
)
|
221
|
-
else:
|
222
|
-
print("[yellow]警告: pyinterp模块未安装,无法使用球面坐标插值。尝试使用平面插值作为备选方案。[/yellow]")
|
223
|
-
print("[yellow]推荐使用 pip install pyinterp 安装pyinterp以获得更准确的地理数据插值结果。[/yellow]")
|
224
|
-
try:
|
225
|
-
return interp_2d(
|
226
|
-
target_x_coordinates=target_x_coordinates,
|
227
|
-
target_y_coordinates=target_y_coordinates,
|
228
|
-
source_x_coordinates=source_x_coordinates,
|
229
|
-
source_y_coordinates=source_y_coordinates,
|
230
|
-
source_data=source_data,
|
231
|
-
)
|
232
|
-
except Exception as e:
|
233
|
-
raise ImportError(f"pyinterp不可用且备选插值方法也失败: {e}")
|
234
|
-
|
235
|
-
|
236
149
|
def mask_shapefile(
|
237
150
|
data_array: np.ndarray,
|
238
151
|
longitudes: np.ndarray,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
oafuncs/__init__.py,sha256=T_-VtnWWllV3Q91twT5Yt2sUapeA051QbPNnBxmg9nw,1456
|
2
2
|
oafuncs/oa_cmap.py,sha256=pUFAGzbIg0WLxObBP2t_--ZIg00Dxdojx0y7OjTeqEo,11551
|
3
|
-
oafuncs/oa_data.py,sha256=
|
3
|
+
oafuncs/oa_data.py,sha256=Wp7Yn6n-WNddAp1UtwK5CSEdGSrzzgOH5gtaOHBaxtw,8065
|
4
4
|
oafuncs/oa_date.py,sha256=WhM6cyD4G3IeghjLTHhAMtlvJbA7kwQG2sHnxdTgyso,6303
|
5
5
|
oafuncs/oa_draw.py,sha256=IaBGDx-EOxyMM2IuJ4zLZt6ruHHV5qFStPItmUOXoWk,17635
|
6
6
|
oafuncs/oa_file.py,sha256=j9gXJgPOJsliu4IOUc4bc-luW4yBvQyNCEmMyDVjUwQ,16404
|
@@ -12,7 +12,6 @@ oafuncs/_data/hycom.png,sha256=MadKs6Gyj5n9-TOu7L4atQfTXtF9dvN9w-tdU9IfygI,10945
|
|
12
12
|
oafuncs/_data/oafuncs.png,sha256=o3VD7wm-kwDea5E98JqxXl04_78cBX7VcdUt7uQXGiU,3679898
|
13
13
|
oafuncs/_script/cprogressbar.py,sha256=UIgGcLFs-6IgWlITuBLaQqrpt4OAK3Mst5RlCiNfZdQ,15772
|
14
14
|
oafuncs/_script/data_interp.py,sha256=EiZbt6n5BEaRKcng88UgX7TFPhKE6TLVZniS01awXjg,5146
|
15
|
-
oafuncs/_script/data_interp_geo.py,sha256=5ozhMcTTKiw-182scSvBa2s7EuF43P0tv9rLcQv37kc,7313
|
16
15
|
oafuncs/_script/email.py,sha256=lL4HGKrr524-g0xLlgs-4u7x4-u7DtgNoD9AL8XJKj4,3058
|
17
16
|
oafuncs/_script/netcdf_merge.py,sha256=tM9ePqLiEsE7eIsNM5XjEYeXwxjYOdNz5ejnEuI7xKw,6066
|
18
17
|
oafuncs/_script/netcdf_modify.py,sha256=sGRUYNhfGgf9JV70rnBzw3bzuTRSXzBTL_RMDnDPeLQ,4552
|
@@ -39,8 +38,8 @@ oafuncs/oa_sign/__init__.py,sha256=QKqTFrJDFK40C5uvk48GlRRbGFzO40rgkYwu6dYxatM,5
|
|
39
38
|
oafuncs/oa_sign/meteorological.py,sha256=8091SHo2L8kl4dCFmmSH5NGVHDku5i5lSiLEG5DLnOQ,6489
|
40
39
|
oafuncs/oa_sign/ocean.py,sha256=xrW-rWD7xBWsB5PuCyEwQ1Q_RDKq2KCLz-LOONHgldU,5932
|
41
40
|
oafuncs/oa_sign/scientific.py,sha256=a4JxOBgm9vzNZKpJ_GQIQf7cokkraV5nh23HGbmTYKw,5064
|
42
|
-
oafuncs-0.0.98.
|
43
|
-
oafuncs-0.0.98.
|
44
|
-
oafuncs-0.0.98.
|
45
|
-
oafuncs-0.0.98.
|
46
|
-
oafuncs-0.0.98.
|
41
|
+
oafuncs-0.0.98.27.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
|
42
|
+
oafuncs-0.0.98.27.dist-info/METADATA,sha256=hz_q6P9Mu1TkhuD9gychMUh7lE9pqMZl50PtKLHYTGo,4273
|
43
|
+
oafuncs-0.0.98.27.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
44
|
+
oafuncs-0.0.98.27.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
|
45
|
+
oafuncs-0.0.98.27.dist-info/RECORD,,
|
@@ -1,191 +0,0 @@
|
|
1
|
-
import importlib.util
|
2
|
-
from typing import List, Union
|
3
|
-
|
4
|
-
import numpy as np
|
5
|
-
|
6
|
-
from oafuncs.oa_tool import PEx
|
7
|
-
|
8
|
-
# 检查pyinterp是否可用
|
9
|
-
pyinterp_available = importlib.util.find_spec("pyinterp") is not None
|
10
|
-
|
11
|
-
if pyinterp_available:
|
12
|
-
import pyinterp
|
13
|
-
import pyinterp.backends.xarray as pyxr
|
14
|
-
import xarray as xr
|
15
|
-
|
16
|
-
|
17
|
-
def _fill_nan_with_nearest(data: np.ndarray, source_lons: np.ndarray, source_lats: np.ndarray) -> np.ndarray:
|
18
|
-
"""
|
19
|
-
使用最近邻方法填充NaN值,适合地理数据。
|
20
|
-
"""
|
21
|
-
if not np.isnan(data).any():
|
22
|
-
return data
|
23
|
-
|
24
|
-
# 创建掩码,区分有效值和NaN值
|
25
|
-
mask = ~np.isnan(data)
|
26
|
-
if not np.any(mask):
|
27
|
-
return data # 全是NaN,无法填充
|
28
|
-
|
29
|
-
# 使用pyinterp的RTree进行最近邻插值填充NaN
|
30
|
-
try:
|
31
|
-
if not pyinterp_available:
|
32
|
-
raise ImportError("pyinterp not available")
|
33
|
-
|
34
|
-
# 获取有效数据点的位置和值
|
35
|
-
valid_points = np.column_stack((source_lons[mask].ravel(), source_lats[mask].ravel()))
|
36
|
-
valid_values = data[mask].ravel()
|
37
|
-
|
38
|
-
# 创建RTree
|
39
|
-
tree = pyinterp.RTree()
|
40
|
-
tree.insert(valid_points.astype(np.float64), valid_values.astype(np.float64))
|
41
|
-
|
42
|
-
# 获取所有点的坐标
|
43
|
-
all_points = np.column_stack((source_lons.ravel(), source_lats.ravel()))
|
44
|
-
|
45
|
-
# 最近邻插值
|
46
|
-
filled_values = tree.query(all_points[:, 0], all_points[:, 1], k=1)
|
47
|
-
|
48
|
-
return filled_values.reshape(data.shape)
|
49
|
-
|
50
|
-
except Exception:
|
51
|
-
# 备选方案:使用scipy的最近邻
|
52
|
-
from scipy.interpolate import NearestNDInterpolator
|
53
|
-
|
54
|
-
points = np.column_stack((source_lons[mask].ravel(), source_lats[mask].ravel()))
|
55
|
-
values = data[mask].ravel()
|
56
|
-
|
57
|
-
if len(values) > 0:
|
58
|
-
interp = NearestNDInterpolator(points, values)
|
59
|
-
return interp(source_lons.ravel(), source_lats.ravel()).reshape(data.shape)
|
60
|
-
else:
|
61
|
-
return data # 无有效值可用于填充
|
62
|
-
|
63
|
-
|
64
|
-
def _interp_single_worker(*args):
|
65
|
-
"""
|
66
|
-
单slice插值worker,只使用pyinterp的bicubic方法,失败直接报错。
|
67
|
-
参数: data_slice, source_lons, source_lats, target_lons, target_lats
|
68
|
-
"""
|
69
|
-
if not pyinterp_available:
|
70
|
-
raise ImportError("pyinterp package is required for geographic interpolation")
|
71
|
-
|
72
|
-
data_slice, source_lons, source_lats, target_lons, target_lats = args
|
73
|
-
|
74
|
-
# 预处理:填充NaN值以确保数据完整
|
75
|
-
if np.isnan(data_slice).any():
|
76
|
-
data_filled = _fill_nan_with_nearest(data_slice, source_lons, source_lats)
|
77
|
-
else:
|
78
|
-
data_filled = data_slice
|
79
|
-
|
80
|
-
# 创建xarray DataArray
|
81
|
-
|
82
|
-
da = xr.DataArray(
|
83
|
-
data_filled,
|
84
|
-
coords={"lat": source_lats, "lon": source_lons},
|
85
|
-
dims=("lat", "lon"),
|
86
|
-
)
|
87
|
-
|
88
|
-
# 创建Grid2D对象
|
89
|
-
grid = pyxr.Grid2D(da)
|
90
|
-
|
91
|
-
# 使用bicubic方法插值
|
92
|
-
result = grid.bicubic(coords={"lon": target_lons.flatten(), "lat": target_lats.flatten()}, bounds_error=False, num_threads=1).reshape(target_lons.shape)
|
93
|
-
|
94
|
-
return result
|
95
|
-
|
96
|
-
|
97
|
-
def interp_2d_func_geo(
|
98
|
-
target_x_coordinates: Union[np.ndarray, List[float]],
|
99
|
-
target_y_coordinates: Union[np.ndarray, List[float]],
|
100
|
-
source_x_coordinates: Union[np.ndarray, List[float]],
|
101
|
-
source_y_coordinates: Union[np.ndarray, List[float]],
|
102
|
-
source_data: np.ndarray,
|
103
|
-
use_parallel: bool = True,
|
104
|
-
) -> np.ndarray:
|
105
|
-
"""
|
106
|
-
使用pyinterp进行地理插值,只使用bicubic方法。
|
107
|
-
|
108
|
-
Args:
|
109
|
-
target_x_coordinates: 目标点经度 (-180 to 180 或 0 to 360)
|
110
|
-
target_y_coordinates: 目标点纬度 (-90 to 90)
|
111
|
-
source_x_coordinates: 源数据经度 (-180 to 180 或 0 to 360)
|
112
|
-
source_y_coordinates: 源数据纬度 (-90 to 90)
|
113
|
-
source_data: 多维数组,最后两个维度为空间维度
|
114
|
-
|
115
|
-
Returns:
|
116
|
-
np.ndarray: 插值后的数据数组
|
117
|
-
"""
|
118
|
-
if not pyinterp_available:
|
119
|
-
raise ImportError("pyinterp package is required for geographic interpolation")
|
120
|
-
|
121
|
-
# 验证纬度范围
|
122
|
-
if np.nanmin(target_y_coordinates) < -90 or np.nanmax(target_y_coordinates) > 90:
|
123
|
-
raise ValueError("Target latitude must be in range [-90, 90].")
|
124
|
-
if np.nanmin(source_y_coordinates) < -90 or np.nanmax(source_y_coordinates) > 90:
|
125
|
-
raise ValueError("Source latitude must be in range [-90, 90].")
|
126
|
-
|
127
|
-
# 确保使用numpy数组
|
128
|
-
source_x_coordinates = np.array(source_x_coordinates)
|
129
|
-
source_y_coordinates = np.array(source_y_coordinates)
|
130
|
-
target_x_coordinates = np.array(target_x_coordinates)
|
131
|
-
target_y_coordinates = np.array(target_y_coordinates)
|
132
|
-
|
133
|
-
# 创建网格坐标(如果是一维的)
|
134
|
-
if source_x_coordinates.ndim == 1:
|
135
|
-
source_x_coordinates, source_y_coordinates = np.meshgrid(source_x_coordinates, source_y_coordinates)
|
136
|
-
if target_x_coordinates.ndim == 1:
|
137
|
-
target_x_coordinates, target_y_coordinates = np.meshgrid(target_x_coordinates, target_y_coordinates)
|
138
|
-
|
139
|
-
# 验证源数据形状
|
140
|
-
if source_x_coordinates.shape != source_data.shape[-2:] or source_y_coordinates.shape != source_data.shape[-2:]:
|
141
|
-
raise ValueError("Shape of source_data does not match shape of source_x_coordinates or source_y_coordinates.")
|
142
|
-
|
143
|
-
# 处理多维数据
|
144
|
-
data_dims = source_data.ndim
|
145
|
-
if data_dims < 2:
|
146
|
-
raise ValueError(f"Source data must have at least 2 dimensions, but got {data_dims}.")
|
147
|
-
elif data_dims > 4:
|
148
|
-
raise ValueError(f"Source data has {data_dims} dimensions, but this function currently supports up to 4.")
|
149
|
-
|
150
|
-
# 扩展到4D
|
151
|
-
num_dims_to_add = 4 - data_dims
|
152
|
-
source_data = source_data.reshape((1,) * num_dims_to_add + source_data.shape)
|
153
|
-
t, z, y, x = source_data.shape
|
154
|
-
|
155
|
-
if use_parallel:
|
156
|
-
# 准备并行处理参数
|
157
|
-
params = []
|
158
|
-
for t_index in range(t):
|
159
|
-
for z_index in range(z):
|
160
|
-
params.append(
|
161
|
-
(
|
162
|
-
source_data[t_index, z_index],
|
163
|
-
source_x_coordinates[0, :], # 假设经度在每行都相同
|
164
|
-
source_y_coordinates[:, 0], # 假设纬度在每列都相同
|
165
|
-
target_x_coordinates,
|
166
|
-
target_y_coordinates,
|
167
|
-
)
|
168
|
-
)
|
169
|
-
|
170
|
-
# 并行执行插值
|
171
|
-
with PEx() as executor:
|
172
|
-
results = executor.run(_interp_single_worker, params)
|
173
|
-
|
174
|
-
# 还原到原始维度
|
175
|
-
return np.squeeze(np.array(results).reshape((t, z) + target_x_coordinates.shape))
|
176
|
-
else:
|
177
|
-
# 单线程处理
|
178
|
-
results = []
|
179
|
-
for t_index in range(t):
|
180
|
-
for z_index in range(z):
|
181
|
-
result = _interp_single_worker(
|
182
|
-
source_data[t_index, z_index],
|
183
|
-
source_x_coordinates[0, :], # 假设经度在每行都相同
|
184
|
-
source_y_coordinates[:, 0], # 假设纬度在每列都相同
|
185
|
-
target_x_coordinates,
|
186
|
-
target_y_coordinates,
|
187
|
-
)
|
188
|
-
results.append(result)
|
189
|
-
|
190
|
-
# 还原到原始维度
|
191
|
-
return np.squeeze(np.array(results).reshape((t, z) + target_x_coordinates.shape))
|
File without changes
|
File without changes
|
File without changes
|