cloudnetpy 1.82.2__tar.gz → 1.83.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.82.2/cloudnetpy.egg-info → cloudnetpy-1.83.0}/PKG-INFO +1 -1
  2. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/attenuations/melting_attenuation.py +7 -6
  3. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/datasource.py +2 -2
  4. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/nc_radar.py +2 -2
  5. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/products/observation_products.py +1 -1
  6. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/plotting/plot_meta.py +24 -0
  7. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/plotting/plotting.py +70 -7
  8. cloudnetpy-1.83.0/cloudnetpy/products/classification.py +464 -0
  9. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/version.py +2 -2
  10. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0/cloudnetpy.egg-info}/PKG-INFO +1 -1
  11. cloudnetpy-1.82.2/cloudnetpy/products/classification.py +0 -228
  12. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/LICENSE +0 -0
  13. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/MANIFEST.in +0 -0
  14. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/README.md +0 -0
  15. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/__init__.py +0 -0
  16. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/__init__.py +0 -0
  17. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/atmos_utils.py +0 -0
  18. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/attenuation.py +0 -0
  19. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/attenuations/__init__.py +0 -0
  20. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/attenuations/gas_attenuation.py +0 -0
  21. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/attenuations/liquid_attenuation.py +0 -0
  22. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/attenuations/rain_attenuation.py +0 -0
  23. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/categorize.py +0 -0
  24. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/classify.py +0 -0
  25. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/containers.py +0 -0
  26. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/disdrometer.py +0 -0
  27. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/droplet.py +0 -0
  28. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/falling.py +0 -0
  29. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/freezing.py +0 -0
  30. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/insects.py +0 -0
  31. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/itu.py +0 -0
  32. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/lidar.py +0 -0
  33. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/melting.py +0 -0
  34. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/model.py +0 -0
  35. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/mwr.py +0 -0
  36. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/categorize/radar.py +0 -0
  37. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/cli.py +0 -0
  38. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/cloudnetarray.py +0 -0
  39. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/concat_lib.py +0 -0
  40. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/constants.py +0 -0
  41. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/exceptions.py +0 -0
  42. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/__init__.py +0 -0
  43. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/basta.py +0 -0
  44. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/bowtie.py +0 -0
  45. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/ceilo.py +0 -0
  46. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/ceilometer.py +0 -0
  47. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/cl61d.py +0 -0
  48. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/cloudnet_instrument.py +0 -0
  49. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/copernicus.py +0 -0
  50. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/disdrometer/__init__.py +0 -0
  51. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/disdrometer/common.py +0 -0
  52. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/disdrometer/parsivel.py +0 -0
  53. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/disdrometer/thies.py +0 -0
  54. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/fd12p.py +0 -0
  55. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/galileo.py +0 -0
  56. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/hatpro.py +0 -0
  57. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/instruments.py +0 -0
  58. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/lufft.py +0 -0
  59. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/mira.py +0 -0
  60. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/mrr.py +0 -0
  61. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/nc_lidar.py +0 -0
  62. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/pollyxt.py +0 -0
  63. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/radiometrics.py +0 -0
  64. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/rain_e_h3.py +0 -0
  65. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/rpg.py +0 -0
  66. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/rpg_reader.py +0 -0
  67. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/toa5.py +0 -0
  68. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/vaisala.py +0 -0
  69. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/instruments/weather_station.py +0 -0
  70. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/metadata.py +0 -0
  71. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/__init__.py +0 -0
  72. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/file_handler.py +0 -0
  73. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/metadata.py +0 -0
  74. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/model_metadata.py +0 -0
  75. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/plotting/__init__.py +0 -0
  76. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/plotting/plot_meta.py +0 -0
  77. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/plotting/plot_tools.py +0 -0
  78. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/plotting/plotting.py +0 -0
  79. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/products/__init__.py +0 -0
  80. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/products/advance_methods.py +0 -0
  81. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/products/grid_methods.py +0 -0
  82. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/products/model_products.py +0 -0
  83. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/products/product_resampling.py +0 -0
  84. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/products/tools.py +0 -0
  85. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/statistics/__init__.py +0 -0
  86. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/statistics/statistical_methods.py +0 -0
  87. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/__init__.py +0 -0
  88. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/__init__.py +0 -0
  89. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/conftest.py +0 -0
  90. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/__init__.py +0 -0
  91. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/main.py +0 -0
  92. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/process_cf/tests.py +0 -0
  93. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/__init__.py +0 -0
  94. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/main.py +0 -0
  95. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/process_iwc/tests.py +0 -0
  96. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/__init__.py +0 -0
  97. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/main.py +0 -0
  98. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py +0 -0
  99. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/__init__.py +0 -0
  100. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/conftest.py +0 -0
  101. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py +0 -0
  102. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +0 -0
  103. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/test_model_products.py +0 -0
  104. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +0 -0
  105. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py +0 -0
  106. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/test_plotting.py +0 -0
  107. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py +0 -0
  108. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/tests/unit/test_tools.py +0 -0
  109. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/model_evaluation/utils.py +0 -0
  110. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/output.py +0 -0
  111. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/plotting/__init__.py +0 -0
  112. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/__init__.py +0 -0
  113. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/der.py +0 -0
  114. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/drizzle.py +0 -0
  115. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/drizzle_error.py +0 -0
  116. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/drizzle_tools.py +0 -0
  117. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/epsilon.py +0 -0
  118. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/ier.py +0 -0
  119. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/iwc.py +0 -0
  120. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/lwc.py +0 -0
  121. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/mie_lu_tables.nc +0 -0
  122. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/mwr_tools.py +0 -0
  123. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/products/product_tools.py +0 -0
  124. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/py.typed +0 -0
  125. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy/utils.py +0 -0
  126. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy.egg-info/SOURCES.txt +0 -0
  127. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy.egg-info/dependency_links.txt +0 -0
  128. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy.egg-info/entry_points.txt +0 -0
  129. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy.egg-info/requires.txt +0 -0
  130. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/cloudnetpy.egg-info/top_level.txt +0 -0
  131. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/docs/source/conf.py +0 -0
  132. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/pyproject.toml +0 -0
  133. {cloudnetpy-1.82.2 → cloudnetpy-1.83.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.82.2
3
+ Version: 1.83.0
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -13,14 +13,14 @@ def calc_melting_attenuation(
13
13
  data: Observations, classification: ClassificationResult
14
14
  ) -> Attenuation:
15
15
  shape = classification.category_bits.melting.shape
16
- is_rain = classification.is_rain
16
+ no_rain = classification.is_rain == 0
17
17
 
18
18
  affected_region = classification.category_bits.freezing.copy()
19
19
 
20
20
  if data.disdrometer is None:
21
- affected_region[~is_rain, :] = False
22
21
  above_melting = utils.ffill(classification.category_bits.melting)
23
22
  affected_region[~above_melting] = False
23
+ affected_region[no_rain, :] = False
24
24
  return Attenuation(
25
25
  amount=ma.masked_all(shape),
26
26
  error=ma.masked_all(shape),
@@ -29,22 +29,23 @@ def calc_melting_attenuation(
29
29
  )
30
30
 
31
31
  rainfall_rate = data.disdrometer.data["rainfall_rate"][:]
32
- rainfall_rate[is_rain == 0] = ma.masked
32
+ rainfall_rate = ma.where(no_rain, 0, rainfall_rate)
33
+
33
34
  frequency = data.radar.radar_frequency
34
35
 
35
36
  attenuation_array = _calc_melting_attenuation(rainfall_rate, frequency)
36
37
 
37
38
  amount = affected_region * utils.transpose(attenuation_array)
38
39
 
39
- affected_region[amount == 0] = False
40
+ no_attenuation = amount == 0
40
41
 
41
- amount[amount == 0] = ma.masked
42
+ affected_region[no_attenuation] = False
43
+ amount[no_attenuation] = ma.masked
42
44
 
43
45
  band = utils.get_wl_band(data.radar.radar_frequency)
44
46
  error_factor = {"Ka": 0.2, "W": 0.1}[band]
45
47
 
46
48
  error = amount * error_factor
47
- error[~affected_region] = ma.masked
48
49
 
49
50
  return Attenuation(
50
51
  amount=amount,
@@ -74,14 +74,14 @@ class DataSource:
74
74
  ndarray: The actual data.
75
75
 
76
76
  Raises:
77
- RuntimeError: The variable is not found.
77
+ KeyError: The variable is not found.
78
78
 
79
79
  """
80
80
  for arg in args:
81
81
  if arg in self.dataset.variables:
82
82
  return self.dataset.variables[arg][:]
83
83
  msg = f"Missing variable {args[0]} in the input file."
84
- raise RuntimeError(msg)
84
+ raise KeyError(msg)
85
85
 
86
86
  def append_data(
87
87
  self,
@@ -41,7 +41,7 @@ class NcRadar(DataSource, CloudnetInstrument):
41
41
  name = keymap[key]
42
42
  try:
43
43
  array = self.getvar(key)
44
- except RuntimeError:
44
+ except KeyError:
45
45
  logging.warning("Can not find variable %s from the input file", key)
46
46
  continue
47
47
  array = np.array(array) if utils.isscalar(array) else array
@@ -158,7 +158,7 @@ class NcRadar(DataSource, CloudnetInstrument):
158
158
  self.data[key] = CloudnetArray(np.median(np.array(data)), key)
159
159
  if "NyquistVelocity" in self.data:
160
160
  del self.data["NyquistVelocity"]
161
- except RuntimeError:
161
+ except KeyError:
162
162
  logging.warning("Unable to find nyquist_velocity")
163
163
 
164
164
  def test_if_all_masked(self) -> None:
@@ -104,7 +104,7 @@ class ObservationManager(DataSource):
104
104
  """Check if rainrate in file."""
105
105
  try:
106
106
  self.getvar("rainrate")
107
- except RuntimeError:
107
+ except KeyError:
108
108
  return False
109
109
  return True
110
110
 
@@ -90,6 +90,12 @@ _CLABEL = {
90
90
  ("Clutter", _COLORS["shockred"]),
91
91
  ("_Lidar molecular scattering", _COLORS["pink"]),
92
92
  ),
93
+ "signal_source_status": (
94
+ ("Clear sky", _COLORS["white"]),
95
+ ("Radar & lidar", _COLORS["green"]),
96
+ ("Radar only", _COLORS["lightsteel"]),
97
+ ("Lidar only", _COLORS["yellow"]),
98
+ ),
93
99
  "ice_retrieval_status": (
94
100
  ("_No ice", _COLORS["white"]),
95
101
  ("Reliable", _COLORS["green"]),
@@ -124,6 +130,15 @@ _CLABEL = {
124
130
  ("Unfeasible", _COLORS["red"]),
125
131
  ("Surrounding ice", _COLORS["lightsteel"]),
126
132
  ),
133
+ "radar_attenuation_status": (
134
+ ("_Clear sky", _COLORS["white"]),
135
+ ("Negligible", _COLORS["green"]),
136
+ ("Minor", _COLORS["lightgreen"]),
137
+ ("Moderate", _COLORS["yellow"]),
138
+ ("Severe", _COLORS["red"]),
139
+ ("Unquantifiable", _COLORS["seaweed_roll"]),
140
+ ("Undetected", _COLORS["skyblue"]),
141
+ ),
127
142
  }
128
143
 
129
144
 
@@ -213,6 +228,9 @@ ATTRIBUTES = {
213
228
  ),
214
229
  },
215
230
  "fallback": {
231
+ "cloud_top_height_agl": PlotMeta(
232
+ moving_average=False,
233
+ ),
216
234
  "nubf": PlotMeta(plot_range=(0, 5)),
217
235
  "ze_sat": PlotMeta(
218
236
  plot_range=(-40, 15),
@@ -281,6 +299,9 @@ ATTRIBUTES = {
281
299
  "der_retrieval_status": PlotMeta(
282
300
  clabel=_CLABEL["der_retrieval_status"],
283
301
  ),
302
+ "radar_attenuation_status": PlotMeta(
303
+ clabel=_CLABEL["radar_attenuation_status"],
304
+ ),
284
305
  "mu": PlotMeta(
285
306
  plot_range=(0, 10),
286
307
  ),
@@ -554,6 +575,9 @@ ATTRIBUTES = {
554
575
  "detection_status": PlotMeta(
555
576
  clabel=_CLABEL["detection_status"],
556
577
  ),
578
+ "signal_source_status": PlotMeta(
579
+ clabel=_CLABEL["signal_source_status"],
580
+ ),
557
581
  "iwc": PlotMeta(
558
582
  plot_range=(1e-7, 1e-3),
559
583
  log_scale=True,
@@ -28,6 +28,7 @@ from cloudnetpy.categorize.atmos_utils import calc_altitude
28
28
  from cloudnetpy.exceptions import PlottingError
29
29
  from cloudnetpy.instruments.ceilometer import calc_sigma_units
30
30
  from cloudnetpy.plotting.plot_meta import ATTRIBUTES, PlotMeta
31
+ from cloudnetpy.products.classification import TopStatus
31
32
 
32
33
  EARTHCARE_MAX_X = 517.84
33
34
 
@@ -375,6 +376,7 @@ class Plot:
375
376
  "air_temperature": (add, -273.15, "\u00b0C"),
376
377
  "r_accum_RT": (multiply, 1000, "mm"),
377
378
  "r_accum_NRT": (multiply, 1000, "mm"),
379
+ "cloud_top_height_agl": (multiply, con.M_TO_KM, "Height (km AGL)"),
378
380
  }
379
381
  conversion_method, conversion, units = units_conversion.get(
380
382
  self.sub_plot.variable.name, (multiply, 1, None)
@@ -467,6 +469,12 @@ class Plot:
467
469
  self._data = data_new
468
470
  figure_data.time_including_gaps = time_new
469
471
 
472
+ def _read_cloud_top_flags(
473
+ self, figure_data: FigureData, flag_value: int | tuple[int, ...]
474
+ ) -> ndarray:
475
+ status = figure_data.file.variables["cloud_top_height_status"][:]
476
+ return np.isin(status, flag_value)
477
+
470
478
  def _read_flagged_data(self, figure_data: FigureData) -> ndarray:
471
479
  flag_names = [
472
480
  f"{self.sub_plot.variable.name}_quality_flag",
@@ -503,6 +511,32 @@ class Plot2D(Plot):
503
511
  if figure_data.is_mwrpy_product():
504
512
  self._fill_flagged_data(figure_data)
505
513
 
514
+ if figure_data.variables[0].name == "signal_source_status":
515
+ self._indicate_rainy_profiles(figure_data)
516
+
517
+ def _indicate_rainy_profiles(self, figure_data: FigureData) -> None:
518
+ if "rain_detected" not in figure_data.file.variables:
519
+ return
520
+ rain = figure_data.file.variables["rain_detected"][:]
521
+ is_rain: ma.MaskedArray = ma.masked_array(np.zeros_like(rain), mask=(rain == 0))
522
+ if is_rain.mask.all():
523
+ return
524
+ self._ax.plot(
525
+ figure_data.time,
526
+ is_rain,
527
+ color="red",
528
+ marker="|",
529
+ linestyle="None",
530
+ markersize=10,
531
+ zorder=-999,
532
+ label="Rain",
533
+ )
534
+ self._ax.legend(
535
+ markerscale=0.75,
536
+ numpoints=1,
537
+ frameon=False,
538
+ )
539
+
506
540
  def _fill_flagged_data(self, figure_data: FigureData) -> None:
507
541
  flags = self._read_flagged_data(figure_data)
508
542
  batches = find_batches_of_ones(flags)
@@ -672,11 +706,35 @@ class Plot1D(Plot):
672
706
  self.sub_plot.set_yax(ylabel=units, y_limits=self._get_y_limits())
673
707
  pos = self._ax.get_position()
674
708
  self._ax.set_position((pos.x0, pos.y0, pos.width * 0.965, pos.height))
709
+ self._plot_flags(figure_data)
710
+
711
+ def _plot_flags(self, figure_data: FigureData) -> None:
675
712
  if figure_data.is_mwrpy_product():
676
713
  flags = self._read_flagged_data(figure_data)
677
714
  if np.any(flags):
678
715
  self._plot_flag_data(figure_data.time[flags], self._data_orig[flags])
679
716
  self._add_legend()
717
+ if (
718
+ figure_data.variables[0].name == "cloud_top_height_agl"
719
+ and "cloud_top_height_status" in figure_data.file.variables
720
+ ):
721
+ legend: tuple = ()
722
+ flag_value = (TopStatus.MODERATE_ATT, TopStatus.UNCORR_ATT)
723
+ flags = self._read_cloud_top_flags(figure_data, flag_value)
724
+ if np.any(flags):
725
+ self._plot_flag_data(
726
+ figure_data.time[flags], self._data_orig[flags], color="orange"
727
+ )
728
+ legend += ("Suspicious",)
729
+ flag_value = (TopStatus.SEVERE_ATT, TopStatus.ABOVE_RANGE)
730
+ flags = self._read_cloud_top_flags(figure_data, flag_value)
731
+ if np.any(flags):
732
+ self._plot_flag_data(
733
+ figure_data.time[flags], self._data_orig[flags], color="red"
734
+ )
735
+ legend += ("Unreliable",)
736
+ if legend:
737
+ self._add_legend(name=legend)
680
738
 
681
739
  def plot_tb(self, figure_data: FigureData, freq_ind: int) -> None:
682
740
  if len(self._data.shape) != 2 or freq_ind >= self._data.shape[1]:
@@ -728,20 +786,22 @@ class Plot1D(Plot):
728
786
  },
729
787
  )
730
788
 
731
- def _plot_flag_data(self, time: ndarray, values: ndarray) -> None:
789
+ def _plot_flag_data(
790
+ self, time: ndarray, values: ndarray, color: str = "salmon"
791
+ ) -> None:
732
792
  self._ax.plot(
733
793
  time,
734
794
  values,
735
- color="salmon",
795
+ color=color,
736
796
  marker=".",
737
797
  lw=0,
738
798
  markersize=3,
739
799
  zorder=_get_zorder("flags"),
740
800
  )
741
801
 
742
- def _add_legend(self) -> None:
802
+ def _add_legend(self, name: str | tuple = ("Flagged data",)) -> None:
743
803
  self._ax.legend(
744
- ["Flagged data"],
804
+ name,
745
805
  markerscale=3,
746
806
  numpoints=1,
747
807
  frameon=False,
@@ -772,7 +832,10 @@ class Plot1D(Plot):
772
832
  custom_options = {
773
833
  "tb": {
774
834
  "color": "lightblue",
775
- }
835
+ },
836
+ "cloud_top_height_agl": {
837
+ "color": "steelblue",
838
+ },
776
839
  }
777
840
 
778
841
  variable_name = self.sub_plot.variable.name
@@ -807,8 +870,8 @@ class Plot1D(Plot):
807
870
  data = np.stack([wind_speed, data], axis=1)
808
871
 
809
872
  block_ind = np.where(np.diff(is_invalid))[0] + 1
810
- valid_time_blocks = np.split(time, block_ind)[is_invalid[0] :: 2]
811
- valid_data_blocks = np.split(data, block_ind)[is_invalid[0] :: 2]
873
+ valid_time_blocks = np.split(time, block_ind)[int(is_invalid[0]) :: 2]
874
+ valid_data_blocks = np.split(data, block_ind)[int(is_invalid[0]) :: 2]
812
875
 
813
876
  for time1, data1 in zip(valid_time_blocks, valid_data_blocks, strict=False):
814
877
  if is_wind_direction: