oafuncs 0.0.98.33__py3-none-any.whl → 0.0.98.35__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.
@@ -91,7 +91,7 @@ def plot_2d(data: xr.DataArray, output_path: str, data_range: Optional[Tuple[flo
91
91
  lon_lat_ratio = np.abs(np.max(lon_range) - np.min(lon_range)) / (np.max(lat_range) - np.min(lat_range))
92
92
  figsize = (10, 10 / lon_lat_ratio)
93
93
  fig, ax = plt.subplots(figsize=figsize, subplot_kw={"projection": ccrs.PlateCarree()})
94
- oafuncs.oa_draw.add_cartopy(ax, lon_range, lat_range)
94
+ oafuncs.oa_draw.setup_map(ax, lon_range, lat_range)
95
95
  else:
96
96
  fig, ax = plt.subplots(figsize=(10, 8))
97
97
 
oafuncs/oa_cmap.py CHANGED
@@ -1,10 +1,10 @@
1
1
  from typing import List, Optional, Union
2
2
 
3
3
  import matplotlib as mpl
4
- import matplotlib.pyplot as plt
5
4
  import numpy as np
5
+ import random
6
6
 
7
- __all__ = ["show", "to_color", "create", "get"]
7
+ __all__ = ["show", "to_color", "create", "get", "random_color"]
8
8
 
9
9
 
10
10
  # ** 将cmap用填色图可视化(官网摘抄函数)
@@ -23,6 +23,7 @@ def show(
23
23
  colormaps : Union[str, mpl.colors.Colormap, List[Union[str, mpl.colors.Colormap]]]
24
24
  单个颜色映射或颜色映射列表;可以是名称字符串或颜色映射对象。
25
25
  """
26
+ import matplotlib.pyplot as plt
26
27
  if not isinstance(colormaps, list):
27
28
  colormaps = [colormaps]
28
29
 
@@ -304,6 +305,14 @@ def get(colormap_name: Optional[str] = None, show_available: bool = False) -> Op
304
305
  return mpl.colormaps.get_cmap("rainbow") # 默认返回 'rainbow'
305
306
 
306
307
 
308
+ # ** 生成随机颜色
309
+ def random_color():
310
+ """Generate a random color in hexadecimal format."""
311
+ r = random.randint(0, 255)
312
+ g = random.randint(0, 255)
313
+ b = random.randint(0, 255)
314
+ return f"#{r:02x}{g:02x}{b:02x}"
315
+
307
316
  if __name__ == "__main__":
308
317
  # ** 测试自制cmap
309
318
  colors = ["#C2B7F3", "#B3BBF2", "#B0CBF1", "#ACDCF0", "#A8EEED"]
oafuncs/oa_data.py CHANGED
@@ -1,10 +1,9 @@
1
1
  from typing import Any, List, Union
2
2
 
3
3
  import numpy as np
4
- import salem
5
4
  import xarray as xr
6
5
  from rich import print
7
- from scipy.interpolate import interp1d
6
+
8
7
 
9
8
  __all__ = ["interp_along_dim", "interp_2d", "ensure_list", "mask_shapefile"]
10
9
 
@@ -59,6 +58,7 @@ def interp_along_dim(
59
58
  >>> result = interp_along_dim(target_coordinates, source_coordinates, source_data)
60
59
  >>> print(result) # Expected output: [20.0, 30.0]
61
60
  """
61
+ from scipy.interpolate import interp1d
62
62
  target_coordinates = np.asarray(target_coordinates)
63
63
  if target_coordinates.ndim != 1:
64
64
  raise ValueError("[red]target_coordinates must be a 1D array.[/red]")
@@ -177,6 +177,7 @@ def mask_shapefile(
177
177
  >>> print(masked_data) # Expected output: Masked DataArray
178
178
 
179
179
  """
180
+ import salem
180
181
  try:
181
182
  shp_f = salem.read_shapefile(shapefile_path)
182
183
  data_da = xr.DataArray(data_array, coords=[("latitude", latitudes), ("longitude", longitudes)])
oafuncs/oa_draw.py CHANGED
@@ -1,12 +1,9 @@
1
1
  import warnings
2
2
 
3
3
  import cartopy.crs as ccrs
4
- import cartopy.feature as cfeature
5
- import cv2
6
4
  import matplotlib as mpl
7
5
  import matplotlib.pyplot as plt
8
6
  import numpy as np
9
- from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter
10
7
  from rich import print
11
8
 
12
9
  __all__ = ["fig_minus", "gif", "movie", "setup_map", "MidpointNormalize"]
@@ -74,7 +71,7 @@ def fig_minus(x_axis: plt.Axes = None, y_axis: plt.Axes = None, colorbar: mpl.co
74
71
  elif colorbar is not None:
75
72
  colorbar.set_ticklabels(out_ticks)
76
73
 
77
- print("[green]Axis tick labels updated successfully.[/green]")
74
+ # print("[green]Axis tick labels updated successfully.[/green]")
78
75
  return target_object
79
76
 
80
77
 
@@ -148,6 +145,7 @@ def movie(image_files: list[str], output_video_path: str, fps: int) -> None:
148
145
  print("[red]Error:[/red] Image files list is empty.")
149
146
  return
150
147
 
148
+ import cv2
151
149
  # Read first image to get frame dimensions
152
150
  try:
153
151
  frame = cv2.imread(image_files[0])
@@ -231,61 +229,11 @@ def setup_map(
231
229
  right_labels: bool = False,
232
230
  top_labels: bool = False,
233
231
  ) -> plt.Axes:
234
- """Setup a complete cartopy map with customizable features.
235
-
236
- Args:
237
- axes (plt.Axes): The axes to setup as a map.
238
- longitude_data (np.ndarray, optional): Array of longitudes to set map extent.
239
- latitude_data (np.ndarray, optional): Array of latitudes to set map extent.
240
- map_projection (ccrs.Projection, optional): Coordinate reference system. Defaults to PlateCarree.
241
-
242
- show_land (bool, optional): Whether to show land features. Defaults to True.
243
- show_ocean (bool, optional): Whether to show ocean features. Defaults to True.
244
- show_coastline (bool, optional): Whether to show coastlines. Defaults to True.
245
- show_borders (bool, optional): Whether to show country borders. Defaults to False.
246
- land_color (str, optional): Color of land. Defaults to "lightgrey".
247
- ocean_color (str, optional): Color of oceans. Defaults to "lightblue".
248
- coastline_linewidth (float, optional): Line width for coastlines. Defaults to 0.5.
249
-
250
- show_gridlines (bool, optional): Whether to show gridlines. Defaults to False.
251
- longitude_ticks (list[float], optional): Longitude tick positions.
252
- latitude_ticks (list[float], optional): Latitude tick positions.
253
- tick_decimals (int, optional): Number of decimal places for tick labels. Defaults to 0.
254
-
255
- grid_color (str, optional): Gridline color. Defaults to "k".
256
- grid_alpha (float, optional): Gridline transparency. Defaults to 0.5.
257
- grid_style (str, optional): Gridline style. Defaults to "--".
258
- grid_width (float, optional): Gridline width. Defaults to 0.5.
259
-
260
- show_labels (bool, optional): Whether to show coordinate labels. Defaults to True.
261
- left_labels (bool, optional): Show labels on left side. Defaults to True.
262
- bottom_labels (bool, optional): Show labels on bottom. Defaults to True.
263
- right_labels (bool, optional): Show labels on right side. Defaults to False.
264
- top_labels (bool, optional): Show labels on top. Defaults to False.
265
-
266
- Returns:
267
- plt.Axes: The configured map axes.
268
-
269
- Examples:
270
- >>> # Basic map setup
271
- >>> ax = setup_map(ax)
272
-
273
- >>> # Map with gridlines and custom extent
274
- >>> ax = setup_map(ax, longitude_data=lon, latitude_data=lat, show_gridlines=True)
275
-
276
- >>> # Customized map
277
- >>> ax = setup_map(
278
- ... ax,
279
- ... show_gridlines=True,
280
- ... longitude_ticks=[0, 30, 60],
281
- ... latitude_ticks=[-30, 0, 30],
282
- ... land_color='wheat',
283
- ... ocean_color='lightcyan'
284
- ... )
285
- """
232
+ """Setup a complete cartopy map with customizable features."""
286
233
  from matplotlib import ticker as mticker
287
234
 
288
235
  # Add map features
236
+ import cartopy.feature as cfeature
289
237
  if show_land:
290
238
  axes.add_feature(cfeature.LAND, facecolor=land_color)
291
239
  if show_ocean:
@@ -296,6 +244,7 @@ def setup_map(
296
244
  axes.add_feature(cfeature.BORDERS, linewidth=coastline_linewidth, linestyle=":")
297
245
 
298
246
  # Setup coordinate formatting
247
+ from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter
299
248
  lon_formatter = LongitudeFormatter(zero_direction_label=False, number_format=f".{tick_decimals}f")
300
249
  lat_formatter = LatitudeFormatter(number_format=f".{tick_decimals}f")
301
250
 
@@ -327,14 +276,14 @@ def setup_map(
327
276
  current_extent = axes.get_extent(crs=map_projection)
328
277
  lon_range = current_extent[1] - current_extent[0]
329
278
  # Generate reasonable tick spacing
330
- tick_spacing = 5 if lon_range <= 30 else (10 if lon_range <= 90 else 20)
279
+ tick_spacing = 1 if lon_range <= 10 else (5 if lon_range <= 30 else (10 if lon_range <= 90 else 20))
331
280
  longitude_ticks = np.arange(np.ceil(current_extent[0] / tick_spacing) * tick_spacing, current_extent[1] + tick_spacing, tick_spacing)
332
281
 
333
282
  if latitude_ticks is None:
334
283
  current_extent = axes.get_extent(crs=map_projection)
335
284
  lat_range = current_extent[3] - current_extent[2]
336
285
  # Generate reasonable tick spacing
337
- tick_spacing = 5 if lat_range <= 30 else (10 if lat_range <= 90 else 20)
286
+ tick_spacing = 1 if lat_range <= 10 else (5 if lat_range <= 30 else (10 if lat_range <= 90 else 20))
338
287
  latitude_ticks = np.arange(np.ceil(current_extent[2] / tick_spacing) * tick_spacing, current_extent[3] + tick_spacing, tick_spacing)
339
288
 
340
289
  # Set tick positions and formatters
@@ -343,12 +292,18 @@ def setup_map(
343
292
  axes.xaxis.set_major_formatter(lon_formatter)
344
293
  axes.yaxis.set_major_formatter(lat_formatter)
345
294
 
295
+ # Control label visibility based on input parameters
296
+ axes.tick_params(axis="x", labelbottom=bottom_labels, labeltop=top_labels)
297
+ axes.tick_params(axis="y", labelleft=left_labels, labelright=right_labels)
298
+
346
299
  # 只要传入经纬度数据就自动设置范围
347
300
  # 范围必须在cartopy添加地图特征之后设置,因为添加特征可能会改变axes的范围
348
301
  if longitude_data is not None and latitude_data is not None:
349
302
  # 过滤掉NaN,避免极端值影响
350
- lon_valid = np.asarray(longitude_data)[~np.isnan(longitude_data)]
351
- lat_valid = np.asarray(latitude_data)[~np.isnan(latitude_data)]
303
+ lon_data = np.asarray(longitude_data)
304
+ lat_data = np.asarray(latitude_data)
305
+ lon_valid = lon_data[~np.isnan(lon_data)]
306
+ lat_valid = lat_data[~np.isnan(lat_data)]
352
307
  if lon_valid.size > 0 and lat_valid.size > 0:
353
308
  lon_min, lon_max = np.min(lon_valid), np.max(lon_valid)
354
309
  lat_min, lat_max = np.min(lat_valid), np.max(lat_valid)
@@ -389,6 +344,23 @@ class MidpointNormalize(mpl.colors.Normalize):
389
344
  result = np.clip(result, 0, 1)
390
345
 
391
346
  return np.ma.masked_array(result)
347
+
348
+ def ticks(self, num_ticks: int = 7) -> np.ndarray:
349
+ """Generate ticks for the normalization range, centered around vcenter."""
350
+ if self.vmin is None or self.vmax is None:
351
+ raise ValueError("vmin and vmax must be set to generate ticks.")
352
+
353
+ if num_ticks % 2 == 0:
354
+ num_ticks += 1
355
+
356
+ num_points_side = (num_ticks - 1) // 2 + 1
357
+
358
+ negative_ticks = np.linspace(self.vmin, self.vcenter, num_points_side)[:-1]
359
+ positive_ticks = np.linspace(self.vcenter, self.vmax, num_points_side)[1:]
360
+
361
+ ticks = np.concatenate([negative_ticks, [self.vcenter], positive_ticks])
362
+
363
+ return ticks
392
364
 
393
365
  def inverse(self, value: np.ndarray) -> np.ndarray:
394
366
  y, x = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1]
oafuncs/oa_nc.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import os
2
2
  from typing import List, Optional, Tuple, Union
3
3
 
4
- import netCDF4 as nc
5
4
  import numpy as np
6
5
  import xarray as xr
7
6
  from rich import print
@@ -112,6 +111,7 @@ def rename(
112
111
  Example:
113
112
  >>> rename('file.nc', 'old_var', 'new_var')
114
113
  """
114
+ import netCDF4 as nc
115
115
  try:
116
116
  with nc.Dataset(file_path, "r+") as dataset:
117
117
  if old_name not in dataset.variables and old_name not in dataset.dimensions:
@@ -159,6 +159,7 @@ def check(
159
159
  return False
160
160
 
161
161
  try:
162
+ import netCDF4 as nc
162
163
  with nc.Dataset(file_path, "r") as ds_verify:
163
164
  if not ds_verify.variables:
164
165
  if print_messages:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oafuncs
3
- Version: 0.0.98.33
3
+ Version: 0.0.98.35
4
4
  Summary: Oceanic and Atmospheric Functions
5
5
  Home-page: https://github.com/Industry-Pays/OAFuncs
6
6
  Author: Kun Liu
@@ -1,11 +1,11 @@
1
1
  oafuncs/__init__.py,sha256=T_-VtnWWllV3Q91twT5Yt2sUapeA051QbPNnBxmg9nw,1456
2
- oafuncs/oa_cmap.py,sha256=KKEM3Dx0RYYFdLaj0eX6p1iQ1IcKR0RZmt7a3bMGO3Y,13609
3
- oafuncs/oa_data.py,sha256=Wp7Yn6n-WNddAp1UtwK5CSEdGSrzzgOH5gtaOHBaxtw,8065
2
+ oafuncs/oa_cmap.py,sha256=h9QrOSwbzZJXuS2pjFZkJtck1bq9itPY1natIuIRB3s,13884
3
+ oafuncs/oa_data.py,sha256=u4H1ZazQf2jmGx3IAiaGxLjQHY9cQEMizRIaTQW4UiE,8075
4
4
  oafuncs/oa_date.py,sha256=aU2wVIWXyWoRiSQ9dg8sHvShFTxw86RrgbV3Q6tDjD4,6841
5
- oafuncs/oa_draw.py,sha256=oPW1dlL0dKIfx4u18djBJfokhZAAAV7t-280DU4MblQ,15967
5
+ oafuncs/oa_draw.py,sha256=UnUyOcr6KHtEWCZG0TCnHFW0jrjkAW9XWZoUDcSs6oI,14386
6
6
  oafuncs/oa_file.py,sha256=fLb0gRhq2AiPl-5ASDHMrx6Z267FmhqNcTV7CdCxTdI,16934
7
7
  oafuncs/oa_help.py,sha256=0J5VaZX-cB0c090KxgmktQJBc0o00FsY-4wB8l5y00k,4178
8
- oafuncs/oa_nc.py,sha256=TMrrPBdPz1IJ-7dMOD_gzzTbG6FHSgm-ZfdlvoJDtcY,15245
8
+ oafuncs/oa_nc.py,sha256=mKNxQ9jPxfRH7xINyrX7tBhitG5gmOKm6Dn7stk5mdw,15279
9
9
  oafuncs/oa_python.py,sha256=xYMQnM0cGq9xUCtcoMpnN0LG5Rc_s94tai5nC6CNJ3E,4831
10
10
  oafuncs/oa_tool.py,sha256=Zuaoa92wll0YqXGRf0oF_c7wlATtl7bvjCuLt9VLXp0,8046
11
11
  oafuncs/_data/hycom.png,sha256=MadKs6Gyj5n9-TOu7L4atQfTXtF9dvN9w-tdU9IfygI,10945710
@@ -18,12 +18,11 @@ oafuncs/_script/netcdf_modify.py,sha256=XDlAEToe_lwfAetkBSENqU5df-wnH7MGuxNTjG1g
18
18
  oafuncs/_script/netcdf_write.py,sha256=GvyUyUhzMonzSp3y4pT8ZAfbQrsh5J3dLnmINYJKhuE,21422
19
19
  oafuncs/_script/parallel.py,sha256=07-BJVHxXJNlrOrhrSGt7qCZiKWq6dBvNDBA1AANYnI,8861
20
20
  oafuncs/_script/parallel_test.py,sha256=0GBqZOX7IaCOKF2t1y8N8YYu53GJ33OkfsWgpvZNqM4,372
21
- oafuncs/_script/plot_dataset.py,sha256=4jhUZNIc2DLHnk5GH0rotzhOq0cAMmB7rhMJKorYObo,16329
21
+ oafuncs/_script/plot_dataset.py,sha256=QrA4vOCzWbAJp3hf5YYzgIRUZdJB5_ugepgyT_YfnaY,16327
22
22
  oafuncs/_script/replace_file_content.py,sha256=wIwvaISFNYWG58BLZHZP9ZgbC5OhoZ-cpR3y25U1EUM,5601
23
23
  oafuncs/oa_down/User_Agent-list.txt,sha256=pHaMlElMvZ8TG4vf4BqkZYKqe0JIGkr4kCN0lM1Y9FQ,514295
24
24
  oafuncs/oa_down/__init__.py,sha256=IT6oTqaxuV_mC6AwBut0HtkmnVtEu1MyX0x0oS7TKoA,218
25
25
  oafuncs/oa_down/hycom_3hourly.py,sha256=y2ZoT1uCpWRJaOMRXzvW1e9f9lXzTTqw5kYVumzms5Q,55266
26
- oafuncs/oa_down/hycom_3hourly_proxy.py,sha256=xNAPSuTP0fvBAGMv16eeB2TCvNhS2cJq3M5F4GUmPN8,54180
27
26
  oafuncs/oa_down/idm.py,sha256=vAhRjt_Sb-rKhzFShmSf29QcFTqsHpHXCvTSD1uSXyQ,1455
28
27
  oafuncs/oa_down/literature.py,sha256=7Qy5OphcjdRwY2uZ5hmmgK36U_QtVmEUSW0vQaxihC8,10960
29
28
  oafuncs/oa_down/read_proxy.py,sha256=HQpr-Mwn0Z8ICAuf63NUUY9p05E_uNWyWmOK46-73Ec,2866
@@ -38,8 +37,8 @@ oafuncs/oa_sign/__init__.py,sha256=JSx1fcWpmNhQBvX_Bmq3xysfSkkFMrjbJASxV_V6aqE,1
38
37
  oafuncs/oa_sign/meteorological.py,sha256=3MSjy7HTcvz2zsITkjUMr_0Y027Gas1LFE9pk99990k,6110
39
38
  oafuncs/oa_sign/ocean.py,sha256=3uYEzaq-27yVy23IQoqy-clhWu1I_fhPFBAQyT-OF4M,5562
40
39
  oafuncs/oa_sign/scientific.py,sha256=moIl2MEY4uitbXoD596JmXookXGQtQsS-8_1NBBTx84,4689
41
- oafuncs-0.0.98.33.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
42
- oafuncs-0.0.98.33.dist-info/METADATA,sha256=SSKQ7VF-hVUtg_YT91r5QfPfL_sAMlIF5Cz0jPuTAbI,4326
43
- oafuncs-0.0.98.33.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
- oafuncs-0.0.98.33.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
45
- oafuncs-0.0.98.33.dist-info/RECORD,,
40
+ oafuncs-0.0.98.35.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
41
+ oafuncs-0.0.98.35.dist-info/METADATA,sha256=s4W9Zkj2_ALKyPBleO3l791AVeekgC508wE7XNRrpcU,4326
42
+ oafuncs-0.0.98.35.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
43
+ oafuncs-0.0.98.35.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
44
+ oafuncs-0.0.98.35.dist-info/RECORD,,