oafuncs 0.0.98.16__py3-none-any.whl → 0.0.98.17__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.
@@ -2,51 +2,88 @@ import importlib.util
2
2
  from typing import List, Union
3
3
 
4
4
  import numpy as np
5
- from oafuncs.oa_tool import PEx
6
5
  from scipy.interpolate import griddata
7
6
 
7
+ from oafuncs.oa_tool import PEx
8
+
9
+ # 检查 pykdtree 是否可用
8
10
  _has_pykdtree = importlib.util.find_spec("pykdtree.kdtree") is not None
9
11
 
10
12
 
11
- def _fill_nan_nearest(arr):
12
- """用最近邻插值填充 NaN,优先用pykdtree加速"""
13
+ def _fill_nan_nearest(arr: np.ndarray) -> np.ndarray:
14
+ """
15
+ 用最近邻填充 NaN(只支持2D数组)
16
+ """
17
+ # 基础检查:如果输入为None,直接返回None
18
+ if arr is None:
19
+ return None
20
+
21
+ # 确保是2D ndarray
22
+ arr = np.asarray(arr)
23
+ if arr.ndim != 2:
24
+ raise ValueError(f"_fill_nan_nearest 只支持2D数组,但输入的维度是 {arr.ndim}")
25
+
26
+ # 保存原始dtype并转为float
27
+ orig_dtype = arr.dtype
28
+ arr = arr.astype(float, copy=True) # 使用copy=True确保不修改原数据
29
+
30
+ # 检查是否有NaN需要填充
13
31
  mask = np.isnan(arr)
14
32
  if not mask.any():
15
- return arr
16
- if _has_pykdtree:
17
- from pykdtree.kdtree import KDTree
18
-
19
- valid_idx = np.array(np.where(~mask)).T
20
- nan_idx = np.array(np.where(mask)).T
21
- if len(valid_idx) == 0:
22
- # 全是nan,直接返回
23
- return arr
24
- tree = KDTree(valid_idx)
25
- dist, idx = tree.query(nan_idx, k=1)
26
- filled = arr.copy()
27
- # idx shape: (n_nan, 1),valid_idx shape: (n_valid, ndim)
28
- # valid_idx[idx].T shape: (ndim, n_nan)
29
- filled[tuple(nan_idx.T)] = arr[tuple(valid_idx[idx.flatten()].T)]
30
- return filled
31
- else:
32
- from scipy.ndimage import distance_transform_edt
33
-
34
- idx = distance_transform_edt(mask, return_distances=False, return_indices=True)
35
- return arr[tuple(idx)]
36
-
37
-
38
- def _data_clip(data, data_min, data_max):
33
+ return arr.copy()
34
+
35
+ try:
36
+ valid = np.array(np.where(~mask)).T
37
+ invalid = np.array(np.where(mask)).T
38
+
39
+ # 如果有效点为空,直接返回原数据
40
+ if valid.shape[0] == 0:
41
+ return arr.copy()
42
+
43
+ # 使用KDTree进行最近邻填充
44
+ if _has_pykdtree:
45
+ from pykdtree.kdtree import KDTree
46
+
47
+ tree = KDTree(valid)
48
+ _, idx = tree.query(invalid, k=1)
49
+ filled = arr.copy()
50
+ filled[tuple(invalid.T)] = arr[tuple(valid[idx.flatten()].T)]
51
+ else:
52
+ # 备用方法:使用scipy的distance_transform_edt
53
+ from scipy.ndimage import distance_transform_edt
54
+
55
+ idx = distance_transform_edt(mask, return_distances=False, return_indices=True)
56
+ filled = arr[tuple(idx)]
57
+
58
+ return filled.astype(orig_dtype)
59
+ except Exception as e:
60
+ import warnings
61
+
62
+ warnings.warn(f"Error in _fill_nan_nearest: {e}, shape={arr.shape}")
63
+ return arr.copy() # 发生异常返回原始数据
64
+
65
+
66
+ def _data_clip(data: np.ndarray, data_min, data_max) -> np.ndarray:
39
67
  """
40
- 对data进行范围裁剪,超出范围的点设为nan,并用fill_nan_nearest填充,最后再次填充极端nan。
68
+ 将数据裁剪至 [data_min, data_max],超出或 NaN 用最近邻填补。
69
+ 支持 1~4D。
41
70
  """
42
- arr = np.asarray(data)
71
+ arr = np.array(data, copy=True) # 使用副本避免修改原数据
72
+ ndims = arr.ndim
73
+ if ndims != 2:
74
+ raise ValueError(f"_data_clip 只支持1~4维数组,但输入的维度是 {ndims}")
75
+ dtype = arr.dtype
76
+
77
+ # 检查是否需要裁剪
43
78
  mask = np.isnan(arr) | (arr < data_min) | (arr > data_max)
44
- if np.any(mask):
45
- arr = np.where(mask, np.nan, arr)
46
- arr = _fill_nan_nearest(arr)
47
- if np.any(np.isnan(arr)):
48
- arr = _fill_nan_nearest(arr)
49
- return arr
79
+ if not np.any(mask):
80
+ return arr.astype(dtype)
81
+
82
+ # 将超出范围的值设为NaN
83
+ arr[mask] = np.nan
84
+
85
+ return _fill_nan_nearest(arr).astype(dtype)
86
+
50
87
 
51
88
 
52
89
  def _interp_single_worker(*args):
@@ -1,54 +1,11 @@
1
- #!/usr/bin/env python
2
- # coding=utf-8
3
- """
4
- Author: Liu Kun && 16031215@qq.com
5
- Date: 2025-04-26 11:54:21
6
- LastEditors: Liu Kun && 16031215@qq.com
7
- LastEditTime: 2025-04-26 11:54:22
8
- FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\_script\\data_interp_geo.py
9
- Description:
10
- EditPlatform: vscode
11
- ComputerInfo: XPS 15 9510
12
- SystemInfo: Windows 11
13
- Python Version: 3.12
14
- """
15
-
16
- import importlib.util
17
1
  from typing import List, Union
18
2
 
19
3
  import numpy as np
20
4
  from scipy.interpolate import RectBivariateSpline
21
5
 
22
6
  from oafuncs.oa_tool import PEx
23
-
24
- _has_pykdtree = importlib.util.find_spec("pykdtree.kdtree") is not None
25
-
26
-
27
- def fill_nan_nearest(arr):
28
- """用最近邻插值填充 NaN,优先用pykdtree加速"""
29
- mask = np.isnan(arr)
30
- if not mask.any():
31
- return arr
32
- if _has_pykdtree:
33
- from pykdtree.kdtree import KDTree
34
-
35
- valid_idx = np.array(np.where(~mask)).T
36
- nan_idx = np.array(np.where(mask)).T
37
- if len(valid_idx) == 0:
38
- # 全是nan,直接返回
39
- return arr
40
- tree = KDTree(valid_idx)
41
- dist, idx = tree.query(nan_idx, k=1)
42
- filled = arr.copy()
43
- # idx shape: (n_nan, 1),valid_idx shape: (n_valid, ndim)
44
- # valid_idx[idx].T shape: (ndim, n_nan)
45
- filled[tuple(nan_idx.T)] = arr[tuple(valid_idx[idx.flatten()].T)]
46
- return filled
47
- else:
48
- from scipy.ndimage import distance_transform_edt
49
-
50
- idx = distance_transform_edt(mask, return_distances=False, return_indices=True)
51
- return arr[tuple(idx)]
7
+ from oafuncs.oa_data import data_clip
8
+ from oafuncs._script.data_interp import _fill_nan_nearest
52
9
 
53
10
 
54
11
  def _interp_single_worker(*args):
@@ -63,7 +20,7 @@ def _interp_single_worker(*args):
63
20
  if np.isnan(data_slice).any():
64
21
  mask = np.isnan(data_slice)
65
22
  if mask.any():
66
- data_slice = fill_nan_nearest(data_slice)
23
+ data_slice = _fill_nan_nearest(data_slice)
67
24
  x1d = np.unique(sx[0, :])
68
25
  y1d = np.unique(sy[:, 0])
69
26
  if sx.shape != (len(y1d), len(x1d)) or sy.shape != (len(y1d), len(x1d)):
@@ -80,13 +37,7 @@ def _interp_single_worker(*args):
80
37
  out = interp_func(ty[:, 0], tx[0, :])
81
38
  # 优化裁剪逻辑:超出范围的点设为nan,再用fill_nan_nearest填充
82
39
  arr = np.asarray(out)
