oafuncs 0.0.97.2__tar.gz → 0.0.97.3__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.2/oafuncs.egg-info → oafuncs-0.0.97.3}/PKG-INFO +1 -1
- oafuncs-0.0.97.3/oafuncs/_nc_script/plot_dataset.py +299 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_nc.py +1 -1
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3/oafuncs.egg-info}/PKG-INFO +1 -1
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs.egg-info/SOURCES.txt +1 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/setup.py +4 -1
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/LICENSE.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/MANIFEST.in +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/README.md +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/data_store/OAFuncs.png +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/data_store/hycom_3hourly.png +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_cmap.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_data.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_down/User_Agent-list.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_down/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_down/hycom_3hourly.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_down/hycom_3hourly_20250129.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_down/idm.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_down/literature.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_down/test_ua.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_down/user_agent.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_draw.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_file.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_help.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_model/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_model/roms/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_model/roms/test.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_model/wrf/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_model/wrf/little_r.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_python.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_sign/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_sign/meteorological.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_sign/ocean.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_sign/scientific.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_tool/__init__.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_tool/email.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_tool/parallel.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs/oa_tool/time.py +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs.egg-info/dependency_links.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs.egg-info/requires.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/oafuncs.egg-info/top_level.txt +0 -0
- {oafuncs-0.0.97.2 → oafuncs-0.0.97.3}/setup.cfg +0 -0
@@ -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)
|
@@ -20,7 +20,7 @@ import numpy as np
|
|
20
20
|
import xarray as xr
|
21
21
|
from rich import print
|
22
22
|
|
23
|
-
from .
|
23
|
+
from ._nc_script.plot_dataset import func_plot_dataset
|
24
24
|
|
25
25
|
__all__ = ["get_var", "extract", "save", "merge", "modify", "rename", "check", "convert_longitude", "isel", "draw"]
|
26
26
|
|
@@ -15,6 +15,7 @@ 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/_nc_script/plot_dataset.py
|
18
19
|
oafuncs/data_store/OAFuncs.png
|
19
20
|
oafuncs/data_store/hycom_3hourly.png
|
20
21
|
oafuncs/oa_down/User_Agent-list.txt
|
@@ -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.3" # 下次用98.0,98.1已经被用过了
|
22
22
|
|
23
23
|
# What packages are required for this module to be executed?
|
24
24
|
REQUIRED = [
|
@@ -120,6 +120,9 @@ packages = find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"])
|
|
120
120
|
if "oafuncs.data_store" not in packages:
|
121
121
|
packages.append("oafuncs.data_store")
|
122
122
|
|
123
|
+
if "oafuncs._nc_script" not in packages:
|
124
|
+
packages.append("oafuncs._nc_script")
|
125
|
+
|
123
126
|
# Where the magic happens:
|
124
127
|
setup(
|
125
128
|
name=NAME,
|
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
|
File without changes
|