cloudnetpy 1.56.12__py3-none-any.whl → 1.56.14__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.
- cloudnetpy/instruments/disdrometer/parsivel.py +51 -17
- cloudnetpy/plotting/plotting.py +2 -1
- cloudnetpy/products/classification.py +1 -1
- cloudnetpy/version.py +1 -1
- {cloudnetpy-1.56.12.dist-info → cloudnetpy-1.56.14.dist-info}/METADATA +1 -1
- {cloudnetpy-1.56.12.dist-info → cloudnetpy-1.56.14.dist-info}/RECORD +9 -9
- {cloudnetpy-1.56.12.dist-info → cloudnetpy-1.56.14.dist-info}/LICENSE +0 -0
- {cloudnetpy-1.56.12.dist-info → cloudnetpy-1.56.14.dist-info}/WHEEL +0 -0
- {cloudnetpy-1.56.12.dist-info → cloudnetpy-1.56.14.dist-info}/top_level.txt +0 -0
@@ -66,6 +66,9 @@ def parsivel2nc(
|
|
66
66
|
disdrometer = Parsivel(disdrometer_file, site_meta, telegram, date, timestamps)
|
67
67
|
disdrometer.sort_timestamps()
|
68
68
|
disdrometer.remove_duplicate_timestamps()
|
69
|
+
if len(disdrometer.data["time"].data) < 2:
|
70
|
+
msg = "Too few data points"
|
71
|
+
raise DisdrometerDataError(msg)
|
69
72
|
disdrometer.convert_units()
|
70
73
|
disdrometer.add_meta()
|
71
74
|
attributes = output.add_time_attribute(ATTRIBUTES, disdrometer.date)
|
@@ -495,30 +498,58 @@ def _read_toa5(filename: str | PathLike) -> dict[str, list]:
|
|
495
498
|
return data
|
496
499
|
|
497
500
|
|
498
|
-
def _read_typ_op4a(
|
501
|
+
def _read_typ_op4a(lines: list[str]) -> dict[str, list]:
|
499
502
|
"""Read output of "CS/PA" command. The output starts with line "TYP OP4A"
|
500
503
|
followed by one line per measured variable in format: <number>:<value>.
|
501
504
|
Output ends with characters: <ETX><CR><LF><NUL>. Lines are separated by
|
502
505
|
<CR><LF>.
|
503
506
|
"""
|
504
507
|
data = {}
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
data[varname] = [parser(iter(tokens))]
|
508
|
+
for line in lines:
|
509
|
+
if ":" not in line:
|
510
|
+
continue
|
511
|
+
key, value = line.strip().split(":", maxsplit=1)
|
512
|
+
# Skip datetime and 16-bit values.
|
513
|
+
if key in ("19", "30", "31", "32", "33"):
|
514
|
+
continue
|
515
|
+
varname = TELEGRAM.get(int(key))
|
516
|
+
if varname is None:
|
517
|
+
continue
|
518
|
+
parser = PARSERS.get(varname, next)
|
519
|
+
tokens = value.split(";")
|
520
|
+
data[varname] = [parser(iter(tokens))]
|
519
521
|
return data
|
520
522
|
|
521
523
|
|
524
|
+
def _read_fmi(content: str):
|
525
|
+
"""Read format used by Finnish Meteorological Institute and University of
|
526
|
+
Helsinki:
|
527
|
+
- "[YYYY-MM-DD HH:MM:SS\n"
|
528
|
+
- output of "CS/PA" command without non-printable characters at the end
|
529
|
+
- "]\n"
|
530
|
+
"""
|
531
|
+
output: dict[str, Any] = defaultdict(list)
|
532
|
+
for m in re.finditer(
|
533
|
+
r"\[(?P<year>\d+)-(?P<month>\d+)-(?P<day>\d+) "
|
534
|
+
r"(?P<hour>\d+):(?P<minute>\d+):(?P<second>\d+)"
|
535
|
+
r"(?P<output>[^\]]*)\]",
|
536
|
+
content,
|
537
|
+
):
|
538
|
+
for key, value in _read_typ_op4a(m["output"].splitlines()).items():
|
539
|
+
output[key].append(value)
|
540
|
+
output["_datetime"].append(
|
541
|
+
datetime.datetime(
|
542
|
+
int(m["year"]),
|
543
|
+
int(m["month"]),
|
544
|
+
int(m["day"]),
|
545
|
+
int(m["hour"]),
|
546
|
+
int(m["minute"]),
|
547
|
+
int(m["second"]),
|
548
|
+
)
|
549
|
+
)
|
550
|
+
return output
|
551
|
+
|
552
|
+
|
522
553
|
def _read_parsivel(
|
523
554
|
filenames: Iterable[str | PathLike],
|
524
555
|
telegram: Sequence[int | None] | None = None,
|
@@ -527,17 +558,20 @@ def _read_parsivel(
|
|
527
558
|
combined_data = defaultdict(list)
|
528
559
|
for filename in filenames:
|
529
560
|
with open(filename, encoding="latin1", errors="ignore") as file:
|
530
|
-
|
561
|
+
content = file.read()
|
562
|
+
lines = content.splitlines()
|
531
563
|
if not lines:
|
532
564
|
msg = f"File '{filename}' is empty"
|
533
565
|
raise DisdrometerDataError(msg)
|
534
566
|
if "TOA5" in lines[0]:
|
535
567
|
data = _read_toa5(filename)
|
536
568
|
elif "TYP OP4A" in lines[0]:
|
537
|
-
data = _read_typ_op4a(
|
569
|
+
data = _read_typ_op4a(lines)
|
538
570
|
elif "Date" in lines[0]:
|
539
571
|
headers = _parse_headers(lines[0])
|
540
572
|
data = _read_rows(headers, lines[1:])
|
573
|
+
elif "[" in lines[0]:
|
574
|
+
data = _read_fmi(content)
|
541
575
|
elif telegram is not None:
|
542
576
|
headers = _parse_telegram(telegram)
|
543
577
|
data = _read_rows(headers, lines)
|
cloudnetpy/plotting/plotting.py
CHANGED
@@ -629,7 +629,8 @@ class Plot1D(Plot):
|
|
629
629
|
sma = self._calculate_moving_average(data, time, window=5)
|
630
630
|
gap_time = _get_max_gap_in_minutes(figure_data)
|
631
631
|
gaps = self._find_time_gap_indices(time, max_gap_min=gap_time)
|
632
|
-
|
632
|
+
if len(gaps) > 0:
|
633
|
+
sma[gaps] = np.nan
|
633
634
|
if len(sma) == len(time):
|
634
635
|
self._ax.plot(
|
635
636
|
time,
|
@@ -166,7 +166,7 @@ DEFINITIONS = {
|
|
166
166
|
"Value 5: Good radar echo only.\n"
|
167
167
|
"Value 6: No radar echo but known attenuation.\n"
|
168
168
|
"Value 7: Radar echo corrected for liquid attenuation using microwave\n"
|
169
|
-
" radiometer data
|
169
|
+
" radiometer data.\n"
|
170
170
|
"Value 8: Radar ground clutter.\n"
|
171
171
|
"Value 9: Lidar clear-air molecular scattering."
|
172
172
|
),
|
cloudnetpy/version.py
CHANGED
@@ -8,7 +8,7 @@ cloudnetpy/metadata.py,sha256=Bcu1a9UyUq61jomuZ0_6hYIOzf61e5qCXeiwLm46ikw,5040
|
|
8
8
|
cloudnetpy/output.py,sha256=jD1pfBb4OQhVOrlhPEk-8FAi4bUW7zjAL468r6BPkJg,14586
|
9
9
|
cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
10
|
cloudnetpy/utils.py,sha256=yY5a5HLuAks2uzA4XbbqsGFEmXoyqECn_TjD3sMa0lI,27193
|
11
|
-
cloudnetpy/version.py,sha256=
|
11
|
+
cloudnetpy/version.py,sha256=Fa0L-CaTgGkRxlnKqX3a-6es2Ei1Q8LSXzXmGmFXq7w,73
|
12
12
|
cloudnetpy/categorize/__init__.py,sha256=gP5q3Vis1y9u9OWgA_idlbjfWXYN_S0IBSWdwBhL_uU,69
|
13
13
|
cloudnetpy/categorize/atmos.py,sha256=cax3iRmvr7S-VkUZqz0JCfAN3WEsUVbGfH4zSHy1APo,12384
|
14
14
|
cloudnetpy/categorize/atmos_utils.py,sha256=wndpwJxc2-QnNTkV8tc8I11Vs_WkNz9sVMX1fuGgUC4,3777
|
@@ -48,7 +48,7 @@ cloudnetpy/instruments/vaisala.py,sha256=E6PaK26lHprqOJUCEDZPZQu83Qan9n_THudTFQM
|
|
48
48
|
cloudnetpy/instruments/weather_station.py,sha256=IMJHGXfMhb4jJw_i66oGDCkeeRn3_eko8zVehu6Fte0,5970
|
49
49
|
cloudnetpy/instruments/disdrometer/__init__.py,sha256=lyjwttWvFvuwYxEkusoAvgRcbBmglmOp5HJOpXUqLWo,93
|
50
50
|
cloudnetpy/instruments/disdrometer/common.py,sha256=nWlVqwvlxei4wJaubBN6NoNsAOpnEqDHvKCPjrAb6Go,15701
|
51
|
-
cloudnetpy/instruments/disdrometer/parsivel.py,sha256=
|
51
|
+
cloudnetpy/instruments/disdrometer/parsivel.py,sha256=7clC_RS1vbHQ9xY5kHp0pShSRk9mnRwnWHMx42MJJSU,20766
|
52
52
|
cloudnetpy/instruments/disdrometer/thies.py,sha256=h7EwZ9tn47UUMiYqDQ68vkXv4q0rEqX1ZeFXd7XJYNg,5050
|
53
53
|
cloudnetpy/model_evaluation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
54
|
cloudnetpy/model_evaluation/file_handler.py,sha256=oUGIblcEWLLv16YKUch-M5KA-dGRAcuHa-9anP3xtX4,6447
|
@@ -92,9 +92,9 @@ cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py,sha256=Ra3r4V
|
|
92
92
|
cloudnetpy/model_evaluation/tests/unit/test_tools.py,sha256=Ia_VrLdV2NstX5gbx_3AZTOAlrgLAy_xFZ8fHYVX0xI,3817
|
93
93
|
cloudnetpy/plotting/__init__.py,sha256=lg9Smn4BI0dVBgnDLC3JVJ4GmwoSnO-qoSd4ApvwV6Y,107
|
94
94
|
cloudnetpy/plotting/plot_meta.py,sha256=NWI8ECKMypN5YyM9XKCAp1WEthbFlKMvilxqXmYSEK4,14631
|
95
|
-
cloudnetpy/plotting/plotting.py,sha256=
|
95
|
+
cloudnetpy/plotting/plotting.py,sha256=2NhSl_4gcLxOSlUEGPnwBNc0mUCmPracaguHo9kL51A,30714
|
96
96
|
cloudnetpy/products/__init__.py,sha256=2hRb5HG9hNrxH1if5laJkLeFeaZCd5W1q3hh4ewsX0E,273
|
97
|
-
cloudnetpy/products/classification.py,sha256=
|
97
|
+
cloudnetpy/products/classification.py,sha256=0E9OUGR3uLCsS1nORwQu0SqW0_8uX7n6LlRcVhtzKw4,7845
|
98
98
|
cloudnetpy/products/der.py,sha256=HAdPvbJySEqkIwDrdZDPnli_wnN2qwm72_D1a82ZWIs,12398
|
99
99
|
cloudnetpy/products/drizzle.py,sha256=BY2HvJeWt_ps6KKCGXwUUNRTy78q0cQM8bOCCoj8TWA,10803
|
100
100
|
cloudnetpy/products/drizzle_error.py,sha256=4GwlHRtNbk9ks7bGtXCco-wXbcDOKeAQwKmbhzut6Qk,6132
|
@@ -106,8 +106,8 @@ cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe5
|
|
106
106
|
cloudnetpy/products/mwr_tools.py,sha256=PRm5aCULccUehU-Byk55wYhhEHseMjoAjGBu5TSyHao,4621
|
107
107
|
cloudnetpy/products/product_tools.py,sha256=E8CSijBY8cr70BH2JFa0lGQ-RzI9EcHQ0Fzt8CQ8rY4,10442
|
108
108
|
docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
|
109
|
-
cloudnetpy-1.56.
|
110
|
-
cloudnetpy-1.56.
|
111
|
-
cloudnetpy-1.56.
|
112
|
-
cloudnetpy-1.56.
|
113
|
-
cloudnetpy-1.56.
|
109
|
+
cloudnetpy-1.56.14.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
|
110
|
+
cloudnetpy-1.56.14.dist-info/METADATA,sha256=nSphTgk88JFpj2s5KJX9SLUFuHkKBIcLvUcm0ZC2w8E,5734
|
111
|
+
cloudnetpy-1.56.14.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
112
|
+
cloudnetpy-1.56.14.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
|
113
|
+
cloudnetpy-1.56.14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|