@@ -1070,32 +1070,41 @@ def _grid_dims(self, plot_vars: list[str] | None = None) -> tuple:
10701070 attrs = distnav .attrs ,
10711071 )
10721072
1073- # Horizontal gridded to 3x the number of profiles
1073+ # Horizontal gridded to 3x the number of profiles (or len of distnav if unavailable)
1074+ num_profiles = (
1075+ int (np .nanmax (self .ds ["profile_number" ].to_numpy ()))
1076+ if "profile_number" in self .ds
1077+ else len (distnav )
1078+ )
10741079 idist = np .linspace (
10751080 distnav .to_numpy ()[0 ],
10761081 distnav .to_numpy ()[- 1 ],
1077- int ( 3 * np . nanmax ( self . ds [ "profile_number" ]. to_numpy ())) ,
1082+ 3 * num_profiles ,
10781083 )
10791084 # Vertical gridded to .5 m, rounded down to nearest 10m (minimum 10m)
10801085 # Use only depths where at least one sensor variable has valid data to
10811086 # exclude bogus depth values recorded when no valid sensor data was logged
10821087 # (e.g. from memory corruption events)
1083- depth_values = self .ds .cf ["depth" ].to_numpy ()
1084- time_dim = self .ds .cf ["depth" ].dims [0 ]
1085- nav_vars = {"depth" , "latitude" , "longitude" , "profile_number" }
1086- has_valid_sensor_data = np .zeros (len (depth_values ), dtype = bool )
1087- vars_to_check = [
1088- v for v in (plot_vars or self .ds .data_vars ) if v in self .ds and "pitch" not in v
1089- ]
1090- for var in vars_to_check :
1091- if var not in nav_vars and time_dim in self .ds [var ].dims and self .ds [var ].ndim == 1 :
1092- has_valid_sensor_data |= ~ np .isnan (self .ds [var ].to_numpy ())
1093- depths_with_data = depth_values [has_valid_sensor_data ]
1094- if len (depths_with_data ) > 0 and not np .all (np .isnan (depths_with_data )):
1095- max_depth = max (np .floor (np .nanmax (depths_with_data ) / 10 ) * 10 , 10 )
1088+ if "depth" not in self .ds .cf :
1089+ self .logger .debug ("No depth variable in dataset, using minimal iz" )
1090+ iz = np .arange (0 , 10.5 , 0.5 )
10961091 else :
1097- max_depth = max (np .floor (np .nanmax (depth_values ) / 10 ) * 10 , 10 )
1098- iz = np .arange (0 , max_depth + 0.5 , 0.5 ) # include max_depth so axis reaches it
1092+ depth_values = self .ds .cf ["depth" ].to_numpy ()
1093+ time_dim = self .ds .cf ["depth" ].dims [0 ]
1094+ nav_vars = {"depth" , "latitude" , "longitude" , "profile_number" }
1095+ has_valid_sensor_data = np .zeros (len (depth_values ), dtype = bool )
1096+ vars_to_check = [
1097+ v for v in (plot_vars or self .ds .data_vars ) if v in self .ds and "pitch" not in v
1098+ ]
1099+ for var in vars_to_check :
1100+ if var not in nav_vars and time_dim in self .ds [var ].dims and self .ds [var ].ndim == 1 :
1101+ has_valid_sensor_data |= ~ np .isnan (self .ds [var ].to_numpy ())
1102+ depths_with_data = depth_values [has_valid_sensor_data ]
1103+ if len (depths_with_data ) > 0 and not np .all (np .isnan (depths_with_data )):
1104+ max_depth = max (np .floor (np .nanmax (depths_with_data ) / 10 ) * 10 , 10 )
1105+ else :
1106+ max_depth = max (np .floor (np .nanmax (depth_values ) / 10 ) * 10 , 10 )
1107+ iz = np .arange (0 , max_depth + 0.5 , 0.5 ) # include max_depth so axis reaches it
10991108
11001109 return idist , iz , distnav
11011110
@@ -1166,6 +1175,9 @@ def _profile_bottoms(
11661175 """Return array of distance and depth points defining the bottom of the profiles
11671176 where there is no data"""
11681177
1178+ if "depth" not in self .ds .cf :
1179+ self .logger .debug ("No depth variable in dataset, skipping profile bottoms" )
1180+ return None
11691181 # Create a DataArray of depths indexed by distance
11701182 depth_dist = xr .DataArray (
11711183 self .ds .cf ["depth" ].to_numpy (),
@@ -1464,7 +1476,13 @@ def _section_overlays(self, distnav: xr.DataArray) -> tuple:
14641476 return profile_bottoms , bottom_depths
14651477
14661478 def _cumulative_profile_numbers (self ) -> np .ndarray :
1467- """Return profile_number array that increments monotonically across log files."""
1479+ """Return profile_number array that increments monotonically across log files.
1480+
1481+ Falls back to a simple index array when profile_number is absent.
1482+ """
1483+ if "profile_number" not in self .ds :
1484+ self .logger .debug ("profile_number not in dataset, using index array for track color" )
1485+ return np .arange (len (self .ds ["time" ]), dtype = float )
14681486 profile_numbers = self .ds ["profile_number" ].to_numpy ()
14691487 result = profile_numbers .copy ().astype (float )
14701488 offset = 0
@@ -2066,14 +2084,19 @@ def _plot_var_scatter( # noqa: C901, PLR0912, PLR0913, PLR0915
20662084 # filtered in _grid_dims (e.g. sparse GPS in realtime SBD data).
20672085 # Align depth and var arrays to distnav's time subset.
20682086 n_ds = len (self .ds .cf ["time" ])
2087+ has_depth = "depth" in self .ds .cf
20692088 if len (distnav ) != n_ds :
20702089 ds_time = self .ds .cf ["time" ].to_numpy ()
20712090 nav_idx = np .searchsorted (ds_time , distnav .coords ["time" ].to_numpy ())
20722091 nav_idx = nav_idx [nav_idx < n_ds ]
2073- depth_for_scatter = self .ds .cf ["depth" ].to_numpy ()[nav_idx ]
2092+ depth_for_scatter = (
2093+ self .ds .cf ["depth" ].to_numpy ()[nav_idx ] if has_depth else np .zeros (len (nav_idx ))
2094+ )
20742095 var_for_scatter = var_to_plot [nav_idx ]
20752096 else :
2076- depth_for_scatter = self .ds .cf ["depth" ].to_numpy ()
2097+ depth_for_scatter = (
2098+ self .ds .cf ["depth" ].to_numpy () if has_depth else np .zeros (len (var_to_plot ))
2099+ )
20772100 var_for_scatter = var_to_plot
20782101
20792102 # Create scatter plot with actual data points
0 commit comments