@@ -432,12 +432,15 @@ def rdann(recordname, annotator, sampfrom=0, sampto=None):
432
432
# Snip the unallocated end of the arrays
433
433
annsamp ,anntype ,num ,subtype ,chan ,aux = snip_arrays (annsamp ,anntype ,num ,subtype ,chan ,aux ,ai )
434
434
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
+
435
438
# Apply annotation range (from X to Y)
436
439
annsamp ,anntype ,num ,subtype ,chan ,aux = apply_annotation_range (annsamp ,
437
440
sampfrom ,sampto ,anntype ,num ,subtype ,chan ,aux )
438
441
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 ]
441
444
442
445
# Store fields in an Annotation object
443
446
annotation = Annotation (recordname , annotator , annsamp , anntype ,
@@ -539,7 +542,7 @@ def snip_arrays(annsamp,anntype,num,subtype,chan,aux,ai):
539
542
aux = aux [0 :ai ]
540
543
return annsamp ,anntype ,num ,subtype ,chan ,aux
541
544
542
- # Keep only the specified annotations
545
+ # Keep annotations within a sample range
543
546
def apply_annotation_range (annsamp ,sampfrom ,sampto ,anntype ,num ,subtype ,chan ,aux ):
544
547
545
548
returnempty = 0
@@ -578,6 +581,43 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
578
581
return annsamp ,anntype ,num ,subtype ,chan ,aux
579
582
580
583
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
+
581
621
## ------------- /Reading Annotations ------------- ##
582
622
583
623
@@ -599,9 +639,9 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
599
639
12 : '/' , # paced beat */
600
640
13 : 'Q' , # unclassifiable beat */
601
641
14 : '~' , # signal quality change */
602
- # 15: '[15]',
642
+ 15 : '[15]' ,
603
643
16 : '|' , # isolated QRS-like artifact */
604
- # 17: '[17]',
644
+ 17 : '[17]' ,
605
645
18 : 's' , # ST change */
606
646
19 : 'T' , # T-wave change */
607
647
20 : '*' , # systole */
@@ -624,18 +664,16 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
624
664
37 : 'x' , # non-conducted P-wave (blocked APB) */
625
665
38 : 'f' , # fusion of paced and normal beat */
626
666
39 : '(' , # waveform onset */
627
- # 39: 'PQ', # PQ junction (beginning of QRS) */
628
667
40 : ')' , # waveform end */
629
- # 40: 'JPT', # J point (end of QRS) */
630
668
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]' ,
639
677
}
640
678
# Reverse ann symbols for mapping symbols back to numbers
641
679
revannsyms = {v : k for k , v in annsyms .items ()}
@@ -658,7 +696,9 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
658
696
12 : 'PACE' , # paced beat */
659
697
13 : 'UNKNOWN' , # unclassifiable beat */
660
698
14 : 'NOISE' , # signal quality change */
699
+ 15 : '' ,
661
700
16 : 'ARFCT' , # isolated QRS-like artifact */
701
+ 17 : '' ,
662
702
18 : 'STCH' , # ST change */
663
703
19 : 'TCH' , # T-wave change */
664
704
20 : 'SYSTOLE' , # systole */
@@ -681,10 +721,16 @@ def apply_annotation_range(annsamp,sampfrom,sampto,anntype,num,subtype,chan,aux)
681
721
37 : 'NAPC' , # non-conducted P-wave (blocked APB) */
682
722
38 : 'PFUS' , # fusion of paced and normal beat */
683
723
39 : 'WFON' , # waveform onset */
684
- # 39: 'PQ', # PQ junction (beginning of QRS) */
685
724
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 : ''
688
734
}
689
735
690
736
# Mapping annotation symbols to the annotation codes
0 commit comments