cloudnetpy 1.56.1__py3-none-any.whl → 1.56.3__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.
Files changed (60) hide show
  1. cloudnetpy/categorize/atmos.py +0 -27
  2. cloudnetpy/categorize/atmos_utils.py +0 -10
  3. cloudnetpy/categorize/categorize.py +1 -6
  4. cloudnetpy/categorize/classify.py +0 -12
  5. cloudnetpy/categorize/containers.py +0 -6
  6. cloudnetpy/categorize/droplet.py +0 -17
  7. cloudnetpy/categorize/falling.py +0 -3
  8. cloudnetpy/categorize/freezing.py +0 -5
  9. cloudnetpy/categorize/insects.py +0 -3
  10. cloudnetpy/categorize/lidar.py +0 -1
  11. cloudnetpy/categorize/melting.py +0 -3
  12. cloudnetpy/categorize/model.py +0 -5
  13. cloudnetpy/categorize/mwr.py +0 -2
  14. cloudnetpy/categorize/radar.py +0 -8
  15. cloudnetpy/cloudnetarray.py +0 -6
  16. cloudnetpy/concat_lib.py +0 -5
  17. cloudnetpy/datasource.py +0 -12
  18. cloudnetpy/instruments/basta.py +0 -5
  19. cloudnetpy/instruments/ceilo.py +0 -4
  20. cloudnetpy/instruments/ceilometer.py +0 -2
  21. cloudnetpy/instruments/copernicus.py +0 -6
  22. cloudnetpy/instruments/disdrometer/parsivel.py +0 -5
  23. cloudnetpy/instruments/disdrometer/thies.py +0 -4
  24. cloudnetpy/instruments/galileo.py +0 -5
  25. cloudnetpy/instruments/hatpro.py +0 -6
  26. cloudnetpy/instruments/mira.py +0 -5
  27. cloudnetpy/instruments/mrr.py +0 -5
  28. cloudnetpy/instruments/nc_radar.py +0 -2
  29. cloudnetpy/instruments/pollyxt.py +0 -3
  30. cloudnetpy/instruments/radiometrics.py +0 -4
  31. cloudnetpy/instruments/rpg.py +0 -5
  32. cloudnetpy/instruments/rpg_reader.py +0 -1
  33. cloudnetpy/instruments/vaisala.py +0 -4
  34. cloudnetpy/instruments/weather_station.py +0 -3
  35. cloudnetpy/model_evaluation/file_handler.py +0 -4
  36. cloudnetpy/model_evaluation/plotting/plotting.py +0 -6
  37. cloudnetpy/model_evaluation/products/advance_methods.py +0 -1
  38. cloudnetpy/model_evaluation/products/grid_methods.py +0 -2
  39. cloudnetpy/model_evaluation/products/model_products.py +0 -2
  40. cloudnetpy/model_evaluation/products/observation_products.py +0 -2
  41. cloudnetpy/model_evaluation/products/product_resampling.py +0 -4
  42. cloudnetpy/model_evaluation/products/tools.py +0 -2
  43. cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -4
  44. cloudnetpy/output.py +0 -9
  45. cloudnetpy/products/classification.py +0 -3
  46. cloudnetpy/products/der.py +0 -4
  47. cloudnetpy/products/drizzle.py +0 -8
  48. cloudnetpy/products/drizzle_error.py +0 -2
  49. cloudnetpy/products/drizzle_tools.py +0 -12
  50. cloudnetpy/products/ier.py +0 -4
  51. cloudnetpy/products/iwc.py +0 -4
  52. cloudnetpy/products/lwc.py +0 -14
  53. cloudnetpy/products/product_tools.py +0 -9
  54. cloudnetpy/utils.py +0 -81
  55. cloudnetpy/version.py +1 -1
  56. {cloudnetpy-1.56.1.dist-info → cloudnetpy-1.56.3.dist-info}/METADATA +4 -5
  57. {cloudnetpy-1.56.1.dist-info → cloudnetpy-1.56.3.dist-info}/RECORD +60 -60
  58. {cloudnetpy-1.56.1.dist-info → cloudnetpy-1.56.3.dist-info}/LICENSE +0 -0
  59. {cloudnetpy-1.56.1.dist-info → cloudnetpy-1.56.3.dist-info}/WHEEL +0 -0
  60. {cloudnetpy-1.56.1.dist-info → cloudnetpy-1.56.3.dist-info}/top_level.txt +0 -0
