cloudnetpy 1.85.4__tar.gz → 1.86.0__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.
Files changed (133) hide show
  1. {cloudnetpy-1.85.4/cloudnetpy.egg-info → cloudnetpy-1.86.0}/PKG-INFO +1 -1
  2. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/containers.py +12 -4
  3. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/disdrometer.py +5 -2
  4. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/fd12p.py +0 -3
  5. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/mrr.py +7 -0
  6. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/metadata.py +3 -0
  7. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/plotting/plot_meta.py +7 -1
  8. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/plotting/plotting.py +11 -0
  9. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/classification.py +18 -5
  10. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/utils.py +7 -2
  11. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/version.py +2 -2
  12. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0/cloudnetpy.egg-info}/PKG-INFO +1 -1
  13. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/LICENSE +0 -0
  14. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/MANIFEST.in +0 -0
  15. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/README.md +0 -0
  16. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/__init__.py +0 -0
  17. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/__init__.py +0 -0
  18. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/atmos_utils.py +0 -0
  19. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/attenuation.py +0 -0
  20. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/attenuations/__init__.py +0 -0
  21. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
  22. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +0 -0
  23. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/attenuations/melting_attenuation.py +0 -0
  24. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/attenuations/rain_attenuation.py +0 -0
  25. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/categorize.py +0 -0
  26. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/classify.py +0 -0
  27. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/droplet.py +0 -0
  28. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/falling.py +0 -0
  29. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/freezing.py +0 -0
  30. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/insects.py +0 -0
  31. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/itu.py +0 -0
  32. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/lidar.py +0 -0
  33. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/melting.py +0 -0
  34. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/model.py +0 -0
  35. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/mwr.py +0 -0
  36. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/categorize/radar.py +0 -0
  37. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/cli.py +0 -0
  38. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/cloudnetarray.py +0 -0
  39. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/concat_lib.py +0 -0
  40. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/constants.py +0 -0
  41. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/datasource.py +0 -0
  42. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/exceptions.py +0 -0
  43. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/__init__.py +0 -0
  44. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/basta.py +0 -0
  45. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/bowtie.py +0 -0
  46. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/ceilo.py +0 -0
  47. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/ceilometer.py +0 -0
  48. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/cl61d.py +0 -0
  49. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/cloudnet_instrument.py +0 -0
  50. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/copernicus.py +0 -0
  51. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/da10.py +0 -0
  52. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/disdrometer/__init__.py +0 -0
  53. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/disdrometer/common.py +0 -0
  54. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/disdrometer/parsivel.py +0 -0
  55. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/disdrometer/thies.py +0 -0
  56. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/galileo.py +0 -0
  57. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/hatpro.py +0 -0
  58. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/instruments.py +0 -0
  59. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/lufft.py +0 -0
  60. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/mira.py +0 -0
  61. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/nc_lidar.py +0 -0
  62. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/nc_radar.py +0 -0
  63. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/pollyxt.py +0 -0
  64. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/radiometrics.py +0 -0
  65. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/rain_e_h3.py +0 -0
  66. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/rpg.py +0 -0
  67. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/rpg_reader.py +0 -0
  68. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/toa5.py +0 -0
  69. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/vaisala.py +0 -0
  70. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/instruments/weather_station.py +0 -0
  71. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/__init__.py +0 -0
  72. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/file_handler.py +0 -0
  73. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/metadata.py +0 -0
  74. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
  75. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
  76. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
  77. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/plotting/plot_tools.py +0 -0
  78. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/plotting/plotting.py +0 -0
  79. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
  80. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/products/advance_methods.py +0 -0
  81. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/products/grid_methods.py +0 -0
  82. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/products/model_products.py +0 -0
  83. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/products/observation_products.py +0 -0
  84. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/products/product_resampling.py +0 -0
  85. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/products/tools.py +0 -0
  86. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
  87. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -0
  88. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
  89. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
  90. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
  91. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
  92. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
  93. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
  94. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
  95. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
  96. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
  97. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
  98. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
  99. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
  100. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
  101. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
  102. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
  103. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
  104. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +0 -0
  105. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
  106. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
  107. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +0 -0
  108. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
  109. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +0 -0
  110. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/model_evaluation/utils.py +0 -0
  111. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/output.py +0 -0
  112. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/plotting/__init__.py +0 -0
  113. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/__init__.py +0 -0
  114. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/der.py +0 -0
  115. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/drizzle.py +0 -0
  116. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/drizzle_error.py +0 -0
  117. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/drizzle_tools.py +0 -0
  118. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/epsilon.py +0 -0
  119. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/ier.py +0 -0
  120. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/iwc.py +0 -0
  121. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/lwc.py +0 -0
  122. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/mie_lu_tables.nc +0 -0
  123. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/mwr_tools.py +0 -0
  124. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/products/product_tools.py +0 -0
  125. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy/py.typed +0 -0
  126. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy.egg-info/SOURCES.txt +0 -0
  127. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy.egg-info/dependency_links.txt +0 -0
  128. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy.egg-info/entry_points.txt +0 -0
  129. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy.egg-info/requires.txt +0 -0
  130. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/cloudnetpy.egg-info/top_level.txt +0 -0
  131. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/docs/source/conf.py +0 -0
  132. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/pyproject.toml +0 -0
  133. {cloudnetpy-1.85.4 → cloudnetpy-1.86.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.85.4
3
+ Version: 1.86.0
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -92,10 +92,18 @@ class ClassData:
92
92
  rain_from_disdrometer = self._find_rain_from_disdrometer()
93
93
  ind = ~rain_from_disdrometer.mask
94
94
  is_rain[ind] = rain_from_disdrometer[ind]
95
- mask = ma.getmaskarray(self.tw)
96
- first_valid_ind = np.nonzero(np.all(~mask, axis=0))[0][0]
97
- is_positive_temp = self.tw[:, first_valid_ind] > T0 + 5 # Filter snowfall
98
- return is_rain & is_positive_temp
95
+ # Filter out snowfall:
96
+ if (
97
+ self.data.disdrometer is not None
98
+ and "synop_WaWa" in self.data.disdrometer.data
99
+ ):
100
+ wawa = self.data.disdrometer.data["synop_WaWa"].data
101
+ liquid_rain_only = (wawa >= 57) & (wawa <= 68)
102
+ else:
103
+ mask = ma.getmaskarray(self.tw)
104
+ first_valid_ind = np.nonzero(np.all(~mask, axis=0))[0][0]
105
+ liquid_rain_only = self.tw[:, first_valid_ind] > T0 + 5
106
+ return is_rain & liquid_rain_only
99
107
 
100
108
  def _find_rain_from_radar_echo(self) -> npt.NDArray:
101
109
  first_gate_with_data = np.argmin(self.z.mask.all(axis=0))
@@ -24,14 +24,17 @@ class Disdrometer(DataSource):
24
24
 
25
25
  def interpolate_to_grid(self, time_grid: npt.NDArray) -> None:
26
26
  for key, array in self.data.items():
27
+ method = "nearest" if key == "synop_WaWa" else "linear"
27
28
  self.data[key].data = interpolate_1d(
28
- self.time, array.data, time_grid, max_time=1
29
+ self.time, array.data, time_grid, max_time=1, method=method
29
30
  )
30
31
 
31
32
  def _init_rainfall_rate(self) -> None:
32
- keys = ("rainfall_rate", "n_particles")
33
+ keys = ("rainfall_rate", "n_particles", "synop_WaWa")
33
34
  for key in keys:
34
35
  if key not in self.dataset.variables:
36
+ if key == "synop_WaWa":
37
+ continue
35
38
  msg = f"variable {key} is missing"
36
39
  raise DisdrometerDataError(msg)
37
40
  self.append_data(self.dataset.variables[key][:], key)
@@ -198,7 +198,4 @@ ATTRIBUTES = {
198
198
  comment="Cumulated snow since 00:00 UTC",
199
199
  dimensions=("time",),
200
200
  ),
201
- "synop_WaWa": MetaData(
202
- long_name="Synop code WaWa", units="1", dimensions=("time",)
203
- ),
204
201
  }
