@@ -113,69 +113,65 @@ def _handle_nan(data):
113113
114114
115115def _create_dataset (data ):
116- """Creates an xarray dataset from dictionary created from binary
116+ """
117+ Creates an xarray dataset from dictionary created from binary
117118 readers.
118119 Direction 'dir' coordinates are set in `set_coords`
119120 """
120- ds = xr .Dataset ()
121- tag = ["_avg" , "_b5" , "_echo" , "_bt" , "_gps" , "_altraw" , "_sl" ]
122121
123- FoR = {}
124- try :
125- beams = data ["attrs" ]["n_beams" ]
126- except :
122+ tag = ["_avg" , "_b5" , "_echo" , "_bt" , "_gps" , "_altraw" , "_altraw_avg" , "_sl" ]
123+
124+ ds_dict = {}
125+ for key in data ["coords" ]:
126+ ds_dict [key ] = {"dims" : (key ), "data" : data ["coords" ][key ]}
127+
128+ # Set various coordinate frames
129+ if "n_beams_avg" in data ["attrs" ]:
127130 beams = data ["attrs" ]["n_beams_avg" ]
131+ else :
132+ beams = data ["attrs" ]["n_beams" ]
128133 n_beams = max (min (beams , 4 ), 3 )
129134 beams = np .arange (1 , n_beams + 1 , dtype = np .int32 )
130- FoR ["beam" ] = xr .DataArray (
131- beams ,
132- dims = ["beam" ],
133- name = "beam" ,
134- attrs = {"units" : "1" , "long_name" : "Beam Reference Frame" },
135- )
136- FoR ["dir" ] = xr .DataArray (
137- beams ,
138- dims = ["dir" ],
139- name = "dir" ,
140- attrs = {"units" : "1" , "long_name" : "Reference Frame" },
141- )
142135
136+ ds_dict ["beam" ] = {"dims" : ("beam" ), "data" : beams }
137+ ds_dict ["dir" ] = {"dims" : ("dir" ), "data" : beams }
138+ data ["units" ].update ({"beam" : "1" , "dir" : "1" })
139+ data ["long_name" ].update ({"beam" : "Beam Reference Frame" , "dir" : "Reference Frame" })
140+
141+ # Iterate through data variables and add them to new dictionary
143142 for key in data ["data_vars" ]:
144143 # orientation matrices
145144 if "mat" in key :
146145 if "inst" in key : # beam2inst & inst2head orientation matrices
147- ds [key ] = xr .DataArray (
148- data ["data_vars" ][key ],
149- coords = {"x1" : beams , "x2" : beams },
150- dims = ["x1" , "x2" ],
151- attrs = {"units" : "1" , "long_name" : "Rotation Matrix" },
152- )
146+ if "x1" not in ds_dict :
147+ ds_dict ["x1" ] = {"dims" : ("x1" ), "data" : beams }
148+ ds_dict ["x2" ] = {"dims" : ("x2" ), "data" : beams }
149+
150+ ds_dict [key ] = {"dims" : ("x1" , "x2" ), "data" : data ["data_vars" ][key ]}
151+ data ["units" ].update ({key : "1" })
152+ data ["long_name" ].update ({key : "Rotation Matrix" })
153+
153154 elif "orientmat" in key : # earth2inst orientation matrix
154155 if any (val in key for val in tag ):
155156 tg = "_" + key .rsplit ("_" )[- 1 ]
156157 else :
157158 tg = ""
158- earth = xr .DataArray (
159- ["E" , "N" , "U" ],
160- dims = ["earth" ],
161- name = "earth" ,
162- attrs = {"units" : "1" , "long_name" : "Earth Reference Frame" },
163- )
164- inst = xr .DataArray (
165- ["X" , "Y" , "Z" ],
166- dims = ["inst" ],
167- name = "inst" ,
168- attrs = {"units" : "1" , "long_name" : "Instrument Reference Frame" },
159+
160+ ds_dict ["earth" ] = {"dims" : ("earth" ), "data" : ["E" , "N" , "U" ]}
161+ ds_dict ["inst" ] = {"dims" : ("inst" ), "data" : ["X" , "Y" , "Z" ]}
162+ ds_dict [key ] = {
163+ "dims" : ("earth" , "inst" , "time" + tg ),
164+ "data" : data ["data_vars" ][key ],
165+ }
166+ data ["units" ].update (
167+ {"earth" : "1" , "inst" : "1" , key : data ["units" ]["orientmat" ]}
169168 )
170- time = data ["coords" ]["time" + tg ]
171- ds [key ] = xr .DataArray (
172- data ["data_vars" ][key ],
173- coords = {"earth" : earth , "inst" : inst , "time" + tg : time },
174- dims = ["earth" , "inst" , "time" + tg ],
175- attrs = {
176- "units" : data ["units" ]["orientmat" ],
177- "long_name" : data ["long_name" ]["orientmat" ],
178- },
169+ data ["long_name" ].update (
170+ {
171+ "earth" : "Earth Reference Frame" ,
172+ "inst" : "Instrument Reference Frame" ,
173+ key : data ["long_name" ]["orientmat" ],
174+ }
179175 )
180176
181177 # quaternion units never change
@@ -184,67 +180,43 @@ def _create_dataset(data):
184180 tg = "_" + key .rsplit ("_" )[- 1 ]
185181 else :
186182 tg = ""
187- q = xr .DataArray (
188- ["w" , "x" , "y" , "z" ],
189- dims = ["q" ],
190- name = "q" ,
191- attrs = {"units" : "1" , "long_name" : "Quaternion Vector Components" },
192- )
193- time = data ["coords" ]["time" + tg ]
194- ds [key ] = xr .DataArray (
195- data ["data_vars" ][key ],
196- coords = {"q" : q , "time" + tg : time },
197- dims = ["q" , "time" + tg ],
198- attrs = {
199- "units" : data ["units" ]["quaternions" ],
200- "long_name" : data ["long_name" ]["quaternions" ],
201- },
202- )
203- else :
204- # Assign each variable to a dataArray
205- ds [key ] = xr .DataArray (data ["data_vars" ][key ])
206- # Assign metadata to each dataArray
207- for md in ["units" , "long_name" , "standard_name" ]:
208- if key in data [md ]:
209- ds [key ].attrs [md ] = data [md ][key ]
210- try : # make sure ones with tags get units
211- tg = "_" + key .rsplit ("_" )[- 1 ]
212- if any (val in key for val in tag ):
213- ds [key ].attrs [md ] = data [md ][key [: - len (tg )]]
214- except :
215- pass
216183
217- # Fill in dimensions and coordinates for each dataArray
184+ if "q" not in ds_dict :
185+ ds_dict ["q" ] = {"dims" : ("q" ), "data" : ["w" , "x" , "y" , "z" ]}
186+ data ["units" ].update ({"q" : "1" })
187+ data ["long_name" ].update ({"q" : "Quaternion Vector Components" })
188+
189+ ds_dict [key ] = {"dims" : ("q" , "time" + tg ), "data" : data ["data_vars" ][key ]}
190+ data ["units" ].update ({key : data ["units" ]["quaternions" ]})
191+ data ["long_name" ].update ({key : data ["long_name" ]["quaternions" ]})
192+
193+ else :
218194 shp = data ["data_vars" ][key ].shape
219- l = len (shp )
220- if l == 1 : # 1D variables
221- if any (val in key for val in tag ):
195+ if len (shp ) == 1 : # 1D variables
196+ if "_altraw_avg" in key :
197+ tg = "_altraw_avg"
198+ elif any (val in key for val in tag ):
222199 tg = "_" + key .rsplit ("_" )[- 1 ]
223200 else :
224201 tg = ""
225- ds [key ] = ds [key ].rename ({"dim_0" : "time" + tg })
226- ds [key ] = ds [key ].assign_coords (
227- {"time" + tg : data ["coords" ]["time" + tg ]}
228- )
202+ ds_dict [key ] = {"dims" : ("time" + tg ), "data" : data ["data_vars" ][key ]}
229203
230- elif l == 2 : # 2D variables
204+ elif len ( shp ) == 2 : # 2D variables
231205 if key == "echo" :
232- ds [key ] = ds [key ].rename (
233- {"dim_0" : "range_echo" , "dim_1" : "time_echo" }
234- )
235- ds [key ] = ds [key ].assign_coords (
236- {
237- "range_echo" : data ["coords" ]["range_echo" ],
238- "time_echo" : data ["coords" ]["time_echo" ],
239- }
240- )
241- elif key == "samp_altraw" : # raw altimeter samples
242- ds [key ] = ds [key ].rename (
243- {"dim_0" : "n_altraw" , "dim_1" : "time_altraw" }
244- )
245- ds [key ] = ds [key ].assign_coords (
246- {"time_altraw" : data ["coords" ]["time_altraw" ]}
247- )
206+ ds_dict [key ] = {
207+ "dims" : ("range_echo" , "time_echo" ),
208+ "data" : data ["data_vars" ][key ],
209+ }
210+ elif key == "samp_altraw" :
211+ ds_dict [key ] = {
212+ "dims" : ("n_altraw" , "time_altraw" ),
213+ "data" : data ["data_vars" ][key ],
214+ }
215+ elif key == "samp_altraw_avg" :
216+ ds_dict [key ] = {
217+ "dims" : ("n_altraw_avg" , "time_altraw_avg" ),
218+ "data" : data ["data_vars" ][key ],
219+ }
248220
249221 # ADV/ADCP instrument vector data, bottom tracking
250222 elif shp [0 ] == n_beams and not any (val in key for val in tag [:3 ]):
@@ -259,31 +231,36 @@ def _create_dataset(data):
259231 dim0 = "beam"
260232 else :
261233 dim0 = "dir"
262- ds [key ] = ds [key ].rename ({"dim_0" : dim0 , "dim_1" : "time" + tg })
263- ds [key ] = ds [key ].assign_coords (
264- {dim0 : FoR [dim0 ], "time" + tg : data ["coords" ]["time" + tg ]}
265- )
234+ ds_dict [key ] = {
235+ "dims" : (dim0 , "time" + tg ),
236+ "data" : data ["data_vars" ][key ],
237+ }
238+
266239 # ADCP IMU data
267240 elif shp [0 ] == 3 :
268241 if not any (val in key for val in tag ):
269242 tg = ""
270243 else :
271244 tg = [val for val in tag if val in key ]
272245 tg = tg [0 ]
273- dirIMU = xr .DataArray (
274- [1 , 2 , 3 ],
275- dims = ["dirIMU" ],
276- name = "dirIMU" ,
277- attrs = {"units" : "1" , "long_name" : "Reference Frame" },
278- )
279- ds [key ] = ds [key ].rename ({"dim_0" : "dirIMU" , "dim_1" : "time" + tg })
280- ds [key ] = ds [key ].assign_coords (
281- {"dirIMU" : dirIMU , "time" + tg : data ["coords" ]["time" + tg ]}
282- )
283246
284- ds [key ].attrs ["coverage_content_type" ] = "physicalMeasurement"
247+ if "dirIMU" not in ds_dict :
248+ ds_dict ["dirIMU" ] = {"dims" : ("dirIMU" ), "data" : [1 , 2 , 3 ]}
249+ data ["units" ].update ({"dirIMU" : "1" })
250+ data ["long_name" ].update ({"dirIMU" : "Reference Frame" })
251+
252+ ds_dict [key ] = {
253+ "dims" : ("dirIMU" , "time" + tg ),
254+ "data" : data ["data_vars" ][key ],
255+ }
285256
286- elif l == 3 : # 3D variables
257+ elif "b5" in tg :
258+ ds_dict [key ] = {
259+ "dims" : ("range_b5" , "time_b5" ),
260+ "data" : data ["data_vars" ][key ],
261+ }
262+
263+ elif len (shp ) == 3 : # 3D variables
287264 if "vel" in key :
288265 dim0 = "dir"
289266 else : # amp, corr, prcnt_gd, status
@@ -294,43 +271,43 @@ def _create_dataset(data):
294271 tg = "_avg"
295272 else :
296273 tg = ""
297- ds [key ] = ds [key ].rename (
298- {"dim_0" : dim0 , "dim_1" : "range" + tg , "dim_2" : "time" + tg }
299- )
300- ds [key ] = ds [key ].assign_coords (
301- {
302- dim0 : FoR [dim0 ],
303- "range" + tg : data ["coords" ]["range" + tg ],
304- "time" + tg : data ["coords" ]["time" + tg ],
305- }
306- )
274+ ds_dict [key ] = {
275+ "dims" : (dim0 , "range" + tg , "time" + tg ),
276+ "data" : data ["data_vars" ][key ],
277+ }
278+
307279 elif "b5" in key :
308- # xarray can't handle coords of length 1
309- ds [key ] = ds [key ][0 ]
310- ds [key ] = ds [key ].rename ({"dim_1" : "range_b5" , "dim_2" : "time_b5" })
311- ds [key ] = ds [key ].assign_coords (
312- {
313- "range_b5" : data ["coords" ]["range_b5" ],
314- "time_b5" : data ["coords" ]["time_b5" ],
315- }
316- )
280+ # "vel_b5" sometimes stored as (1, range_b5, time_b5)
281+ ds_dict [key ] = {
282+ "dims" : ("range_b5" , "time_b5" ),
283+ "data" : data ["data_vars" ][key ][0 ],
284+ }
317285 elif "sl" in key :
318- ds [key ] = ds [key ].rename (
319- {"dim_0" : dim0 , "dim_1" : "range_sl" , "dim_2" : "time" }
320- )
321- ds [key ] = ds [key ].assign_coords (
322- {
323- "range_sl" : data ["coords" ]["range_sl" ],
324- "time" : data ["coords" ]["time" ],
325- }
326- )
286+ ds_dict [key ] = {
287+ "dims" : (dim0 , "range_sl" , "time" ),
288+ "data" : data ["data_vars" ][key ],
289+ }
327290 else :
328- ds = ds .drop_vars (key )
329291 warnings .warn (f"Variable not included in dataset: { key } " )
330292
293+ # Create dataset
294+ ds = xr .Dataset .from_dict (ds_dict )
295+
296+ # Assign data array attributes
297+ for key in ds .variables :
298+ for md in ["units" , "long_name" , "standard_name" ]:
299+ if key in data [md ]:
300+ ds [key ].attrs [md ] = data [md ][key ]
301+ if len (ds [key ].shape ) > 1 :
331302 ds [key ].attrs ["coverage_content_type" ] = "physicalMeasurement"
303+ try : # make sure ones with tags get units
304+ tg = "_" + key .rsplit ("_" )[- 1 ]
305+ if any (val in key for val in tag ):
306+ ds [key ].attrs [md ] = data [md ][key [: - len (tg )]]
307+ except :
308+ pass
332309
333- # coordinate attributes
310+ # Assign coordinate attributes
334311 for ky in ds .dims :
335312 ds [ky ].attrs ["coverage_content_type" ] = "coordinate"
336313 r_list = [r for r in ds .coords if "range" in r ]
@@ -344,7 +321,7 @@ def _create_dataset(data):
344321 ds [ky ].attrs ["long_name" ] = "Time"
345322 ds [ky ].attrs ["standard_name" ] = "time"
346323
347- # dataset metadata
324+ # Set dataset metadata
348325 ds .attrs = data ["attrs" ]
349326
350327 return ds
0 commit comments