cloudnetpy/utils.py CHANGED
@@ -26,15 +26,12 @@ def seconds2hours(time_in_seconds: np.ndarray) -> np.ndarray:
26
26
  """Converts seconds since some epoch to fraction hour.
27
27
 
28
28
  Args:
29
- ----
30
29
  time_in_seconds: 1-D array of seconds since some epoch that starts on midnight.
31
30
 
32
31
  Returns:
33
- -------
34
32
  Time as fraction hour.
35
33
 
36
34
  Notes:
37
- -----
38
35
  Excludes leap seconds.
39
36
 
40
37
  """
@@ -49,11 +46,9 @@ def seconds2time(time_in_seconds: float) -> list:
49
46
  """Converts seconds since some epoch to time of day.
50
47
 
51
48
  Args:
52
- ----
53
49
  time_in_seconds: seconds since some epoch.
54
50
 
55
51
  Returns:
56
- -------
57
52
  list: [hours, minutes, seconds] formatted as '05' etc.
58
53
 
59
54
  """
@@ -69,12 +64,10 @@ def seconds2date(time_in_seconds: float, epoch: Epoch = (2001, 1, 1)) -> list:
69
64
  """Converts seconds since some epoch to datetime (UTC).
70
65
 
71
66
  Args:
72
- ----
73
67
  time_in_seconds: Seconds since some epoch.
74
68
  epoch: Epoch, default is (2001, 1, 1) (UTC).
75
69
 
76
70
  Returns:
77
- -------
78
71
  [year, month, day, hours, minutes, seconds] formatted as '05' etc (UTC).
79
72
 
80
73
  """
@@ -106,15 +99,12 @@ def time_grid(time_step: int = 30) -> np.ndarray:
106
99
  resolution (in seconds).
107
100
 
108
101
  Args:
109
- ----
110
102
  time_step: Time resolution in seconds, greater than 1. Default is 30.
111
103
 
112
104
  Returns:
113
- -------
114
105
  Time vector between 0 and 24.
115
106
 
116
107
  Raises:
117
- ------
118
108
  ValueError: Bad resolution as input.
119
109
 
120
110
  """
@@ -129,15 +119,12 @@ def binvec(x: np.ndarray | list) -> np.ndarray:
129
119
  """Converts 1-D center points to bins with even spacing.
130
120
 
131
121
  Args:
132
- ----
133
122
  x: 1-D array of N real values.
134
123
 
135
124
  Returns:
136
- -------
137
125
  ndarray: N + 1 edge values.
138
126
 
139
127
  Examples:
140
- --------
141
128
  >>> binvec([1, 2, 3])
142
129
  [0.5, 1.5, 2.5, 3.5]
143
130
 
