oafuncs 0.0.97.2__tar.gz → 0.0.97.4__tar.gz
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-0.0.97.4/MANIFEST.in +5 -0
- {oafuncs-0.0.97.2/oafuncs.egg-info → oafuncs-0.0.97.4}/PKG-INFO +78 -7
- oafuncs-0.0.97.4/README.md +131 -0
- oafuncs-0.0.97.4/oafuncs/_script/plot_dataset.py +299 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4/oafuncs.egg-info}/PKG-INFO +78 -7
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs.egg-info/SOURCES.txt +3 -2
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/setup.py +9 -3
- oafuncs-0.0.97.2/MANIFEST.in +0 -4
- oafuncs-0.0.97.2/README.md +0 -60
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/LICENSE.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/__init__.py +0 -0
- {oafuncs-0.0.97.2/oafuncs/data_store → oafuncs-0.0.97.4/oafuncs/_data}/OAFuncs.png +0 -0
- {oafuncs-0.0.97.2/oafuncs/data_store → oafuncs-0.0.97.4/oafuncs/_data}/hycom_3hourly.png +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_cmap.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_data.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_down/User_Agent-list.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_down/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_down/hycom_3hourly.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_down/hycom_3hourly_20250129.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_down/idm.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_down/literature.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_down/test_ua.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_down/user_agent.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_draw.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_file.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_help.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_model/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_model/roms/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_model/roms/test.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_model/wrf/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_model/wrf/little_r.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_nc.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_python.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_sign/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_sign/meteorological.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_sign/ocean.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_sign/scientific.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_tool/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_tool/email.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_tool/parallel.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs/oa_tool/time.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs.egg-info/dependency_links.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs.egg-info/requires.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/oafuncs.egg-info/top_level.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: oafuncs
|
3
|
-
Version: 0.0.97.
|
3
|
+
Version: 0.0.97.4
|
4
4
|
Summary: Oceanic and Atmospheric Functions
|
5
5
|
Home-page: https://github.com/Industry-Pays/OAFuncs
|
6
6
|
Author: Kun Liu
|
@@ -86,17 +86,88 @@ oafuncs.oa_help.use('query')
|
|
86
86
|
```
|
87
87
|
|
88
88
|
```shell
|
89
|
-
# 此小板块于
|
89
|
+
# 此小板块于2025/03/16更新,仅为示例,不代表最新情况
|
90
90
|
函数数量:
|
91
|
-
|
91
|
+
62
|
92
92
|
函数列表:
|
93
|
-
[
|
93
|
+
[
|
94
|
+
'MidpointNormalize',
|
95
|
+
'ParallelExecutor',
|
96
|
+
'add_cartopy',
|
97
|
+
'add_gridlines',
|
98
|
+
'add_lonlat_unit',
|
99
|
+
'check',
|
100
|
+
'clear_folder',
|
101
|
+
'contour',
|
102
|
+
'contourf',
|
103
|
+
'convert_longitude',
|
104
|
+
'copy_file',
|
105
|
+
'create',
|
106
|
+
'create_rgbtxt',
|
107
|
+
'data_record',
|
108
|
+
'download',
|
109
|
+
'download5doi',
|
110
|
+
'downloader',
|
111
|
+
'draw',
|
112
|
+
'draw_time_range',
|
113
|
+
'ending_record',
|
114
|
+
'ensure_list',
|
115
|
+
'extract',
|
116
|
+
'fig_minus',
|
117
|
+
'file_size',
|
118
|
+
'find_file',
|
119
|
+
'get',
|
120
|
+
'get_days',
|
121
|
+
'get_time_list',
|
122
|
+
'get_ua',
|
123
|
+
'get_var',
|
124
|
+
'gif',
|
125
|
+
'header_record',
|
126
|
+
'how_to_use',
|
127
|
+
'install_lib',
|
128
|
+
'interp_2d',
|
129
|
+
'interp_along_dim',
|
130
|
+
'isel',
|
131
|
+
'link_file',
|
132
|
+
'log',
|
133
|
+
'make_dir',
|
134
|
+
'make_folder',
|
135
|
+
'mask_shapefile',
|
136
|
+
'mean_size',
|
137
|
+
'merge',
|
138
|
+
'modify',
|
139
|
+
'query',
|
140
|
+
'quiver',
|
141
|
+
'remove',
|
142
|
+
'remove_empty_folder',
|
143
|
+
'rename',
|
144
|
+
'rename_file',
|
145
|
+
'save',
|
146
|
+
'send',
|
147
|
+
'show',
|
148
|
+
'sign_in_love_ocean',
|
149
|
+
'sign_in_meteorological_home',
|
150
|
+
'sign_in_scientific_research',
|
151
|
+
'tail_record',
|
152
|
+
'test',
|
153
|
+
'to_color',
|
154
|
+
'upgrade_lib',
|
155
|
+
'use'
|
156
|
+
]
|
157
|
+
同名函数:
|
158
|
+
----------------------------------------
|
94
159
|
模块全路径:
|
95
160
|
oafuncs.oa_help.query
|
96
|
-
函数提示:
|
97
161
|
|
98
|
-
|
99
|
-
|
162
|
+
Help on function query in module oafuncs.oa_help:
|
163
|
+
|
164
|
+
query()
|
165
|
+
Description:
|
166
|
+
Show the number of functions and the list of functions in the module.
|
167
|
+
Example:
|
168
|
+
query()
|
169
|
+
|
170
|
+
----------------------------------------
|
100
171
|
```
|
101
172
|
|
102
173
|
## Structure
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# oafuncs
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
**Python Function**
|
6
|
+
|
7
|
+
```text
|
8
|
+
In the field of geoscience, some commonly used and universal operations!
|
9
|
+
|
10
|
+
Just for the convenience of daily use, some complex operations are integrated into general functions.
|
11
|
+
|
12
|
+
The code will be optimized and updated from time to time, with additions, deletions, or modifications…
|
13
|
+
|
14
|
+
Existing functions will not be completely removed, they might just have a different function name, or the parameter passing might have been optimized…
|
15
|
+
|
16
|
+
Note: If there are any requirements, you can email to liukun0312@stu.ouc.edu.cn. Within my capabilities, I can consider implementing them.
|
17
|
+
```
|
18
|
+
|
19
|
+
## PyPI
|
20
|
+
|
21
|
+
```html
|
22
|
+
https://pypi.org/project/oafuncs
|
23
|
+
```
|
24
|
+
|
25
|
+
## Github
|
26
|
+
|
27
|
+
```html
|
28
|
+
https://github.com/Industry-Pays/OAFuncs
|
29
|
+
```
|
30
|
+
|
31
|
+
## Example
|
32
|
+
|
33
|
+
```python
|
34
|
+
import oafuncs
|
35
|
+
|
36
|
+
# 查询当前所有可用函数
|
37
|
+
oafuncs.oa_help.query()
|
38
|
+
# 根据函数名获取使用方法
|
39
|
+
oafuncs.oa_help.use('query')
|
40
|
+
```
|
41
|
+
|
42
|
+
```shell
|
43
|
+
# 此小板块于2025/03/16更新,仅为示例,不代表最新情况
|
44
|
+
函数数量:
|
45
|
+
62
|
46
|
+
函数列表:
|
47
|
+
[
|
48
|
+
'MidpointNormalize',
|
49
|
+
'ParallelExecutor',
|
50
|
+
'add_cartopy',
|
51
|
+
'add_gridlines',
|
52
|
+
'add_lonlat_unit',
|
53
|
+
'check',
|
54
|
+
'clear_folder',
|
55
|
+
'contour',
|
56
|
+
'contourf',
|
57
|
+
'convert_longitude',
|
58
|
+
'copy_file',
|
59
|
+
'create',
|
60
|
+
'create_rgbtxt',
|
61
|
+
'data_record',
|
62
|
+
'download',
|
63
|
+
'download5doi',
|
64
|
+
'downloader',
|
65
|
+
'draw',
|
66
|
+
'draw_time_range',
|
67
|
+
'ending_record',
|
68
|
+
'ensure_list',
|
69
|
+
'extract',
|
70
|
+
'fig_minus',
|
71
|
+
'file_size',
|
72
|
+
'find_file',
|
73
|
+
'get',
|
74
|
+
'get_days',
|
75
|
+
'get_time_list',
|
76
|
+
'get_ua',
|
77
|
+
'get_var',
|
78
|
+
'gif',
|
79
|
+
'header_record',
|
80
|
+
'how_to_use',
|
81
|
+
'install_lib',
|
82
|
+
'interp_2d',
|
83
|
+
'interp_along_dim',
|
84
|
+
'isel',
|
85
|
+
'link_file',
|
86
|
+
'log',
|
87
|
+
'make_dir',
|
88
|
+
'make_folder',
|
89
|
+
'mask_shapefile',
|
90
|
+
'mean_size',
|
91
|
+
'merge',
|
92
|
+
'modify',
|
93
|
+
'query',
|
94
|
+
'quiver',
|
95
|
+
'remove',
|
96
|
+
'remove_empty_folder',
|
97
|
+
'rename',
|
98
|
+
'rename_file',
|
99
|
+
'save',
|
100
|
+
'send',
|
101
|
+
'show',
|
102
|
+
'sign_in_love_ocean',
|
103
|
+
'sign_in_meteorological_home',
|
104
|
+
'sign_in_scientific_research',
|
105
|
+
'tail_record',
|
106
|
+
'test',
|
107
|
+
'to_color',
|
108
|
+
'upgrade_lib',
|
109
|
+
'use'
|
110
|
+
]
|
111
|
+
同名函数:
|
112
|
+
----------------------------------------
|
113
|
+
模块全路径:
|
114
|
+
oafuncs.oa_help.query
|
115
|
+
|
116
|
+
Help on function query in module oafuncs.oa_help:
|
117
|
+
|
118
|
+
query()
|
119
|
+
Description:
|
120
|
+
Show the number of functions and the list of functions in the module.
|
121
|
+
Example:
|
122
|
+
query()
|
123
|
+
|
124
|
+
----------------------------------------
|
125
|
+
```
|
126
|
+
|
127
|
+
## Structure
|
128
|
+
|
129
|
+
<img title="" src="./oafuncs/data_store/OAFuncs.png" alt="">
|
130
|
+
|
131
|
+
<img title="OAFuncs" src="https://raw.githubusercontent.com/Industry-Pays/OAFuncs/main/oafuncs/data_store/OAFuncs.png" alt="OAFuncs">
|
@@ -0,0 +1,299 @@
|
|
1
|
+
import os
|
2
|
+
from typing import Optional, Tuple
|
3
|
+
|
4
|
+
import matplotlib as mpl
|
5
|
+
|
6
|
+
mpl.use("Agg") # Use non-interactive backend
|
7
|
+
|
8
|
+
import cftime
|
9
|
+
import matplotlib.pyplot as plt
|
10
|
+
import numpy as np
|
11
|
+
from rich import print
|
12
|
+
import cartopy.crs as ccrs
|
13
|
+
import xarray as xr
|
14
|
+
|
15
|
+
import oafuncs
|
16
|
+
|
17
|
+
|
18
|
+
def plot_1d(data: xr.DataArray, output_path: str, x_dim: str, y_dim: str, z_dim: str, t_dim: str) -> None:
|
19
|
+
"""Plot 1D data."""
|
20
|
+
plt.figure(figsize=(10, 6))
|
21
|
+
|
22
|
+
# Handle time dimension
|
23
|
+
if t_dim in data.dims and isinstance(data[t_dim].values[0], cftime.datetime):
|
24
|
+
try:
|
25
|
+
data[t_dim] = data.indexes[t_dim].to_datetimeindex()
|
26
|
+
except (AttributeError, ValueError, TypeError) as e:
|
27
|
+
print(f"Warning: Could not convert {t_dim} to datetime index: {e}")
|
28
|
+
|
29
|
+
# Determine X axis data
|
30
|
+
x, x_label = determine_x_axis(data, x_dim, y_dim, z_dim, t_dim)
|
31
|
+
|
32
|
+
y = data.values
|
33
|
+
plt.plot(x, y, linewidth=2)
|
34
|
+
|
35
|
+
# Add chart info
|
36
|
+
long_name = getattr(data, "long_name", "No long_name")
|
37
|
+
units = getattr(data, "units", "")
|
38
|
+
plt.title(f"{data.name} | {long_name}", fontsize=12)
|
39
|
+
plt.xlabel(x_label)
|
40
|
+
plt.ylabel(f"{data.name} ({units})" if units else data.name)
|
41
|
+
|
42
|
+
plt.grid(True, linestyle="--", alpha=0.7)
|
43
|
+
plt.tight_layout()
|
44
|
+
|
45
|
+
# Save image
|
46
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
47
|
+
plt.savefig(output_path, bbox_inches="tight", dpi=600)
|
48
|
+
plt.clf()
|
49
|
+
plt.close()
|
50
|
+
|
51
|
+
|
52
|
+
def determine_x_axis(data: xr.DataArray, x_dim: str, y_dim: str, z_dim: str, t_dim: str) -> Tuple[np.ndarray, str]:
|
53
|
+
"""Determine the X axis data and label."""
|
54
|
+
if x_dim in data.dims:
|
55
|
+
return data[x_dim].values, x_dim
|
56
|
+
elif y_dim in data.dims:
|
57
|
+
return data[y_dim].values, y_dim
|
58
|
+
elif z_dim in data.dims:
|
59
|
+
return data[z_dim].values, z_dim
|
60
|
+
elif t_dim in data.dims:
|
61
|
+
return data[t_dim].values, t_dim
|
62
|
+
else:
|
63
|
+
return np.arange(len(data)), "Index"
|
64
|
+
|
65
|
+
|
66
|
+
def plot_2d(data: xr.DataArray, output_path: str, data_range: Optional[Tuple[float, float]], x_dim: str, y_dim: str, t_dim: str, plot_type: str) -> bool:
|
67
|
+
"""Plot 2D data."""
|
68
|
+
if x_dim in data.dims and y_dim in data.dims and x_dim.lower() in ["lon", "longitude"] and y_dim.lower() in ["lat", "latitude"]:
|
69
|
+
lon_range = data[x_dim].values
|
70
|
+
lat_range = data[y_dim].values
|
71
|
+
lon_lat_ratio = np.abs(np.max(lon_range) - np.min(lon_range)) / (np.max(lat_range) - np.min(lat_range))
|
72
|
+
figsize = (10, 10 / lon_lat_ratio)
|
73
|
+
fig, ax = plt.subplots(figsize=figsize, subplot_kw={"projection": ccrs.PlateCarree()})
|
74
|
+
oafuncs.oa_draw.add_cartopy(ax, lon_range, lat_range)
|
75
|
+
else:
|
76
|
+
fig, ax = plt.subplots(figsize=(10, 8))
|
77
|
+
|
78
|
+
# Handle time dimension
|
79
|
+
if t_dim in data.dims and isinstance(data[t_dim].values[0], cftime.datetime):
|
80
|
+
try:
|
81
|
+
data[t_dim] = data.indexes[t_dim].to_datetimeindex()
|
82
|
+
except (AttributeError, ValueError, TypeError) as e:
|
83
|
+
print(f"Warning: Could not convert {t_dim} to datetime index: {e}")
|
84
|
+
|
85
|
+
# Check for valid data
|
86
|
+
if np.all(np.isnan(data.values)) or data.size == 0:
|
87
|
+
print(f"Skipping {data.name}: All values are NaN or empty")
|
88
|
+
plt.close()
|
89
|
+
return False
|
90
|
+
|
91
|
+
data_range = calculate_data_range(data, data_range)
|
92
|
+
|
93
|
+
if data_range is None:
|
94
|
+
print(f"Skipping {data.name} due to all NaN values")
|
95
|
+
plt.close()
|
96
|
+
return False
|
97
|
+
|
98
|
+
# Select appropriate colormap and levels
|
99
|
+
cmap, norm, levels = select_colormap_and_levels(data_range, plot_type)
|
100
|
+
|
101
|
+
mappable = None
|
102
|
+
try:
|
103
|
+
if plot_type == "contourf":
|
104
|
+
if np.ptp(data.values) < 1e-10 and not np.all(np.isnan(data.values)):
|
105
|
+
print(f"Warning: {data.name} has very little variation. Using imshow instead.")
|
106
|
+
mappable = ax.imshow(data.values, cmap=cmap, aspect="auto", interpolation="none")
|
107
|
+
colorbar = plt.colorbar(mappable, ax=ax)
|
108
|
+
else:
|
109
|
+
mappable = ax.contourf(data[x_dim], data[y_dim], data.values, levels=levels, cmap=cmap, norm=norm)
|
110
|
+
colorbar = plt.colorbar(mappable, ax=ax)
|
111
|
+
elif plot_type == "contour":
|
112
|
+
if np.ptp(data.values) < 1e-10 and not np.all(np.isnan(data.values)):
|
113
|
+
print(f"Warning: {data.name} has very little variation. Using imshow instead.")
|
114
|
+
mappable = ax.imshow(data.values, cmap=cmap, aspect="auto", interpolation="none")
|
115
|
+
colorbar = plt.colorbar(mappable, ax=ax)
|
116
|
+
else:
|
117
|
+
mappable = ax.contour(data[x_dim], data[y_dim], data.values, levels=levels, cmap=cmap, norm=norm)
|
118
|
+
ax.clabel(mappable, inline=True, fontsize=8, fmt="%1.1f")
|
119
|
+
colorbar = plt.colorbar(mappable, ax=ax)
|
120
|
+
except (ValueError, TypeError) as e:
|
121
|
+
print(f"Warning: Could not plot with specified parameters: {e}. Trying simplified parameters.")
|
122
|
+
try:
|
123
|
+
mappable = data.plot(ax=ax, cmap=cmap, add_colorbar=False)
|
124
|
+
colorbar = plt.colorbar(mappable, ax=ax)
|
125
|
+
except Exception as e2:
|
126
|
+
print(f"Error plotting {data.name}: {e2}")
|
127
|
+
plt.figure(figsize=(10, 8))
|
128
|
+
mappable = ax.imshow(data.values, cmap="viridis", aspect="auto")
|
129
|
+
colorbar = plt.colorbar(mappable, ax=ax, label=getattr(data, "units", ""))
|
130
|
+
plt.title(f"{data.name} | {getattr(data, 'long_name', 'No long_name')} (basic plot)", fontsize=12)
|
131
|
+
plt.tight_layout()
|
132
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
133
|
+
plt.savefig(output_path, bbox_inches="tight", dpi=600)
|
134
|
+
plt.close()
|
135
|
+
return True
|
136
|
+
|
137
|
+
plt.title(f"{data.name} | {getattr(data, 'long_name', 'No long_name')}", fontsize=12)
|
138
|
+
units = getattr(data, "units", "")
|
139
|
+
if units and colorbar:
|
140
|
+
colorbar.set_label(units)
|
141
|
+
|
142
|
+
plt.tight_layout()
|
143
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
144
|
+
plt.savefig(output_path, bbox_inches="tight", dpi=600)
|
145
|
+
plt.close()
|
146
|
+
return True
|
147
|
+
|
148
|
+
|
149
|
+
def calculate_data_range(data: xr.DataArray, data_range: Optional[Tuple[float, float]]) -> Optional[Tuple[float, float]]:
|
150
|
+
"""Calculate the data range, ignoring extreme outliers."""
|
151
|
+
if data_range is None:
|
152
|
+
flat_data = data.values.flatten()
|
153
|
+
if flat_data.size == 0:
|
154
|
+
return None
|
155
|
+
valid_data = flat_data[~np.isnan(flat_data)]
|
156
|
+
if len(valid_data) == 0:
|
157
|
+
return None
|
158
|
+
low, high = np.percentile(valid_data, [0.5, 99.5])
|
159
|
+
filtered_data = valid_data[(valid_data >= low) & (valid_data <= high)]
|
160
|
+
if len(filtered_data) > 0:
|
161
|
+
data_range = (np.min(filtered_data), np.max(filtered_data))
|
162
|
+
else:
|
163
|
+
data_range = (np.nanmin(valid_data), np.nanmax(valid_data))
|
164
|
+
if abs(data_range[1] - data_range[0]) < 1e-10:
|
165
|
+
mean = (data_range[0] + data_range[1]) / 2
|
166
|
+
data_range = (mean - 1e-10 if mean != 0 else -1e-10, mean + 1e-10 if mean != 0 else 1e-10)
|
167
|
+
return data_range
|
168
|
+
|
169
|
+
|
170
|
+
def select_colormap_and_levels(data_range: Tuple[float, float], plot_type: str) -> Tuple[mpl.colors.Colormap, mpl.colors.Normalize, np.ndarray]:
|
171
|
+
"""Select colormap and levels based on data range."""
|
172
|
+
if plot_type == "contour":
|
173
|
+
# For contour plots, use fewer levels
|
174
|
+
num_levels = 10
|
175
|
+
else:
|
176
|
+
# For filled contour plots, use more levels
|
177
|
+
num_levels = 128
|
178
|
+
|
179
|
+
if data_range[0] * data_range[1] < 0:
|
180
|
+
cmap = oafuncs.oa_cmap.get("diverging_1")
|
181
|
+
bdy = max(abs(data_range[0]), abs(data_range[1]))
|
182
|
+
norm = mpl.colors.TwoSlopeNorm(vmin=-bdy, vcenter=0, vmax=bdy)
|
183
|
+
levels = np.linspace(-bdy, bdy, num_levels)
|
184
|
+
else:
|
185
|
+
cmap = oafuncs.oa_cmap.get("cool_1") if data_range[0] < 0 else oafuncs.oa_cmap.get("warm_1")
|
186
|
+
norm = mpl.colors.Normalize(vmin=data_range[0], vmax=data_range[1])
|
187
|
+
levels = np.linspace(data_range[0], data_range[1], num_levels)
|
188
|
+
|
189
|
+
if np.any(np.diff(levels) <= 0):
|
190
|
+
levels = np.linspace(data_range[0], data_range[1], 10)
|
191
|
+
return cmap, norm, levels
|
192
|
+
|
193
|
+
|
194
|
+
def process_variable(var: str, data: xr.DataArray, dims: int, dims_name: Tuple[str, ...], output_dir: str, x_dim: str, y_dim: str, z_dim: str, t_dim: str, fixed_colorscale: bool, plot_type: str) -> None:
|
195
|
+
"""Process a single variable."""
|
196
|
+
valid_dims = {x_dim, y_dim, z_dim, t_dim}
|
197
|
+
if not set(dims_name).issubset(valid_dims):
|
198
|
+
print(f"Skipping {var} due to unsupported dimensions: {dims_name}")
|
199
|
+
return
|
200
|
+
|
201
|
+
# Process 1D data
|
202
|
+
if dims == 1:
|
203
|
+
if np.issubdtype(data.dtype, np.character):
|
204
|
+
print(f"Skipping {var} due to character data type")
|
205
|
+
return
|
206
|
+
plot_1d(data, os.path.join(output_dir, f"{var}.png"), x_dim, y_dim, z_dim, t_dim)
|
207
|
+
print(f"{var}.png")
|
208
|
+
return
|
209
|
+
|
210
|
+
# Compute global data range for fixed colorscale
|
211
|
+
global_data_range = None
|
212
|
+
if dims >= 2 and fixed_colorscale:
|
213
|
+
global_data_range = calculate_data_range(data, None)
|
214
|
+
if global_data_range is None:
|
215
|
+
print(f"Skipping {var} due to no valid data")
|
216
|
+
return
|
217
|
+
print(f"Fixed colorscale range: {global_data_range}")
|
218
|
+
|
219
|
+
# Process 2D data
|
220
|
+
if dims == 2:
|
221
|
+
success = plot_2d(data, os.path.join(output_dir, f"{var}.png"), global_data_range, x_dim, y_dim, t_dim, plot_type)
|
222
|
+
if success:
|
223
|
+
print(f"{var}.png")
|
224
|
+
|
225
|
+
# Process 3D data
|
226
|
+
if dims == 3:
|
227
|
+
for i in range(data.shape[0]):
|
228
|
+
for attempt in range(10):
|
229
|
+
try:
|
230
|
+
if data[i].values.size == 0:
|
231
|
+
print(f"Skipped {var}_{dims_name[0]}-{i} (empty data)")
|
232
|
+
break
|
233
|
+
success = plot_2d(data[i], os.path.join(output_dir, f"{var}_{dims_name[0]}-{i}.png"), global_data_range, x_dim, y_dim, t_dim, plot_type)
|
234
|
+
if success:
|
235
|
+
print(f"{var}_{dims_name[0]}-{i}.png")
|
236
|
+
else:
|
237
|
+
print(f"Skipped {var}_{dims_name[0]}-{i} (invalid data)")
|
238
|
+
break
|
239
|
+
except Exception as e:
|
240
|
+
if attempt < 9:
|
241
|
+
print(f"Retrying {var}_{dims_name[0]}-{i} (attempt {attempt + 1})")
|
242
|
+
else:
|
243
|
+
print(f"Error processing {var}_{dims_name[0]}-{i}: {e}")
|
244
|
+
|
245
|
+
# Process 4D data
|
246
|
+
if dims == 4:
|
247
|
+
for i in range(data.shape[0]):
|
248
|
+
for j in range(data.shape[1]):
|
249
|
+
for attempt in range(3):
|
250
|
+
try:
|
251
|
+
if data[i, j].values.size == 0:
|
252
|
+
print(f"Skipped {var}_{dims_name[0]}-{i}_{dims_name[1]}-{j} (empty data)")
|
253
|
+
break
|
254
|
+
success = plot_2d(data[i, j], os.path.join(output_dir, f"{var}_{dims_name[0]}-{i}_{dims_name[1]}-{j}.png"), global_data_range, x_dim, y_dim, t_dim, plot_type)
|
255
|
+
if success:
|
256
|
+
print(f"{var}_{dims_name[0]}-{i}_{dims_name[1]}-{j}.png")
|
257
|
+
else:
|
258
|
+
print(f"Skipped {var}_{dims_name[0]}-{i}_{dims_name[1]}-{j} (invalid data)")
|
259
|
+
break
|
260
|
+
except Exception as e:
|
261
|
+
if attempt < 2:
|
262
|
+
print(f"Retrying {var}_{dims_name[0]}-{i}_{dims_name[1]}-{j} (attempt {attempt + 1})")
|
263
|
+
else:
|
264
|
+
print(f"Error processing {var}_{dims_name[0]}-{i}_{dims_name[1]}-{j}: {e}")
|
265
|
+
|
266
|
+
|
267
|
+
def func_plot_dataset(ds_in: xr.Dataset, output_dir: str, xyzt_dims: Tuple[str, str, str, str] = ("longitude", "latitude", "level", "time"), plot_type: str = "contourf", fixed_colorscale: bool = False) -> None:
|
268
|
+
"""Plot variables from a NetCDF file and save the plots to the specified directory."""
|
269
|
+
os.makedirs(output_dir, exist_ok=True)
|
270
|
+
x_dim, y_dim, z_dim, t_dim = xyzt_dims
|
271
|
+
|
272
|
+
# Main processing function
|
273
|
+
try:
|
274
|
+
ds = ds_in
|
275
|
+
varlist = list(ds.data_vars)
|
276
|
+
print(f"Found {len(varlist)} variables in dataset")
|
277
|
+
|
278
|
+
for var in varlist:
|
279
|
+
print("=" * 120)
|
280
|
+
print(f"Processing: {var}")
|
281
|
+
data = ds[var]
|
282
|
+
dims = len(data.shape)
|
283
|
+
dims_name = data.dims
|
284
|
+
try:
|
285
|
+
process_variable(var, data, dims, dims_name, output_dir, x_dim, y_dim, z_dim, t_dim, fixed_colorscale, plot_type)
|
286
|
+
except Exception as e:
|
287
|
+
print(f"Error processing variable {var}: {e}")
|
288
|
+
|
289
|
+
except Exception as e:
|
290
|
+
print(f"Error processing dataset: {e}")
|
291
|
+
finally:
|
292
|
+
if "ds" in locals():
|
293
|
+
ds.close()
|
294
|
+
print("Dataset closed")
|
295
|
+
|
296
|
+
|
297
|
+
if __name__ == "__main__":
|
298
|
+
pass
|
299
|
+
# func_plot_dataset(ds, output_dir, xyzt_dims=("longitude", "latitude", "level", "time"), plot_type="contourf", fixed_colorscale=False)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: oafuncs
|
3
|
-
Version: 0.0.97.
|
3
|
+
Version: 0.0.97.4
|
4
4
|
Summary: Oceanic and Atmospheric Functions
|
5
5
|
Home-page: https://github.com/Industry-Pays/OAFuncs
|
6
6
|
Author: Kun Liu
|
@@ -86,17 +86,88 @@ oafuncs.oa_help.use('query')
|
|
86
86
|
```
|
87
87
|
|
88
88
|
```shell
|
89
|
-
# 此小板块于
|
89
|
+
# 此小板块于2025/03/16更新,仅为示例,不代表最新情况
|
90
90
|
函数数量:
|
91
|
-
|
91
|
+
62
|
92
92
|
函数列表:
|
93
|
-
[
|
93
|
+
[
|
94
|
+
'MidpointNormalize',
|
95
|
+
'ParallelExecutor',
|
96
|
+
'add_cartopy',
|
97
|
+
'add_gridlines',
|
98
|
+
'add_lonlat_unit',
|
99
|
+
'check',
|
100
|
+
'clear_folder',
|
101
|
+
'contour',
|
102
|
+
'contourf',
|
103
|
+
'convert_longitude',
|
104
|
+
'copy_file',
|
105
|
+
'create',
|
106
|
+
'create_rgbtxt',
|
107
|
+
'data_record',
|
108
|
+
'download',
|
109
|
+
'download5doi',
|
110
|
+
'downloader',
|
111
|
+
'draw',
|
112
|
+
'draw_time_range',
|
113
|
+
'ending_record',
|
114
|
+
'ensure_list',
|
115
|
+
'extract',
|
116
|
+
'fig_minus',
|
117
|
+
'file_size',
|
118
|
+
'find_file',
|
119
|
+
'get',
|
120
|
+
'get_days',
|
121
|
+
'get_time_list',
|
122
|
+
'get_ua',
|
123
|
+
'get_var',
|
124
|
+
'gif',
|
125
|
+
'header_record',
|
126
|
+
'how_to_use',
|
127
|
+
'install_lib',
|
128
|
+
'interp_2d',
|
129
|
+
'interp_along_dim',
|
130
|
+
'isel',
|
131
|
+
'link_file',
|
132
|
+
'log',
|
133
|
+
'make_dir',
|
134
|
+
'make_folder',
|
135
|
+
'mask_shapefile',
|
136
|
+
'mean_size',
|
137
|
+
'merge',
|
138
|
+
'modify',
|
139
|
+
'query',
|
140
|
+
'quiver',
|
141
|
+
'remove',
|
142
|
+
'remove_empty_folder',
|
143
|
+
'rename',
|
144
|
+
'rename_file',
|
145
|
+
'save',
|
146
|
+
'send',
|
147
|
+
'show',
|
148
|
+
'sign_in_love_ocean',
|
149
|
+
'sign_in_meteorological_home',
|
150
|
+
'sign_in_scientific_research',
|
151
|
+
'tail_record',
|
152
|
+
'test',
|
153
|
+
'to_color',
|
154
|
+
'upgrade_lib',
|
155
|
+
'use'
|
156
|
+
]
|
157
|
+
同名函数:
|
158
|
+
----------------------------------------
|
94
159
|
模块全路径:
|
95
160
|
oafuncs.oa_help.query
|
96
|
-
函数提示:
|
97
161
|
|
98
|
-
|
99
|
-
|
162
|
+
Help on function query in module oafuncs.oa_help:
|
163
|
+
|
164
|
+
query()
|
165
|
+
Description:
|
166
|
+
Show the number of functions and the list of functions in the module.
|
167
|
+
Example:
|
168
|
+
query()
|
169
|
+
|
170
|
+
----------------------------------------
|
100
171
|
```
|
101
172
|
|
102
173
|
## Structure
|
@@ -15,8 +15,9 @@ oafuncs.egg-info/SOURCES.txt
|
|
15
15
|
oafuncs.egg-info/dependency_links.txt
|
16
16
|
oafuncs.egg-info/requires.txt
|
17
17
|
oafuncs.egg-info/top_level.txt
|
18
|
-
oafuncs/
|
19
|
-
oafuncs/
|
18
|
+
oafuncs/_data/OAFuncs.png
|
19
|
+
oafuncs/_data/hycom_3hourly.png
|
20
|
+
oafuncs/_script/plot_dataset.py
|
20
21
|
oafuncs/oa_down/User_Agent-list.txt
|
21
22
|
oafuncs/oa_down/__init__.py
|
22
23
|
oafuncs/oa_down/hycom_3hourly.py
|
@@ -18,7 +18,7 @@ URL = "https://github.com/Industry-Pays/OAFuncs"
|
|
18
18
|
EMAIL = "liukun0312@stu.ouc.edu.cn"
|
19
19
|
AUTHOR = "Kun Liu"
|
20
20
|
REQUIRES_PYTHON = ">=3.9.0" # 2025/03/13
|
21
|
-
VERSION = "0.0.97.
|
21
|
+
VERSION = "0.0.97.4" # 下次用98.0,98.1已经被用过了
|
22
22
|
|
23
23
|
# What packages are required for this module to be executed?
|
24
24
|
REQUIRED = [
|
@@ -117,8 +117,14 @@ class UploadCommand(Command):
|
|
117
117
|
# 确保包含所有包
|
118
118
|
packages = find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"])
|
119
119
|
# 显式添加 data_store 目录
|
120
|
-
|
121
|
-
|
120
|
+
# 若添加,还是会被显示为包,但其函数不会被直接显示(应该也可调用)
|
121
|
+
# 要完全隐藏,但同时包含其py脚本和函数,试试在MANIFEST.in中添加
|
122
|
+
# 同一级不写__init__.py,但是在MANIFEST.in中写入,就不会显示函数
|
123
|
+
# if "oafuncs.data_store" not in packages:
|
124
|
+
# packages.append("oafuncs.data_store")
|
125
|
+
|
126
|
+
# if "oafuncs._nc_script" not in packages:
|
127
|
+
# packages.append("oafuncs._nc_script")
|
122
128
|
|
123
129
|
# Where the magic happens:
|
124
130
|
setup(
|
oafuncs-0.0.97.2/MANIFEST.in
DELETED
oafuncs-0.0.97.2/README.md
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
# oafuncs
|
2
|
-
|
3
|
-
## Description
|
4
|
-
|
5
|
-
**Python Function**
|
6
|
-
|
7
|
-
```text
|
8
|
-
In the field of geoscience, some commonly used and universal operations!
|
9
|
-
|
10
|
-
Just for the convenience of daily use, some complex operations are integrated into general functions.
|
11
|
-
|
12
|
-
The code will be optimized and updated from time to time, with additions, deletions, or modifications…
|
13
|
-
|
14
|
-
Existing functions will not be completely removed, they might just have a different function name, or the parameter passing might have been optimized…
|
15
|
-
|
16
|
-
Note: If there are any requirements, you can email to liukun0312@stu.ouc.edu.cn. Within my capabilities, I can consider implementing them.
|
17
|
-
```
|
18
|
-
|
19
|
-
## PyPI
|
20
|
-
|
21
|
-
```html
|
22
|
-
https://pypi.org/project/oafuncs
|
23
|
-
```
|
24
|
-
|
25
|
-
## Github
|
26
|
-
|
27
|
-
```html
|
28
|
-
https://github.com/Industry-Pays/OAFuncs
|
29
|
-
```
|
30
|
-
|
31
|
-
## Example
|
32
|
-
|
33
|
-
```python
|
34
|
-
import oafuncs
|
35
|
-
|
36
|
-
# 查询当前所有可用函数
|
37
|
-
oafuncs.oa_help.query()
|
38
|
-
# 根据函数名获取使用方法
|
39
|
-
oafuncs.oa_help.use('query')
|
40
|
-
```
|
41
|
-
|
42
|
-
```shell
|
43
|
-
# 此小板块于2024/12/26更新,仅为示例,不代表最新情况
|
44
|
-
函数数量:
|
45
|
-
49
|
46
|
-
函数列表:
|
47
|
-
['MidpointNormalize', 'add_cartopy', 'add_gridlines', 'add_lonlat_unit', 'check_ncfile', 'choose_cmap', 'clear_folder', 'cmap2colors', 'convert_longitude', 'copy_file', 'create_cmap', 'create_cmap_rgbtxt', 'create_gif', 'download', 'download5doi', 'draw_time_range', 'extract5nc', 'fig_minus', 'file_size', 'find_file', 'get_time_list', 'get_ua', 'get_var', 'how_to_use', 'install_lib', 'interp_2d', 'link_file', 'make_folder', 'merge5nc', 'modify_var_attr', 'modify_var_value', 'nc_isel', 'plot_contourf', 'plot_contourf_cartopy', 'plot_contourf_lonlat', 'plot_quiver', 'query', 'remove', 'remove_empty_folder', 'rename_file', 'rename_var_or_dim', 'send', 'show', 'sign_in_love_ocean', 'sign_in_meteorological_home', 'sign_in_scientific_research', 'upgrade_lib', 'use', 'write2nc']
|
48
|
-
模块全路径:
|
49
|
-
oafuncs.oa_help.query
|
50
|
-
函数提示:
|
51
|
-
|
52
|
-
description: 查看oafuncs模块的函数列表
|
53
|
-
example: query()
|
54
|
-
```
|
55
|
-
|
56
|
-
## Structure
|
57
|
-
|
58
|
-
<img title="" src="./oafuncs/data_store/OAFuncs.png" alt="">
|
59
|
-
|
60
|
-
<img title="OAFuncs" src="https://raw.githubusercontent.com/Industry-Pays/OAFuncs/main/oafuncs/data_store/OAFuncs.png" alt="OAFuncs">
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|