@@ -135,8 +135,7 @@ def insert_nan_where(self, condition):
135135
136136 nd [varname ] = da .astype (var .dtype )
137137
138- nd = nd .drop_vars (
139- (self .obs_dim , self .trajectory_dim )) # Remove coordinates
138+ nd = nd .assign_coords ({self .obs_dim : np .arange (max_obs )}) # New obs index 1..N
140139
141140 return nd
142141
@@ -164,11 +163,14 @@ def drop_where(self, condition):
164163
165164 # Ensure all trajectories have equal length by padding with NaN at the end
166165 trajs = [
167- t .pad (pad_width = {self .obs_dim : (0 , newlen - t .sizes [self .obs_dim ])})
166+ t .pad (pad_width = {self .obs_dim : (0 , newlen - t .sizes [self .obs_dim ])}).
167+ assign_coords ({self .obs_dim : np .arange (newlen )}) # New obs index 1..N
168168 for t in trajs
169169 ]
170170
171- return xr .concat (trajs , dim = self .trajectory_dim )
171+ ds = xr .concat (trajs , dim = self .trajectory_dim , join = 'exact' )
172+
173+ return ds
172174
173175 @__require_obs_dim__
174176 def condense_obs (self ) -> xr .Dataset :
@@ -220,8 +222,7 @@ def condense_obs(self) -> xr.Dataset:
220222 ds = ds .isel ({self .obs_dim : slice (0 , maxN )})
221223
222224 # Write new observation coordinate.
223- obs = np .arange (0 , maxN )
224- ds = ds .assign_coords ({self .obs_dim : obs })
225+ ds = ds .assign_coords ({self .obs_dim : np .arange (0 , maxN )})
225226
226227 return ds
227228
@@ -246,11 +247,12 @@ def append(self, da, obs_dims=None):
246247
247248 def sel (self , * args , ** kwargs ):
248249 return self .ds .groupby (self .trajectory_dim ).map (
249- lambda d : ensure_time_dim (d .traj .to_1d ().sel (* args , ** kwargs ), self
250- .time_varname ).traj .to_2d (self .obs_dim ))
250+ lambda d : ensure_time_dim (d .traj .to_1d ().traj .sel (* args , ** kwargs ), self .time_varname ).traj .to_2d (self .obs_dim ))
251251
252252 def seltime (self , t0 = None , t1 = None ):
253- return self .sel ({self .time_varname : slice (t0 , t1 )})
253+ # Using TrajAn sel method that allows NaN
254+ return self .ds .groupby (self .trajectory_dim ).map (
255+ lambda d : ensure_time_dim (d .traj .to_1d ().traj .seltime (t0 , t1 ), self .time_varname ).traj .to_2d (self .obs_dim ))
254256
255257 @__require_obs_dim__
256258 def iseltime (self , i ):
@@ -275,18 +277,24 @@ def to_1d(self):
275277 )
276278 else :
277279 ds = self .ds .copy ()
278- ds = ds .dropna (self .obs_dim , how = 'all' )
280+
281+ # Do not remove NaN's since these now have meaning
282+ #ds = ds.dropna(self.obs_dim, how='all')
283+
284+ # For 1D objects, we rename obs-dimension to name of time variable
285+ # so that time becomes a coordinate variable,
286+ # i.e. typically: time(traj, obs) -> time(time)
279287 ds = ds .assign_coords ({self .obs_dim : ds [self .time_varname ]})
280- ds = ds .drop_vars (self .time_varname ).rename (
281- { self .obs_dim : self .time_varname } )
282-
283- ds [ self . time_varname ] = ds [ self . time_varname ]. squeeze (
284- self .trajectory_dim )
285- ds = ds . loc [{ self . time_varname : ~ pd . isna (ds [self .time_varname ])}]
286- _ , ui = np . unique ( ds [ self .time_varname ], return_index = True )
287- ds = ds . isel ({ self . time_varname : ui })
288- ds = ds . assign_coords (
289- {self .trajectory_dim : ds [self .trajectory_dim ]})
288+ ds = ds .drop_vars (self .time_varname ).rename ({ self . obs_dim : self . time_varname })
289+ ds [ self .time_varname ] = ds [ self .time_varname ]. squeeze ( self . trajectory_dim )
290+
291+ # Do not remove NaN's since these now have meaning
292+ #ds = ds.loc[{self.time_varname: ~pd.isna(ds[ self.time_varname])}]
293+ #_, ui = np.unique (ds[self.time_varname], return_index=True)
294+ #ds = ds.isel({ self.time_varname: ui} )
295+
296+ # Keep trajectory dimension, although always length 1 for 1D objects
297+ ds = ds . assign_coords ( {self .trajectory_dim : ds [self .trajectory_dim ]})
290298
291299 return ds
292300
0 commit comments