2
2
import pandas as pd
3
3
import re
4
4
import os
5
+ import copy
5
6
from . import _headers
6
7
from . import downloads
7
8
@@ -73,7 +74,6 @@ def __eq__(self, other):
73
74
return False
74
75
else :
75
76
if v1 != v2 :
76
- print (k )
77
77
return False
78
78
79
79
return True
@@ -246,49 +246,24 @@ def wrannfile(self):
246
246
with open (self .recordname + '.' + self .annotator , 'wb' ) as f :
247
247
databytes .tofile (f )
248
248
249
- # # Convert all used annotation fields into bytes to write
250
- # def fieldbytes(self):
251
-
252
- # # The difference samples to write
253
- # annsampdiff = np.concatenate(([self.annsamp[0]], np.diff(self.annsamp)))
254
-
255
- # # All fields to be written. samp and type are together
256
- # extrawritefields = []
257
-
258
- # for field in ['num', 'subtype', 'chan', 'aux']:
259
- # if getattr(self, field) is not None:
260
- # extrawritefields.append(field)
261
-
262
- # databytes = []
263
-
264
- # # Iterate across all fields one index at a time
265
- # for i in range(len(annsampdiff)):
266
-
267
- # # Process the annsamp (difference) and anntype items
268
- # databytes.append(field2bytes('samptype', [annsampdiff[i], self.anntype[i]]))
269
-
270
- # for field in extrawritefields:
271
- # value = getattr(self, field)[i]
272
- # if value is not None:
273
- # databytes.append(field2bytes(field, value))
274
-
275
- # # Flatten and convert to correct format
276
- # databytes = np.array([item for sublist in databytes for item in sublist]).astype('u1')
277
-
278
- # return databytes
279
-
280
-
281
249
# Convert all used annotation fields into bytes to write
282
250
def fieldbytes (self ):
283
251
284
252
# The difference samples to write
285
253
annsampdiff = np .concatenate (([self .annsamp [0 ]], np .diff (self .annsamp )))
286
254
287
- # All fields to be written. samp and type are together
255
+
256
+ # Create a copy of the annotation object with a
257
+ # compact version of fields to write
258
+ compact_annotation = copy .deepcopy (self )
259
+ compact_annotation .compact_fields ()
260
+
261
+
262
+ # The optional fields to be written. Write if they are not None or all empty
288
263
extrawritefields = []
289
264
290
265
for field in ['num' , 'subtype' , 'chan' , 'aux' ]:
291
- if getattr (self , field ) is not None :
266
+ if not isblank ( getattr (compact_annotation , field )) :
292
267
extrawritefields .append (field )
293
268
294
269
databytes = []
@@ -299,8 +274,9 @@ def fieldbytes(self):
299
274
# Process the annsamp (difference) and anntype items
300
275
databytes .append (field2bytes ('samptype' , [annsampdiff [i ], self .anntype [i ]]))
301
276
277
+ # Process the extra optional fields
302
278
for field in extrawritefields :
303
- value = getattr (self , field )[i ]
279
+ value = getattr (compact_annotation , field )[i ]
304
280
if value is not None :
305
281
databytes .append (field2bytes (field , value ))
306
282
@@ -309,6 +285,44 @@ def fieldbytes(self):
309
285
310
286
return databytes
311
287
288
+ # Compact all of the object's fields so that the output
289
+ # writing annotation file writes as few bytes as possible
290
+ def compact_fields (self ):
291
+
292
+ # Number of annotations
293
+ nannots = len (self .annsamp )
294
+
295
+ # Chan and num carry over previous fields. Get lists of as few
296
+ # elements to write as possible
297
+ self .chan = compact_carry_field (self .chan )
298
+ self .num = compact_carry_field (self .num )
299
+
300
+ # Elements of 0 (default) do not need to be written for subtype.
301
+ # num and sub are signed in original c package...
302
+ if self .subtype is not None :
303
+ if type (self .subtype ) == list :
304
+ for i in range (nannots ):
305
+ if self .subtype [i ] == 0 :
306
+ self .subtype [i ] = None
307
+ if np .array_equal (self .subtype , [None ]* nannots ):
308
+ self .subtype = None
309
+ else :
310
+ zero_inds = np .where (self .subtype == 0 )[0 ]
311
+ if len (zero_inds ) == nannots :
312
+ self .subtype = None
313
+ else :
314
+ self .subtype = list (self .subtype )
315
+ for i in zero_inds :
316
+ self .subtype [i ] = None
317
+
318
+ # Empty aux strings are not written
319
+ if self .aux is not None :
320
+ for i in range (nannots ):
321
+ if self .aux [i ] == '' :
322
+ self .aux [i ] = None
323
+ if np .array_equal (self .aux , [None ]* nannots ):
324
+ self .aux = None
325
+
312
326
313
327
# Move non-encoded anntype elements into the aux field
314
328
def type2aux (self ):
@@ -404,7 +418,49 @@ def customcode2bytes(c_triplet):
404
418
405
419
return annbytes
406
420
421
+ # Tests whether the item is blank
422
+ def isblank (x ):
423
+ if x is None :
424
+ return True
425
+ elif type (x ) == list :
426
+ if np .array_equal (x , [None ]* len (x )):
427
+ return True
428
+ return False
429
+
430
+
431
+ def compact_carry_field (full_field ):
432
+ """
433
+ Return the compact list version of a list/array of an
434
+ annotation field that has previous values carried over
435
+ (chan or num)
436
+ - The first sample is 0 by default. Only set otherwise
437
+ if necessary.
438
+ - Only set fields if they are different from their prev
439
+ field
440
+ """
441
+
442
+ # Keep in mind that the field may already be compact or None
443
+
444
+ if full_field is None :
445
+ return None
446
+
447
+ # List of same length. Place None where element
448
+ # does not need to be written
449
+ compact_field = [None ]* len (full_field )
450
+
451
+ prev_field = 0
452
+
453
+ for i in range (len (full_field )):
454
+ current_field = full_field [i ]
455
+ if current_field != prev_field :
456
+ compact_field [i ] = current_field
457
+ prev_field = current_field
458
+
459
+ # May further simplify
460
+ if np .array_equal (compact_field , [None ]* len (full_field )):
461
+ compact_field = None
407
462
463
+ return compact_field
408
464
409
465
410
466
# Convert an annotation field into bytes to write
0 commit comments