@@ -2487,28 +2487,16 @@ def csv2ann(file_name, extension='atr', fs=None, record_only=False,
2487
2487
if df_CSV .shape [1 ] == 2 :
2488
2488
if verbose :
2489
2489
print ('onset,description format detected' )
2490
+ if not header :
2491
+ df_CSV .columns = ['onset' , 'description' ]
2490
2492
df_out = df_CSV
2491
2493
elif df_CSV .shape [1 ] == 3 :
2492
2494
if verbose :
2493
2495
print ('onset,duration,description format detected' )
2494
2496
print ('Converting durations to single time-point events' )
2495
- # Create two separate dataframes for the start and end annotation
2496
- # then remove them from the original
2497
- df_start = df_CSV [df_CSV ['duration' ] > 0 ]
2498
- df_end = df_CSV [df_CSV ['duration' ] > 0 ]
2499
- df_trunc = df_CSV [df_CSV ['duration' ] == 0 ]
2500
- # Append parentheses at the start for annotation start and end for
2501
- # annotation end
2502
- df_start ['description' ] = '(' + df_start ['description' ].astype (str )
2503
- df_end ['description' ] = df_end ['description' ].astype (str ) + ')'
2504
- # Add the duration time to the onset for the end annotation to convert
2505
- # to single time annotations only
2506
- df_end ['onset' ] = df_end ['onset' ] + df_end ['duration' ]
2507
- # Concatenate all of the dataframes
2508
- df_out = pd .concat ([df_trunc , df_start , df_end ], ignore_index = True )
2509
- # Make sure the sorting is correct
2510
- df_out ['col_index' ] = df_out .index
2511
- df_out = df_out .sort_values (['onset' , 'col_index' ])
2497
+ if not header :
2498
+ df_CSV .columns = ['onset' , 'duration' , 'description' ]
2499
+ df_out = _format_ann_from_df (df_CSV )
2512
2500
else :
2513
2501
raise Exception ("""The number of columns in the CSV was not
2514
2502
recognized.""" )
@@ -2656,6 +2644,7 @@ def rdedfann(record_name, pn_dir=None, delete_file=True, info_only=True,
2656
2644
annotation_string = annotation_string .replace (rep ,' ' )
2657
2645
2658
2646
# Parse the resulting annotation string
2647
+ onsets = []
2659
2648
onset_times = []
2660
2649
sample_nums = []
2661
2650
comments = []
@@ -2675,6 +2664,7 @@ def rdedfann(record_name, pn_dir=None, delete_file=True, info_only=True,
2675
2664
comment = ' ' .join (ann_split [2 :])
2676
2665
if verbose :
2677
2666
print (f'{ onset_time } \t { sample_num } \t { comment } \t \t duration: { duration } ' )
2667
+ onsets .append (onset )
2678
2668
onset_times .append (onset_time )
2679
2669
sample_nums .append (sample_num )
2680
2670
comments .append (comment )
@@ -2689,12 +2679,70 @@ def rdedfann(record_name, pn_dir=None, delete_file=True, info_only=True,
2689
2679
'comment' : comments ,
2690
2680
'duration' : durations
2691
2681
}
2692
- elif record_only :
2693
- # TODO: return WFDB-formatted annotation object
2694
- pass
2695
2682
else :
2696
- # TODO: Create the WFDB annotation file and don't return the object
2697
- pass
2683
+ df_in = pd .DataFrame (data = {
2684
+ 'onset' : onsets , 'duration' : durations , 'description' : comments
2685
+ })
2686
+ df_out = _format_ann_from_df (df_in )
2687
+ # Remove extension from input file name
2688
+ record_name = record_name .split (os .sep )[- 1 ].split ('.' )[0 ]
2689
+ extension = 'atr'
2690
+ fs = rec .fs
2691
+ sample = (df_out ['onset' ].to_numpy ()* fs ).astype (np .int64 )
2692
+ # Assume each annotation is a comment
2693
+ symbol = ['"' ]* len (df_out .index )
2694
+ subtype = np .array ([22 ]* len (df_out .index ))
2695
+ # Assume each annotation belongs with the 1st channel
2696
+ chan = np .array ([0 ]* len (df_out .index ))
2697
+ num = np .array ([0 ]* len (df_out .index ))
2698
+ aux_note = df_out ['description' ].tolist ()
2699
+
2700
+ if record_only :
2701
+ return Annotation (record_name = record_name , extension = extension ,
2702
+ sample = sample , symbol = symbol , subtype = subtype ,
2703
+ chan = chan , num = num , aux_note = aux_note , fs = fs )
2704
+ else :
2705
+ wrann (record_name , extension , sample = sample , symbol = symbol ,
2706
+ subtype = subtype , chan = chan , num = num , aux_note = aux_note ,
2707
+ fs = fs )
2708
+
2709
+
2710
+ def _format_ann_from_df (df_in ):
2711
+ """
2712
+ Parameters
2713
+ ----------
2714
+ df_in : Pandas dataframe
2715
+ Contains all the information needed to create WFDB-formatted
2716
+ annotations. Of the form:
2717
+ onset,duration,description
2718
+ onset_1,duration_1,description_1
2719
+ onset_2,duration_2,description_2
2720
+ ...,...,...
2721
+
2722
+ Returns
2723
+ -------
2724
+ N/A : Pandas dataframe
2725
+ The WFDB-formatted input dataframe.
2726
+
2727
+ """
2728
+ # Create two separate dataframes for the start and end annotation
2729
+ # then remove them from the original
2730
+ df_start = df_in [df_in ['duration' ] > 0 ]
2731
+ df_end = df_in [df_in ['duration' ] > 0 ]
2732
+ df_trunc = df_in [df_in ['duration' ] == 0 ]
2733
+ # Append parentheses at the start for annotation start and end for
2734
+ # annotation end
2735
+ df_start ['description' ] = '(' + df_start ['description' ].astype (str )
2736
+ df_end ['description' ] = df_end ['description' ].astype (str ) + ')'
2737
+ # Add the duration time to the onset for the end annotation to convert
2738
+ # to single time annotations only
2739
+ df_end ['onset' ] = df_end ['onset' ] + df_end ['duration' ]
2740
+ # Concatenate all of the dataframes
2741
+ df_out = pd .concat ([df_trunc , df_start , df_end ], ignore_index = True )
2742
+ # Make sure the sorting is correct
2743
+ df_out ['col_index' ] = df_out .index
2744
+ return df_out .sort_values (['onset' , 'col_index' ])
2745
+
2698
2746
2699
2747
2700
2748
## ------------- Annotation Field Specifications ------------- ##
0 commit comments