@@ -432,12 +432,15 @@ def rdann(recordname, annotator, sampfrom=0, sampto=None):
432432 # Snip the unallocated end of the arrays
433433 annsamp ,anntype ,num ,subtype ,chan ,aux = snip_arrays (annsamp ,anntype ,num ,subtype ,chan ,aux ,ai )
434434
435+ # Process the fields if there are custom annotation types
436+ allannsyms ,annsamp ,anntype ,num ,subtype ,chan ,aux = proccustomtypes (annsamp ,anntype ,num ,subtype ,chan ,aux )
437+
435438 # Apply annotation range (from X to Y)
436439 annsamp ,anntype ,num ,subtype ,chan ,aux = apply_annotation_range (annsamp ,
437440 sampfrom ,sampto ,anntype ,num ,subtype ,chan ,aux )
438441
439- # Set the annotation type to annotation codes
440- anntype = [annsyms [code ] for code in anntype ]
442+ # Set the annotation type to the annotation codes
443+ anntype = [allannsyms [code ] for code in anntype ]
441444
442445 # Store fields in an Annotation object
443446 annotation = Annotation (recordname , annotator , annsamp , anntype ,
@@ -539,7 +542,7 @@ def snip_arrays(annsamp,anntype,num,subtype,chan,aux,ai):
539542 aux = aux [0 :ai ]
540543 return annsamp ,anntype ,num ,subtype ,chan ,aux
541544
542- # Keep only the specified annotations
545+ # Keep annotations within a sample range
543546def apply_annotation_range (annsamp ,sampfrom ,sampto ,anntype ,num ,subtype ,chan ,aux ):
544547
545548 returnempty = 0
@@ -578,6 +581,43 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
578581 return annsamp ,anntype ,num ,subtype ,chan ,aux
579582
580583
584+ # Process the fields if there are custom annotation types
585+ def proccustomtypes (annsamp ,anntype ,num ,subtype ,chan ,aux ):
586+ # Custom anncodes appear as regular annotations in the form:
587+ # sample = 0, anntype = 22 (note annotation '"'), aux = "NUMBER[ \t]CUSTOMANNCODE[ \t]Calibration"
588+ s0 = np .where (annsamp == 0 )[0 ]
589+ t22 = np .where (anntype == 22 )[0 ]
590+ s0t22 = list (set (s0 ).intersection (t22 ))
591+
592+ allannsyms = annsyms .copy ()
593+ if s0t22 != []:
594+ # The custom anncode indices
595+ custominds = []
596+ # Check aux for custom codes
597+ for i in s0t22 :
598+ acceptedstring = re .match ('(\d+)[ \t ](\w+)[ \t ]Calibration' , aux [i ])
599+ # Found custom annotation code.
600+ if acceptedstring is not None and acceptedstring .string == aux [i ]:
601+ # Keep track of index
602+ custominds .append (i )
603+ # Add code to annsym dictionary
604+ codenum , codesym = acceptedstring .group (1 , 2 )
605+ allannsyms [int (codenum )] = codesym
606+
607+ # Remove the attributes with the custom anncode indices
608+ if custominds != []:
609+ keepinds = [i for i in range (len (annsamp )) if i not in custominds ]
610+
611+ annsamp = annsamp [keepinds ]
612+ anntype = anntype [keepinds ]
613+ num = num [keepinds ]
614+ subtype = subtype [keepinds ]
615+ chan = chan [keepinds ]
616+ aux = [aux [i ] for i in keepinds ]
617+
618+ return (allannsyms ,annsamp ,anntype ,num ,subtype ,chan ,aux )
619+
620+
581621## ------------- /Reading Annotations ------------- ##
582622
583623
@@ -599,9 +639,9 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
599639 12 : '/' , # paced beat */
600640 13 : 'Q' , # unclassifiable beat */
601641 14 : '~' , # signal quality change */
602- # 15: '[15]',
642+ 15 : '[15]' ,
603643 16 : '|' , # isolated QRS-like artifact */
604- # 17: '[17]',
644+ 17 : '[17]' ,
605645 18 : 's' , # ST change */
606646 19 : 'T' , # T-wave change */
607647 20 : '*' , # systole */
@@ -624,18 +664,16 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
624664 37 : 'x' , # non-conducted P-wave (blocked APB) */
625665 38 : 'f' , # fusion of paced and normal beat */
626666 39 : '(' , # waveform onset */
627- # 39: 'PQ', # PQ junction (beginning of QRS) */
628667 40 : ')' , # waveform end */
629- # 40: 'JPT', # J point (end of QRS) */
630668 41 : 'r' , # R-on-T premature ventricular contraction */
631- # 42: '[42]',
632- # 43: '[43]',
633- # 44: '[44]',
634- # 45: '[45]',
635- # 46: '[46]',
636- # 47: '[47]',
637- # 48: '[48]',
638- # 49: '[49]',
669+ 42 : '[42]' ,
670+ 43 : '[43]' ,
671+ 44 : '[44]' ,
672+ 45 : '[45]' ,
673+ 46 : '[46]' ,
674+ 47 : '[47]' ,
675+ 48 : '[48]' ,
676+ 49 : '[49]' ,
639677}
640678# Reverse ann symbols for mapping symbols back to numbers
641679revannsyms = {v : k for k , v in annsyms .items ()}
@@ -658,7 +696,9 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
658696 12 : 'PACE' , # paced beat */
659697 13 : 'UNKNOWN' , # unclassifiable beat */
660698 14 : 'NOISE' , # signal quality change */
699+ 15 : '' ,
661700 16 : 'ARFCT' , # isolated QRS-like artifact */
701+ 17 : '' ,
662702 18 : 'STCH' , # ST change */
663703 19 : 'TCH' , # T-wave change */
664704 20 : 'SYSTOLE' , # systole */
@@ -681,10 +721,16 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
681721 37 : 'NAPC' , # non-conducted P-wave (blocked APB) */
682722 38 : 'PFUS' , # fusion of paced and normal beat */
683723 39 : 'WFON' , # waveform onset */
684- # 39: 'PQ', # PQ junction (beginning of QRS) */
685724 40 : 'WFOFF' , # waveform end */
686- # 40: 'JPT', # J point (end of QRS) */
687- 41 : 'RONT' # R-on-T premature ventricular contraction */
725+ 41 : 'RONT' , # R-on-T premature ventricular contraction */
726+ 42 : '' ,
727+ 43 : '' ,
728+ 44 : '' ,
729+ 45 : '' ,
730+ 46 : '' ,
731+ 47 : '' ,
732+ 48 : '' ,
733+ 49 : ''
688734}
689735
690736# Mapping annotation symbols to the annotation codes
0 commit comments