83
- mask = np.isnan(arr) | (arr < data_min) | (arr > data_max)
84
- if np.any(mask):
85
- arr = np.where(mask, np.nan, arr)
86
- arr = fill_nan_nearest(arr)
87
- # 最后再填充nan(极端情况)
88
- if np.any(np.isnan(arr)):
89
- arr = fill_nan_nearest(arr)
40
+ arr = data_clip(arr,data_min,data_max)
90
41
  return arr
91
42
 
92
43
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oafuncs
3
- Version: 0.0.98.16
3
+ Version: 0.0.98.17
4
4
  Summary: Oceanic and Atmospheric Functions
5
5
  Home-page: https://github.com/Industry-Pays/OAFuncs
6
6
  Author: Kun Liu
@@ -11,8 +11,8 @@ oafuncs/oa_tool.py,sha256=rpPkLqWhqMmqlCc5wjL8qMTg3gThCkSrYJckbX_0iJc,8631
11
11
  oafuncs/_data/hycom.png,sha256=MadKs6Gyj5n9-TOu7L4atQfTXtF9dvN9w-tdU9IfygI,10945710
12
12
  oafuncs/_data/oafuncs.png,sha256=o3VD7wm-kwDea5E98JqxXl04_78cBX7VcdUt7uQXGiU,3679898
13
13
  oafuncs/_script/cprogressbar.py,sha256=UIgGcLFs-6IgWlITuBLaQqrpt4OAK3Mst5RlCiNfZdQ,15772
14
- oafuncs/_script/data_interp.py,sha256=W4kYZmkZxWJqKfZVdQOd8jUv0y11t6k8tsukRQt670I,6373
15
- oafuncs/_script/data_interp_geo.py,sha256=Fv-l8MeKhx6e7UVtzk2b6Pb2Cfcg-RNnMFmkcd0ng64,5296
14
+ oafuncs/_script/data_interp.py,sha256=_k8EMSiFxutrqEVTLsL4mEPE6ssYq8bzmBlksCZ9nAE,7428
15
+ oafuncs/_script/data_interp_geo.py,sha256=X89KxLYhpltWi0Sf96gIhBL3r1M5aExd_JCmgBmmvUc,3742
16
16
  oafuncs/_script/email.py,sha256=lL4HGKrr524-g0xLlgs-4u7x4-u7DtgNoD9AL8XJKj4,3058
17
17
  oafuncs/_script/netcdf_merge.py,sha256=9hCyxfeUHnBzs50_0v0jzVfxpMxTX4dNTo0pmsp_T6g,4226
18
18
  oafuncs/_script/netcdf_modify.py,sha256=sGRUYNhfGgf9JV70rnBzw3bzuTRSXzBTL_RMDnDPeLQ,4552
@@ -39,8 +39,8 @@ oafuncs/oa_sign/__init__.py,sha256=QKqTFrJDFK40C5uvk48GlRRbGFzO40rgkYwu6dYxatM,5
39
39
  oafuncs/oa_sign/meteorological.py,sha256=8091SHo2L8kl4dCFmmSH5NGVHDku5i5lSiLEG5DLnOQ,6489
40
40
  oafuncs/oa_sign/ocean.py,sha256=xrW-rWD7xBWsB5PuCyEwQ1Q_RDKq2KCLz-LOONHgldU,5932
41
41
  oafuncs/oa_sign/scientific.py,sha256=a4JxOBgm9vzNZKpJ_GQIQf7cokkraV5nh23HGbmTYKw,5064
42
- oafuncs-0.0.98.16.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
43
- oafuncs-0.0.98.16.dist-info/METADATA,sha256=yPzl7v8ASdNRSjiXasAGuxPKA9rM_zCIQBQHfmz4I0k,4273
44
- oafuncs-0.0.98.16.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
45
- oafuncs-0.0.98.16.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
46
- oafuncs-0.0.98.16.dist-info/RECORD,,
42
+ oafuncs-0.0.98.17.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
43
+ oafuncs-0.0.98.17.dist-info/METADATA,sha256=8-0Gp7bgVD7qR4sfSQtKmoCl5yV8f7YBnEROZV28oJY,4273
44
+ oafuncs-0.0.98.17.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
45
+ oafuncs-0.0.98.17.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
46
+ oafuncs-0.0.98.17.dist-info/RECORD,,