@@ -104,6 +104,7 @@ def mrr2nc(
104
104
  if date:
105
105
  mrr.screen_by_date(date)
106
106
  mrr.add_time_and_range()
107
+ mrr.fix_range()
107
108
  mrr.add_site_geolocation()
108
109
  mrr.add_zenith_angle()
109
110
  mrr.add_radar_specific_variables()
@@ -161,6 +162,12 @@ class MrrPro(NcRadar):
161
162
  valid_indices.append(ind)
162
163
  self.screen_time_indices(valid_indices)
163
164
 
165
+ def fix_range(self) -> None:
166
+ # It seems like the "range" variable in MRR-PRO raw files is actually
167
+ # defined above mean sea level -> convert to range above ground level
168
+ range_data = self.data["range"].data
169
+ range_data -= range_data[0]
170
+
164
171
 
165
172
  ATTRIBUTES = {
166
173
  "lwc": MetaData(
@@ -224,4 +224,7 @@ COMMON_ATTRIBUTES = {
224
224
  comment="SNR threshold used in data screening.",
225
225
  dimensions=None,
226
226
  ),
227
+ "synop_WaWa": MetaData(
228
+ long_name="Synop code WaWa", units="1", dimensions=("time",)
229
+ ),
227
230
  }
@@ -19,6 +19,7 @@ class PlotMeta(NamedTuple):
19
19
  moving_average: Whether to plot a moving average in a 1d plot.
20
20
  contour: Whether to plot contours on top of a filled colormap.
21
21
  zero_line: Whether to plot a zero line in a 1d plot.
22
+ mask_zero: Whether to mask zero values in the plot.
22
23
  time_smoothing_duration: The duration of the time smoothing window
23
24
  (in 2d plots) in minutes.
24
25
  """
@@ -30,6 +31,7 @@ class PlotMeta(NamedTuple):
30
31
  moving_average: bool = True
31
32
  contour: bool = False
32
33
  zero_line: bool = False
34
+ mask_zeros: bool = False
33
35
  time_smoothing_duration: int = 0
34
36
 
35
37
 
@@ -150,6 +152,7 @@ ATTRIBUTES = {
150
152
  "rainfall_rate": PlotMeta(
151
153
  cmap="Blues",
152
154
  plot_range=(0, 50 / 3600000),
155
+ mask_zeros=True,
153
156
  )
154
157
  },
155
158
  "mwr": {
@@ -390,6 +393,7 @@ ATTRIBUTES = {
390
393
  "number_concentration": PlotMeta(plot_range=(1e-2, 1e3), log_scale=True),
391
394
  "fall_velocity": PlotMeta(
392
395
  plot_range=(0, 10),
396
+ mask_zeros=True,
393
397
  ),
394
398
  "pressure": PlotMeta(
395
399
  plot_range=(1e4, 1.2e5),
@@ -560,7 +564,7 @@ ATTRIBUTES = {
560
564
  plot_range=(0, 5),
561
565
  ),
562
566
  "radar_rain_atten": PlotMeta(
563
- plot_range=(0, 5),
567
+ plot_range=(0, 15),
564
568
  ),
565
569
  "radar_melting_atten": PlotMeta(
566
570
  plot_range=(0, 5),
@@ -598,6 +602,7 @@ ATTRIBUTES = {
598
602
  cmap="Blues",
599
603
  plot_range=(1e-5, 1e-2),
600
604
  log_scale=True,
605
+ mask_zeros=True,
601
606
  ),
602
607
  "lwc_error": PlotMeta(
603
608
  cmap="RdYlGn_r",
@@ -608,6 +613,7 @@ ATTRIBUTES = {
608
613
  ),
609
614
  "pia": PlotMeta(
610
615
  plot_range=(0, 3),
616
+ mask_zeros=True,
611
617
  ),
612
618
  "lwp": PlotMeta(
613
619
  zero_line=True,
@@ -362,6 +362,10 @@ class Plot:
362
362
  self._is_log = sub_plot.plot_meta.log_scale
363
363
  self._ax = sub_plot.ax
364
364
 
365
+ def _mask_zeros(self) -> None:
366
+ self._data = ma.masked_where(self._data == 0, self._data)
367
+ self._data_orig = ma.masked_where(self._data_orig == 0, self._data_orig)
368
+
365
369
  def _convert_units(self) -> str:
366
370
  multiply, add = "multiply", "add"
367
371
  units_conversion = {
@@ -491,6 +495,8 @@ class Plot:
491
495
  class Plot2D(Plot):
492
496
  def plot(self, figure_data: FigureData) -> None:
493
497
  self._convert_units()
498
+ if self._plot_meta.mask_zeros:
499
+ self._mask_zeros()
494
500
  if figure_data.file_type == "cpr-simulation":
495
501
  min_x, max_x = 0, EARTHCARE_MAX_X
496
502
  else:
@@ -693,6 +699,8 @@ class Plot1D(Plot):
693
699
  msg = "All data is masked"
694
700
  raise PlottingError(msg)
695
701
  units = self._convert_units()
702
+ if self._plot_meta.mask_zeros:
703
+ self._mask_zeros()
696
704
  self._mark_gaps(figure_data)
697
705
  self._ax.plot(
698
706
  figure_data.time_including_gaps,
@@ -823,6 +831,9 @@ class Plot1D(Plot):
823
831
  max_y = max_data + gap
824
832
  if min_y == 0 and max_y == 0:
825
833
  return fallback
834
+ if min_y == max_y:
835
+ gap = np.abs(min_y) * percent_gap
836
+ return min_y - gap, max_y + gap
826
837
  return min_y, max_y
827
838
 
828
839
  def _get_plot_options(self) -> dict:
@@ -11,6 +11,7 @@ from numpy import ma
11
11
 
12
12
  from cloudnetpy import output, utils
13
13
  from cloudnetpy.categorize import atmos_utils
14
+ from cloudnetpy.constants import M_S_TO_MM_H
14
15
  from cloudnetpy.datasource import DataSource
15
16
  from cloudnetpy.metadata import MetaData
16
17
  from cloudnetpy.products.product_tools import CategorizeBits, QualityBits
@@ -189,24 +190,36 @@ def _get_attenuation_classes(data_source: DataSource) -> AttenuationClass:
189
190
  rain_atten = _read_atten("radar_rain_atten")
190
191
  melting_atten = _read_atten("radar_melting_atten")
191
192
 
192
- if (
193
- "lwp" not in data_source.dataset.variables
194
- or data_source.getvar("radar_frequency") < 90
195
- ):
193
+ not_w_band = data_source.getvar("radar_frequency") < 90
194
+
195
+ if "lwp" not in data_source.dataset.variables or not_w_band:
196
196
  lwp = np.zeros(data_source.time.shape)
197
197
  else:
198
198
  lwp_data = data_source.getvar("lwp")
199
199
  lwp = lwp_data.filled(0) if isinstance(lwp_data, ma.MaskedArray) else lwp_data
200
200
 
201
+ if "rainfall_rate" not in data_source.dataset.variables or not_w_band:
202
+ rain_rate = np.zeros(data_source.time.shape)
203
+ else:
204
+ rain_data = data_source.getvar("rainfall_rate") * M_S_TO_MM_H
205
+ rain_rate = (
206
+ rain_data.filled(0) if isinstance(rain_data, ma.MaskedArray) else rain_data
207
+ )
208
+
201
209
  total_atten = liquid_atten + rain_atten + melting_atten
202
210
 
203
211
  threshold_moderate = 10 # dB
204
212
  threshold_severe = 15 # dB
205
213
  threshold_lwp = 1 # kg/m2
214
+ threshold_rain = 3 # mm/h
206
215
 
207
216
  small = total_atten > 0
208
217
  moderate = total_atten >= threshold_moderate
209
- severe = (total_atten > threshold_severe) | (lwp[:, np.newaxis] > threshold_lwp)
218
+ severe = (
219
+ (total_atten > threshold_severe)
220
+ | (lwp[:, np.newaxis] > threshold_lwp)
221
+ | (rain_rate[:, np.newaxis] > threshold_rain)
222
+ )
210
223
 
211
224
  return AttenuationClass(small=small, moderate=moderate, severe=severe)
212
225
 
@@ -420,7 +420,11 @@ def interpolate_2d_nearest(
420
420
 
421
421
 
422
422
  def interpolate_1d(
423
- time: npt.NDArray, y: ma.MaskedArray, time_new: npt.NDArray, max_time: float
423
+ time: npt.NDArray,
424
+ y: ma.MaskedArray,
425
+ time_new: npt.NDArray,
426
+ max_time: float,
427
+ method: str = "linear",
424
428
  ) -> npt.NDArray:
425
429
  """1D linear interpolation preserving the mask.
426
430
 
@@ -430,6 +434,7 @@ def interpolate_1d(
430
434
  time_new: 1D array, new time coordinates.
431
435
  max_time: Maximum allowed gap in minutes. Values outside this gap will
432
436
  be masked.
437
+ method: Interpolation method, 'linear' (default) or 'nearest'.
433
438
  """
434
439
  if np.max(time) > 24 or np.min(time) < 0:
435
440
  msg = "Time vector must be in fraction hours between 0 and 24"
@@ -439,7 +444,7 @@ def interpolate_1d(
439
444
  return ma.masked_all(time_new.shape)
440
445
  time = time[~y.mask]
441
446
  y = y[~y.mask]
442
- fun = interp1d(time, y, fill_value=(y[0], y[-1]), bounds_error=False)
447
+ fun = interp1d(time, y, kind=method, fill_value=(y[0], y[-1]), bounds_error=False)
443
448
  interpolated = ma.array(fun(time_new))
444
449
  bad_idx = get_gap_ind(time, time_new, max_time / 60)
445
450
 
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
- MINOR = 85
3
- PATCH = 4
2
+ MINOR = 86
3
+ PATCH = 0
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.85.4
3
+ Version: 1.86.0
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
File without changes
File without changes
File without changes
File without changes
File without changes