oafuncs 0.0.98.6__py3-none-any.whl → 0.0.98.7__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_down/hycom_3hourly.py +23 -12
- oafuncs/oa_draw.py +65 -0
- {oafuncs-0.0.98.6.dist-info → oafuncs-0.0.98.7.dist-info}/METADATA +2 -1
- {oafuncs-0.0.98.6.dist-info → oafuncs-0.0.98.7.dist-info}/RECORD +7 -7
- {oafuncs-0.0.98.6.dist-info → oafuncs-0.0.98.7.dist-info}/WHEEL +1 -1
- {oafuncs-0.0.98.6.dist-info → oafuncs-0.0.98.7.dist-info}/licenses/LICENSE.txt +0 -0
- {oafuncs-0.0.98.6.dist-info → oafuncs-0.0.98.7.dist-info}/top_level.txt +0 -0
oafuncs/oa_down/hycom_3hourly.py
CHANGED
@@ -19,7 +19,6 @@ import logging
|
|
19
19
|
import os
|
20
20
|
import random
|
21
21
|
import re
|
22
|
-
import time
|
23
22
|
import warnings
|
24
23
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
25
24
|
from pathlib import Path
|
@@ -728,9 +727,15 @@ class _HycomDownloader:
|
|
728
727
|
|
729
728
|
elapsed = datetime.datetime.now() - start
|
730
729
|
# logging.info(f"File {file_name} downloaded, Time: {elapsed}")
|
731
|
-
logging.info(f"Saving {file_name}
|
730
|
+
logging.info(f"Saving {file_name} ...")
|
731
|
+
logging.info(f"Timing {elapsed} ...")
|
732
732
|
self.count["success"] += 1
|
733
733
|
count_dict["success"] += 1
|
734
|
+
# 输出一条绿色的成功消息
|
735
|
+
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f")[:-3]
|
736
|
+
# print(f"{timestamp} - INFO - ", end="") # Output log prefix without newline
|
737
|
+
# print("[bold #3dfc40]Success")
|
738
|
+
print(f"{timestamp} - RESULT - [bold #3dfc40]Success")
|
734
739
|
return
|
735
740
|
|
736
741
|
except Exception as e:
|
@@ -744,6 +749,10 @@ class _HycomDownloader:
|
|
744
749
|
logging.error(f"Giving up on {file_name}")
|
745
750
|
self.count["fail"] += 1
|
746
751
|
count_dict["fail"] += 1
|
752
|
+
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f")[:-3]
|
753
|
+
# print(f"{timestamp} - ERROR - ", end="")
|
754
|
+
# print("[bold red]Failed")
|
755
|
+
print(f"{timestamp} - RESULT - [bold red]Failure")
|
747
756
|
return
|
748
757
|
|
749
758
|
async def run(self):
|
@@ -757,8 +766,7 @@ class _HycomDownloader:
|
|
757
766
|
|
758
767
|
def _download_file(target_url, store_path, file_name, cover=False):
|
759
768
|
save_path = Path(store_path) / file_name
|
760
|
-
file_name_split = file_name.split("_")
|
761
|
-
file_name_split = file_name_split[:-1]
|
769
|
+
file_name_split = file_name.split("_")[:-1]
|
762
770
|
same_file = "_".join(file_name_split) + "*nc"
|
763
771
|
|
764
772
|
if match_time is not None:
|
@@ -775,10 +783,12 @@ def _download_file(target_url, store_path, file_name, cover=False):
|
|
775
783
|
print(f"[bold green]{file_name} is correct")
|
776
784
|
return
|
777
785
|
|
778
|
-
if not cover and os.path.exists(save_path):
|
779
|
-
|
780
|
-
|
781
|
-
|
786
|
+
# if not cover and os.path.exists(save_path):
|
787
|
+
# print(f"[bold #FFA54F]{save_path} exists, skipping ...")
|
788
|
+
# count_dict["skip"] += 1
|
789
|
+
# return
|
790
|
+
if cover and os.path.exists(save_path):
|
791
|
+
_clear_existing_file(save_path)
|
782
792
|
|
783
793
|
if same_file not in fsize_dict.keys():
|
784
794
|
check_nc(save_path, delete_if_invalid=True, print_messages=False)
|
@@ -786,6 +796,7 @@ def _download_file(target_url, store_path, file_name, cover=False):
|
|
786
796
|
get_mean_size = _get_mean_size_move(same_file, save_path)
|
787
797
|
|
788
798
|
if _check_existing_file(save_path, get_mean_size):
|
799
|
+
print(f"[bold #FFA54F]{save_path} exists, skipping ...")
|
789
800
|
count_dict["skip"] += 1
|
790
801
|
return
|
791
802
|
|
@@ -794,12 +805,12 @@ def _download_file(target_url, store_path, file_name, cover=False):
|
|
794
805
|
if not use_idm:
|
795
806
|
python_downloader = _HycomDownloader([(target_url, save_path)])
|
796
807
|
asyncio.run(python_downloader.run())
|
797
|
-
time.sleep(3 + random.uniform(0, 10))
|
808
|
+
# time.sleep(3 + random.uniform(0, 10))
|
798
809
|
else:
|
799
810
|
idm_downloader(target_url, store_path, file_name, given_idm_engine)
|
800
811
|
idm_download_list.append(save_path)
|
801
812
|
# print(f"[bold #3dfc40]File [bold #dfff73]{save_path} [#3dfc40]has been submit to IDM for downloading")
|
802
|
-
time.sleep(3 + random.uniform(0, 10))
|
813
|
+
# time.sleep(3 + random.uniform(0, 10))
|
803
814
|
|
804
815
|
|
805
816
|
def _check_hour_is_valid(ymdh_str):
|
@@ -890,7 +901,7 @@ def _prepare_url_to_download(var, lon_min=0, lon_max=359.92, lat_min=-80, lat_ma
|
|
890
901
|
else:
|
891
902
|
if download_time < "2024081012":
|
892
903
|
varlist = [_ for _ in var]
|
893
|
-
for key, value in pbar(var_group.items(), description=f"
|
904
|
+
for key, value in pbar(var_group.items(), description=f"Var Group {download_time} ->", total=len(var_group), color="#d7feb9", next_line=True):
|
894
905
|
current_group = []
|
895
906
|
for v in varlist:
|
896
907
|
if v in value:
|
@@ -912,7 +923,7 @@ def _prepare_url_to_download(var, lon_min=0, lon_max=359.92, lat_min=-80, lat_ma
|
|
912
923
|
file_name = f"HYCOM_{key}_{download_time}-{download_time_end}.nc"
|
913
924
|
_download_file(submit_url, store_path, file_name, cover)
|
914
925
|
else:
|
915
|
-
for v in pbar(var,description=f
|
926
|
+
for v in pbar(var, description=f"Var {download_time} ->", total=len(var), color="#d7feb9", next_line=True):
|
916
927
|
submit_url = _get_submit_url_var(v, depth, level_num, lon_min, lon_max, lat_min, lat_max, dataset_name, version_name, download_time, download_time_end)
|
917
928
|
file_name = f"HYCOM_{variable_info[v]['var_name']}_{download_time}.nc"
|
918
929
|
if download_time_end is not None:
|
oafuncs/oa_draw.py
CHANGED
@@ -15,6 +15,7 @@ Python Version: 3.11
|
|
15
15
|
|
16
16
|
import warnings
|
17
17
|
|
18
|
+
import cv2
|
18
19
|
import cartopy.crs as ccrs
|
19
20
|
import cartopy.feature as cfeature
|
20
21
|
import matplotlib as mpl
|
@@ -132,6 +133,70 @@ def gif(image_paths: list[str], output_gif_name: str, frame_duration: float = 20
|
|
132
133
|
return
|
133
134
|
|
134
135
|
|
136
|
+
def movie(image_files, output_video_path, fps):
|
137
|
+
"""
|
138
|
+
从图像文件列表创建视频。
|
139
|
+
|
140
|
+
Args:
|
141
|
+
image_files (list): 按顺序排列的图像文件路径列表。
|
142
|
+
output_video_path (str): 输出视频文件的路径 (例如 'output.mp4')。
|
143
|
+
fps (int): 视频的帧率。
|
144
|
+
"""
|
145
|
+
if not image_files:
|
146
|
+
print("错误:图像文件列表为空。")
|
147
|
+
return
|
148
|
+
|
149
|
+
# 读取第一张图片以获取帧尺寸
|
150
|
+
try:
|
151
|
+
frame = cv2.imread(image_files[0])
|
152
|
+
if frame is None:
|
153
|
+
print(f"错误:无法读取第一张图片:{image_files[0]}")
|
154
|
+
return
|
155
|
+
height, width, layers = frame.shape
|
156
|
+
size = (width, height)
|
157
|
+
print(f"视频尺寸设置为:{size}")
|
158
|
+
except Exception as e:
|
159
|
+
print(f"读取第一张图片时出错:{e}")
|
160
|
+
return
|
161
|
+
|
162
|
+
# 选择编解码器并创建VideoWriter对象
|
163
|
+
# 对于 .mp4 文件,常用 'mp4v' 或 'avc1'
|
164
|
+
# 对于 .avi 文件,常用 'XVID' 或 'MJPG'
|
165
|
+
fourcc = cv2.VideoWriter_fourcc(*"mp4v") # 或者尝试 'avc1', 'XVID' 等
|
166
|
+
out = cv2.VideoWriter(output_video_path, fourcc, fps, size)
|
167
|
+
|
168
|
+
if not out.isOpened():
|
169
|
+
print(f"错误:无法打开视频文件进行写入:{output_video_path}")
|
170
|
+
print("请检查编解码器 ('fourcc') 是否受支持以及路径是否有效。")
|
171
|
+
return
|
172
|
+
|
173
|
+
print(f"开始将图像写入视频:{output_video_path}...")
|
174
|
+
for i, filename in enumerate(image_files):
|
175
|
+
try:
|
176
|
+
frame = cv2.imread(filename)
|
177
|
+
if frame is None:
|
178
|
+
print(f"警告:跳过无法读取的图像:{filename}")
|
179
|
+
continue
|
180
|
+
# 确保帧尺寸与初始化时相同,如果需要可以调整大小
|
181
|
+
current_height, current_width, _ = frame.shape
|
182
|
+
if (current_width, current_height) != size:
|
183
|
+
print(f"警告:图像 {filename} 的尺寸 ({current_width}, {current_height}) 与初始尺寸 {size} 不同。将调整大小。")
|
184
|
+
frame = cv2.resize(frame, size)
|
185
|
+
|
186
|
+
out.write(frame)
|
187
|
+
# 打印进度(可选)
|
188
|
+
if (i + 1) % 50 == 0 or (i + 1) == len(image_files):
|
189
|
+
print(f"已处理 {i + 1}/{len(image_files)} 帧")
|
190
|
+
|
191
|
+
except Exception as e:
|
192
|
+
print(f"处理图像 {filename} 时出错:{e}")
|
193
|
+
continue # 跳过有问题的帧
|
194
|
+
|
195
|
+
# 释放资源
|
196
|
+
out.release()
|
197
|
+
print(f"视频创建成功:{output_video_path}")
|
198
|
+
|
199
|
+
|
135
200
|
def add_lonlat_unit(longitudes: list[float] = None, latitudes: list[float] = None, decimal_places: int = 2) -> tuple[list[str], list[str]] | list[str]:
|
136
201
|
"""Convert longitude and latitude values to formatted string labels.
|
137
202
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: oafuncs
|
3
|
-
Version: 0.0.98.
|
3
|
+
Version: 0.0.98.7
|
4
4
|
Summary: Oceanic and Atmospheric Functions
|
5
5
|
Home-page: https://github.com/Industry-Pays/OAFuncs
|
6
6
|
Author: Kun Liu
|
@@ -27,6 +27,7 @@ Requires-Dist: requests
|
|
27
27
|
Requires-Dist: bs4
|
28
28
|
Requires-Dist: httpx
|
29
29
|
Requires-Dist: matplotlib
|
30
|
+
Requires-Dist: opencv-python
|
30
31
|
Requires-Dist: netCDF4
|
31
32
|
Requires-Dist: xlrd
|
32
33
|
Requires-Dist: geopandas
|
@@ -2,7 +2,7 @@ oafuncs/__init__.py,sha256=T_-VtnWWllV3Q91twT5Yt2sUapeA051QbPNnBxmg9nw,1456
|
|
2
2
|
oafuncs/oa_cmap.py,sha256=DimWT4Bg7uE5Lx8hSw1REp7whpsR2pFRStAwk1cowEM,11494
|
3
3
|
oafuncs/oa_data.py,sha256=0AbQ8_7vf9ecZaui6hmUjubkWRJxs4TGcdhJaPdbmP8,10958
|
4
4
|
oafuncs/oa_date.py,sha256=KqU-bHtC74hYsf6VgiA3i2vI__q_toOVR-whFy4cYP8,5523
|
5
|
-
oafuncs/oa_draw.py,sha256=
|
5
|
+
oafuncs/oa_draw.py,sha256=Wj2QBgyIPpV_dxaDrH10jqj_puK9ZM9rd-si-3VrsrE,17631
|
6
6
|
oafuncs/oa_file.py,sha256=goF5iRXJFFCIKhIjlkCnYYt0EYlJb_4r8AeYNZ0-SOk,16209
|
7
7
|
oafuncs/oa_help.py,sha256=_4AZgRDq5Or0vauNvq5IDDHIBoBfdOQtzak-mG1wwAw,4537
|
8
8
|
oafuncs/oa_nc.py,sha256=L1gqXxg93kIDsMOa87M0o-53KVmdqCipnXeF9XfzfY8,10513
|
@@ -21,7 +21,7 @@ oafuncs/_script/plot_dataset.py,sha256=zkSEnO_-biyagorwWXPoihts_cwuvripzEt-l9bHJ
|
|
21
21
|
oafuncs/_script/replace_file_content.py,sha256=eCFZjnZcwyRvy6b4mmIfBna-kylSZTyJRfgXd6DdCjk,5982
|
22
22
|
oafuncs/oa_down/User_Agent-list.txt,sha256=pHaMlElMvZ8TG4vf4BqkZYKqe0JIGkr4kCN0lM1Y9FQ,514295
|
23
23
|
oafuncs/oa_down/__init__.py,sha256=kRX5eTUCbAiz3zTaQM1501paOYS_3fizDN4Pa0mtNUA,585
|
24
|
-
oafuncs/oa_down/hycom_3hourly.py,sha256=
|
24
|
+
oafuncs/oa_down/hycom_3hourly.py,sha256=wWV14-OB9_LMmjUiZr3YXWBdKKwAyGXNa3Up7fSiWwk,55553
|
25
25
|
oafuncs/oa_down/hycom_3hourly_proxy.py,sha256=1eaoJGI_m-7w4ZZ3n7NGxkZaeFdsm0d3U-hyw8RFNbc,54563
|
26
26
|
oafuncs/oa_down/idm.py,sha256=4z5IvgfTyIKEI1kOtqXZwN7Jnfjwp6qDBOIoVyOLp0I,1823
|
27
27
|
oafuncs/oa_down/literature.py,sha256=2bF9gSKQbzcci9LcKE81j8JEjIJwON7jbwQB3gDDA3E,11331
|
@@ -37,8 +37,8 @@ oafuncs/oa_sign/__init__.py,sha256=QKqTFrJDFK40C5uvk48GlRRbGFzO40rgkYwu6dYxatM,5
|
|
37
37
|
oafuncs/oa_sign/meteorological.py,sha256=8091SHo2L8kl4dCFmmSH5NGVHDku5i5lSiLEG5DLnOQ,6489
|
38
38
|
oafuncs/oa_sign/ocean.py,sha256=xrW-rWD7xBWsB5PuCyEwQ1Q_RDKq2KCLz-LOONHgldU,5932
|
39
39
|
oafuncs/oa_sign/scientific.py,sha256=a4JxOBgm9vzNZKpJ_GQIQf7cokkraV5nh23HGbmTYKw,5064
|
40
|
-
oafuncs-0.0.98.
|
41
|
-
oafuncs-0.0.98.
|
42
|
-
oafuncs-0.0.98.
|
43
|
-
oafuncs-0.0.98.
|
44
|
-
oafuncs-0.0.98.
|
40
|
+
oafuncs-0.0.98.7.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
|
41
|
+
oafuncs-0.0.98.7.dist-info/METADATA,sha256=HotYRm4-mVHvJqg_pe71FgQpZ7mYKjd6WGr2PBbIeJY,4272
|
42
|
+
oafuncs-0.0.98.7.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
43
|
+
oafuncs-0.0.98.7.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
|
44
|
+
oafuncs-0.0.98.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|