@@ -157,7 +144,6 @@ def rebin_2d(
157
144
  """Rebins 2-D data in one dimension.
158
145
 
159
146
  Args:
160
- ----
161
147
  x_in: 1-D array with shape (n,).
162
148
  array: 2-D input data with shape (n, m).
163
149
  x_new: 1-D target vector (center points) with shape (N,).
@@ -166,11 +152,9 @@ def rebin_2d(
166
152
  n_min: Minimum number of points to have good statistics in a bin. Default is 1.
167
153
 
168
154
  Returns:
169
- -------
170
155
  tuple: Rebinned data with shape (N, m) and indices of bins without enough data.
171
156
 
172
157
  Notes:
173
- -----
174
158
  0-values are masked in the returned array.
175
159
 
176
160
  """
@@ -211,7 +195,6 @@ def rebin_1d(
211
195
  """Rebins 1D array.
212
196
 
213
197
  Args:
214
- ----
215
198
  x_in: 1-D array with shape (n,).
216
199
  array: 1-D input data with shape (m,).
217
200
  x_new: 1-D target vector (center points) with shape (N,).
@@ -219,7 +202,6 @@ def rebin_1d(
219
202
  Default is 'mean'.
220
203
 
221
204
  Returns:
222
- -------
223
205
  Re-binned data with shape (N,).
224
206
 
225
207
  """
@@ -242,15 +224,12 @@ def filter_isolated_pixels(array: np.ndarray) -> np.ndarray:
242
224
  """From a 2D boolean array, remove completely isolated single cells.
243
225
 
244
226
  Args:
245
- ----
246
227
  array: 2-D boolean array containing isolated values.
247
228
 
248
229
  Returns:
249
- -------
250
230
  Cleaned array.
251
231
 
252
232
  Examples:
253
- --------
254
233
  >>> filter_isolated_pixels([[0, 0, 0], [0, 1, 0], [0, 0, 0]])
255
234
  array([[0, 0, 0],
256
235
  [0, 0, 0],
@@ -265,19 +244,15 @@ def filter_x_pixels(array: np.ndarray) -> np.ndarray:
265
244
  """From a 2D boolean array, remove cells isolated in x-direction.
266
245
 
267
246
  Args:
268
- ----
269
247
  array: 2-D boolean array containing isolated pixels in x-direction.
270
248
 
271
249
  Returns:
272
- -------
273
250
  Cleaned array.
274
251
 
275
252
  Notes:
276
- -----
277
253
  Stronger cleaning than `filter_isolated_pixels()`
278
254
 
279
255
  Examples:
280
- --------
281
256
  >>> filter_x_pixels([[1, 0, 0], [0, 1, 0], [0, 1, 1]])
282
257
  array([[0, 0, 0],
283
258
  [0, 1, 0],
@@ -301,27 +276,22 @@ def isbit(array: np.ndarray, nth_bit: int) -> np.ndarray:
301
276
  """Tests if nth bit (0,1,2,...) is set.
302
277
 
303
278
  Args:
304
- ----
305
279
  array: Integer array.
306
280
  nth_bit: Investigated bit.
307
281
 
308
282
  Returns:
309
- -------
310
283
  Boolean array denoting values where nth_bit is set.
311
284
 
312
285
  Raises:
313
- ------
314
286
  ValueError: negative bit as input.
315
287
 
316
288
  Examples:
317
- --------
318
289
  >>> isbit(4, 1)
319
290
  False
320
291
  >>> isbit(4, 2)
321
292
  True
322
293
 
323
294
  See Also:
324
- --------
325
295
  utils.setbit()
326
296
 
327
297
  """
@@ -336,27 +306,22 @@ def setbit(array: np.ndarray, nth_bit: int) -> np.ndarray:
336
306
  """Sets nth bit (0, 1, 2, ...) on number.
337
307
 
338
308
  Args:
339
- ----
340
309
  array: Integer array.
341
310
  nth_bit: Bit to be set.
342
311
 
343
312
  Returns:
344
- -------
345
313
  Integer where nth bit is set.
346
314
 
347
315
  Raises:
348
- ------
349
316
  ValueError: negative bit as input.
350
317
 
351
318
  Examples:
352
- --------
353
319
  >>> setbit(1, 1)
354
320
  3
355
321
  >>> setbit(0, 2)
356
322
  4
357
323
 
358
324
  See Also:
359
- --------
360
325
  utils.isbit()
361
326
 
362
327
  """
@@ -378,7 +343,6 @@ def interpolate_2d(
378
343
  """Linear interpolation of gridded 2d data.
379
344
 
380
345
  Args:
381
- ----
382
346
  x: 1-D array.
383
347
  y: 1-D array.
384
348
  z: 2-D array at points (x, y).
@@ -386,11 +350,9 @@ def interpolate_2d(
386
350
  y_new: 1-D array.
387
351
 
388
352
  Returns:
389
- -------
390
353
  Interpolated data.
391
354
 
392
355
  Notes:
393
- -----
394
356
  Does not work with nans. Ignores mask of masked data. Does not extrapolate.
395
357
 
396
358
  """
@@ -408,7 +370,6 @@ def interpolate_2d_mask(
408
370
  """2D linear interpolation preserving the mask.
409
371
 
410
372
  Args:
411
- ----
412
373
  x: 1D array, x-coordinates.
413
374
  y: 1D array, y-coordinates.
414
375
  z: 2D masked array, data values.
@@ -416,11 +377,9 @@ def interpolate_2d_mask(
416
377
  y_new: 1D array, new y-coordinates.
417
378
 
418
379
  Returns:
419
- -------
420
380
  Interpolated 2D masked array.
421
381
 
422
382
  Notes:
423
- -----
424
383
  Points outside the original range will be nans (and masked). Uses linear
425
384
  interpolation. Input data may contain nan-values.
426
385
 
@@ -457,7 +416,6 @@ def interpolate_2d_nearest(
457
416
  """2D nearest neighbor interpolation preserving mask.
458
417
 
459
418
  Args:
460
- ----
461
419
  x: 1D array, x-coordinates.
462
420
  y: 1D array, y-coordinates.
463
421
  z: 2D masked array, data values.
@@ -465,11 +423,9 @@ def interpolate_2d_nearest(
465
423
  y_new: 1D array, new y-coordinates.
466
424
 
467
425
  Returns:
468
- -------
469
426
  Interpolated 2D masked array.
470
427
 
471
428
  Notes:
472
- -----
473
429
  Points outside the original range will be interpolated but masked.
474
430
 
475
431
  """
@@ -516,11 +472,9 @@ def l2norm(*args) -> ma.MaskedArray:
516
472
  """Returns l2 norm.
517
473
 
518
474
  Args:
519
- ----
520
475
  *args: Variable number of data (*array_like*) with the same shape.
521
476
 
522
477
  Returns:
523
- -------
524
478
  The l2 norm.
525
479
 
526
480
  """
@@ -548,14 +502,12 @@ def l2norm_weighted(
548
502
  for the terms.
549
503
 
550
504
  Args:
551
- ----
552
505
  values: Tuple containing the values.
553
506
  overall_scale: Scale factor for the calculated Euclidean distance.
554
507
  term_weights: Weights for the terms. Must be single float or a list of numbers
555
508
  (one per term).
556
509
 
557
510
  Returns:
558
- -------
559
511
  Scaled and weighted Euclidean distance.
560
512
 
561
513
  TODO: Use masked arrays instead of tuples.
@@ -570,16 +522,13 @@ def cumsumr(array: np.ndarray, axis: int = 0) -> np.ndarray:
570
522
  """Finds cumulative sum that resets on 0.
571
523
 
572
524
  Args:
573
- ----
574
525
  array: Input array.
575
526
  axis: Axis where the sum is calculated. Default is 0.
576
527
 
577
528
  Returns:
578
- -------
579
529
  Cumulative sum, restarted at 0.
580
530
 
581
531
  Examples:
582
- --------
583
532
  >>> x = np.array([0, 0, 1, 1, 0, 0, 0, 1, 1, 1])
584
533
  >>> cumsumr(x)
585
534
  [0, 0, 1, 2, 0, 0, 0, 1, 2, 3]
@@ -593,22 +542,18 @@ def ffill(array: np.ndarray, value: int = 0) -> np.ndarray:
593
542
  """Forward fills an array.
594
543
 
595
544
  Args:
596
- ----
597
545
  array: 1-D or 2-D array.
598
546
  value: Value to be filled. Default is 0.
599
547
 
600
548
  Returns:
601
- -------
602
549
  ndarray: Forward-filled array.
603
550
 
604
551
  Examples:
605
- --------
606
552
  >>> x = np.array([0, 5, 0, 0, 2, 0])
607
553
  >>> ffill(x)
608
554
  [0, 5, 5, 5, 2, 2]
609
555
 
610
556
  Notes:
611
- -----
612
557
  Works only in axis=1 direction.
613
558
 
614
559
  """
@@ -631,7 +576,6 @@ def init(
631
576
  """Initializes several numpy arrays.
632
577
 
633
578
  Args:
634
- ----
635
579
  n_vars: Number of arrays to be generated.
636
580
  shape: Shape of the arrays, e.g. (2, 3).
637
581
  dtype: The desired data-type for the arrays, e.g., int. Default is float.
@@ -639,11 +583,9 @@ def init(
639
583
  Default is True.
640
584
 
641
585
  Yields:
642
- ------
643
586
  Iterator containing the empty arrays.
644
587
 
645
588
  Examples:
646
- --------
647
589
  >>> a, b = init(2, (2, 3))
648
590
  >>> a
649
591
  masked_array(
@@ -664,7 +606,6 @@ def n_elements(array: np.ndarray, dist: float, var: str | None = None) -> int:
664
606
  """Returns the number of elements that cover certain distance.
665
607
 
666
608
  Args:
667
- ----
668
609
  array: Input array with arbitrary units or time in fraction hour. *x* should
669
610
  be evenly spaced or at least close to.
670
611
  dist: Distance to be covered. If x is fraction time, *dist* is in minutes.
@@ -673,11 +614,9 @@ def n_elements(array: np.ndarray, dist: float, var: str | None = None) -> int:
673
614
  have the same units. Default is None (same units).
674
615
 
675
616
  Returns:
676
- -------
677
617
  Number of elements in the input array that cover *dist*.
678
618
 
679
619
  Examples:
680
- --------
681
620
  >>> x = np.array([2, 4, 6, 8, 10])
682
621
  >>> n_elements(x, 6)
683
622
  3
@@ -708,7 +647,6 @@ def isscalar(array: np.ndarray | float | list) -> bool:
708
647
  By "scalar" we mean that array has a single value.
709
648
 
710
649
  Examples
711
- --------
712
650
  >>> isscalar(1)
713
651
  True
714
652
  >>> isscalar([1])
@@ -748,11 +686,9 @@ def get_wl_band(radar_frequency: float) -> int:
748
686
  """Returns integer corresponding to radar frequency.
749
687
 
750
688
  Args:
751
- ----
752
689
  radar_frequency: Radar frequency (GHz).
753
690
 
754
691
  Returns:
755
- -------
756
692
  0 = 35GHz radar, 1 = 94Ghz radar.
757
693
 
758
694
  """
@@ -776,12 +712,10 @@ def del_dict_keys(data: dict, keys: tuple | list) -> dict:
776
712
  """Deletes multiple keys from dictionary.
777
713
 
778
714
  Args:
779
- ----
780
715
  data: A dictionary.
781
716
  keys: Keys to be deleted.
782
717
 
783
718
  Returns:
784
- -------
785
719
  Dictionary without the deleted keys.
786
720
 
787
721
  """
@@ -802,7 +736,6 @@ def array_to_probability(
802
736
  """Converts continuous variable into 0-1 probability.
803
737
 
804
738
  Args:
805
- ----
806
739
  array: Numpy array.
807
740
  loc: Center of the distribution. Values smaller than this will have small
808
741
  probability. Values greater than this will have large probability.
@@ -812,7 +745,6 @@ def array_to_probability(
812
745
  Default is False.
813
746
 
814
747
  Returns:
815
- -------
816
748
  Probability with the same shape as the input data.
817
749
 
818
750
  """
@@ -830,16 +762,13 @@ def range_to_height(range_los: np.ndarray, tilt_angle: float) -> np.ndarray:
830
762
  """Converts distances from a tilted instrument to height above the ground.
831
763
 
832
764
  Args:
833
- ----
834
765
  range_los: Distances towards the line of sign from the instrument.
835
766
  tilt_angle: Angle in degrees from the zenith (0 = zenith).
836
767
 
837
768
  Returns:
838
- -------
839
769
  Altitudes of the LOS points.
840
770
 
841
771
  Notes:
842
- -----
843
772
  Uses plane parallel Earth approximation.
844
773
 
845
774
  """
@@ -906,17 +835,14 @@ def screen_by_time(data_in: dict, epoch: Epoch, expected_date: str) -> dict:
906
835
  """Screen data by time.
907
836
 
908
837
  Args:
909
- ----
910
838
  data_in: Dictionary containing at least 'time' key and other numpy arrays.
911
839
  epoch: Epoch of the time array, e.g., (1970, 1, 1)
912
840
  expected_date: Expected date in yyyy-mm-dd
913
841
 
914
842
  Returns:
915
- -------
916
843
  data: Screened and sorted by the time vector.
917
844
 
918
845
  Notes:
919
- -----
920
846
  - Requires 'time' key
921
847
  - Works for dimensions 1, 2, 3 (time has to be at 0-axis)
922
848
  - Does nothing for scalars
@@ -946,21 +872,17 @@ def find_valid_time_indices(time: np.ndarray, epoch: Epoch, expected_date: str)
946
872
  """Finds valid time array indices for the given date.
947
873
 
948
874
  Args:
949
- ----
950
875
  time: Time in seconds from some epoch.
951
876
  epoch: Epoch of the time array, e.g., (1970, 1, 1)
952
877
  expected_date: Expected date in yyyy-mm-dd
953
878
 
954
879
  Returns:
955
- -------
956
880
  list: Valid indices for the given date in sorted order.
957
881
 
958
882
  Raises:
959
- ------
960
883
  RuntimeError: No valid timestamps.
961
884
 
962
885
  Examples:
963
- --------
964
886
  >>> time = [1, 5, 1e6, 3]
965
887
  >>> find_valid_time_indices(time, (1970, 1, 1) '1970-01-01')
966
888
  [0, 3, 2]
@@ -981,7 +903,6 @@ def append_data(data_in: dict, key: str, array: np.ndarray) -> dict:
981
903
  """Appends data to a dictionary field (creates the field if not yet present).
982
904
 
983
905
  Args:
984
- ----
985
906
  data_in: Dictionary where data will be appended.
986
907
  key: Key of the field.
987
908
  array: Numpy array to be appended to data_in[key].
@@ -999,12 +920,10 @@ def edges2mid(data: np.ndarray, reference: Literal["upper", "lower"]) -> np.ndar
999
920
  """Shifts values half bin towards up or down.
1000
921
 
1001
922
  Args:
1002
- ----
1003
923
  data: 1D numpy array (e.g. range)
1004
924
  reference: If 'lower', increase values by half bin. If 'upper', decrease values.
1005
925
 
1006
926
  Returns:
1007
- -------
1008
927
  Shifted values.
1009
928
 
1010
929
  """
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
2
  MINOR = 56
3
- PATCH = 1
3
+ PATCH = 3
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudnetpy
3
- Version: 1.56.1
3
+ Version: 1.56.3
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -26,7 +26,7 @@ License: MIT License
26
26
  SOFTWARE.
27
27
 
28
28
  Project-URL: Homepage, https://github.com/actris-cloudnet/cloudnetpy
29
- Project-URL: Documentation, https://cloudnetpy.readthedocs.io
29
+ Project-URL: Documentation, https://actris-cloudnet.github.io/cloudnetpy/
30
30
  Project-URL: Repository, https://github.com/actris-cloudnet/cloudnetpy
31
31
  Project-URL: Changelog, https://github.com/actris-cloudnet/cloudnetpy/blob/main/CHANGELOG.md
32
32
  Classifier: Development Status :: 5 - Production/Stable
@@ -62,7 +62,6 @@ Requires-Dist: types-requests ; extra == 'test'
62
62
  # CloudnetPy
63
63
 
64
64
  [![CloudnetPy CI](https://github.com/actris-cloudnet/cloudnetpy/actions/workflows/test.yml/badge.svg)](https://github.com/actris-cloudnet/cloudnetpy/actions/workflows/test.yml)
65
- [![Documentation Status](https://readthedocs.org/projects/cloudnetpy/badge/?version=latest)](https://cloudnetpy.readthedocs.io/en/latest/?badge=latest)
66
65
  [![PyPI version](https://badge.fury.io/py/cloudnetpy.svg)](https://badge.fury.io/py/cloudnetpy)
67
66
  [![DOI](https://zenodo.org/badge/233602651.svg)](https://zenodo.org/badge/latestdoi/233602651)
68
67
  [![status](https://joss.theoj.org/papers/959971f196f617dddc0e7d8333ff22b7/status.svg)](https://joss.theoj.org/papers/959971f196f617dddc0e7d8333ff22b7)
@@ -77,8 +76,8 @@ retrieved in further processing steps. See [Illingworth et al. (2007)](https://d
77
76
 
78
77
  CloudnetPy is a rewritten version of the original Cloudnet Matlab code. It features several revised methods, extensive documentation, and more.
79
78
 
80
- - CloudnetPy documentation: https://cloudnetpy.readthedocs.io/en/latest/
81
- - Cloudnet data portal: https://cloudnet.fmi.fi
79
+ - CloudnetPy documentation: <https://actris-cloudnet.github.io/cloudnetpy/>
80
+ - Cloudnet data portal: <https://cloudnet.fmi.fi>
82
81
 
83
82
  ![CloudnetPy example output](https://raw.githubusercontent.com/actris-cloudnet/cloudnetpy/main/docs/source/_static/20230831_lindenberg_classification-9b74f4ac-target_classification.png)
84
83