


BML_ANNOT2SPIKE creates a ft_datatype_spike structure from an annotation table
Use as
spike = bml_annot2spike(cfg, annot)
spike = bml_annot2spike(cfg, annot, raw)
spike = bml_annot2spike(cfg, annot, spike_waveform)
cfg.roi - roi table used to transform the times in annot.starts to
timestamps (ie, samples). Required if raw is not provided.
cfg.waveform_mult - double, multiplying factor for waveform. Defaults to 1.
cfg.waveform_extract - boolean indicating if waveforms whould be cropped
from raw. Defaults to false.
cfg.waveform_samples - integer indicating number of sample for the
waveforms. Defauls to 44.
cfg.annot_spike_id - string, indicates which variable of annot should be
treated as spike index for waveform extraction. Defaults to 'spike_idx'
cfg.unit_delimiter - string to delimit units from channels. Defaults to
'_unit'
annot - annotation table to transform to spike timestamps. Only the
starts vector is used. Normally obtained from bml_plexon2annot
raw - ft_datatype_raw from where to use as template for the spikes
timestamps and to crop the snippets from.
spike_waveform - ft_datatype_spike as returned by ft_read_spike or
bml_plexon2annot. waveforms are extracted from here if available.
should contain fields 'waveform' and 'label'.
returns a ft_datatype_spike structure. Each label correspons to an
individual unit named as <channel>_<unit>.
If spike_waveform is provided, a waveform field will be present in the
output, where the mapping of units to waveform is based on annot.channel,
annot.spike_idx, spike_waveform.label and spike_waveform.waveform.
If raw is provided, a waveform field will be present in the output, where the
mapping of snippets are extracted from the raw vector. The labels of raw
must match annot.channel.

0001 function spike = bml_annot2spike(cfg, annot, raw) 0002 0003 % BML_ANNOT2SPIKE creates a ft_datatype_spike structure from an annotation table 0004 % 0005 % Use as 0006 % spike = bml_annot2spike(cfg, annot) 0007 % spike = bml_annot2spike(cfg, annot, raw) 0008 % spike = bml_annot2spike(cfg, annot, spike_waveform) 0009 % 0010 % cfg.roi - roi table used to transform the times in annot.starts to 0011 % timestamps (ie, samples). Required if raw is not provided. 0012 % cfg.waveform_mult - double, multiplying factor for waveform. Defaults to 1. 0013 % cfg.waveform_extract - boolean indicating if waveforms whould be cropped 0014 % from raw. Defaults to false. 0015 % cfg.waveform_samples - integer indicating number of sample for the 0016 % waveforms. Defauls to 44. 0017 % cfg.annot_spike_id - string, indicates which variable of annot should be 0018 % treated as spike index for waveform extraction. Defaults to 'spike_idx' 0019 % cfg.unit_delimiter - string to delimit units from channels. Defaults to 0020 % '_unit' 0021 % 0022 % annot - annotation table to transform to spike timestamps. Only the 0023 % starts vector is used. Normally obtained from bml_plexon2annot 0024 % raw - ft_datatype_raw from where to use as template for the spikes 0025 % timestamps and to crop the snippets from. 0026 % spike_waveform - ft_datatype_spike as returned by ft_read_spike or 0027 % bml_plexon2annot. waveforms are extracted from here if available. 0028 % should contain fields 'waveform' and 'label'. 0029 % 0030 % returns a ft_datatype_spike structure. Each label correspons to an 0031 % individual unit named as <channel>_<unit>. 0032 % 0033 % If spike_waveform is provided, a waveform field will be present in the 0034 % output, where the mapping of units to waveform is based on annot.channel, 0035 % annot.spike_idx, spike_waveform.label and spike_waveform.waveform. 0036 % 0037 % If raw is provided, a waveform field will be present in the output, where the 0038 % mapping of snippets are extracted from the raw vector. The labels of raw 0039 % must match annot.channel. 0040 0041 if nargin == 3 0042 assert(isstruct(raw), "Invalid third argument"); 0043 if all(ismember({'trial','time','label'},fieldnames(raw))) 0044 % Usage spike = bml_annot2spike(cfg, annot, raw) 0045 spike_waveform = []; 0046 elseif all(ismember({'waveform','label'},fieldnames(raw))) 0047 % Usage spike = bml_annot2spike(cfg, annot, spike_waveform) 0048 spike_waveform = raw; 0049 raw = []; 0050 else 0051 error("invalid third argument"); 0052 end 0053 elseif nargin == 2 0054 spike_waveform = []; 0055 raw = []; 0056 else 0057 error("Incorrect number of arguments"); 0058 end 0059 0060 roi = bml_getopt(cfg,'roi'); 0061 if isempty(roi) 0062 if ~isempty(raw) 0063 roi = bml_raw2annot(raw); 0064 else 0065 error("cfg.roi or raw required"); 0066 end 0067 end 0068 0069 annot = bml_annot_table(annot,[],inputname(2)); 0070 assert(all(ismember({'channel','unit'},annot.Properties.VariableNames)),... 0071 "channel and unit columns required in annot"); 0072 0073 waveform_mult = bml_getopt(cfg,'waveform_mult',1); 0074 waveform_extract = bml_getopt(cfg,'waveform_extract',false); 0075 waveform_samples = bml_getopt(cfg,'waveform_samples',44); 0076 unit_delimiter = bml_getopt_single(cfg,'unit_delimiter','_unit'); 0077 0078 annot_spike_id = bml_getopt_single(cfg,'annot_spike_id','spike_idx'); 0079 has_spike_idx = ismember({annot_spike_id},annot.Properties.VariableNames); 0080 0081 annot.channel_unit = strcat(annot.channel,unit_delimiter,num2str(annot.unit)); 0082 tot_units = length(unique(annot.channel_unit)); 0083 0084 spike=struct(); 0085 spike.timestamp=cell(1,tot_units); 0086 spike.label=cell(1,tot_units); 0087 spike_idx=cell(1,tot_units); 0088 channel=cell(1,tot_units); 0089 0090 lev_channel = unique(annot.channel); 0091 i_tot_unit = 1; 0092 annot = bml_annot_filter(annot,roi); 0093 assert(height(annot)>0,'no events in annot in specified time window'); 0094 for i_ch=1:length(lev_channel) 0095 assert(i_tot_unit<=tot_units); 0096 ch_annot = annot(strcmp(annot.channel,lev_channel(i_ch)),:); 0097 lev_unit = unique(ch_annot.unit); 0098 for i_u=1:length(lev_unit) 0099 u_ch_annot = ch_annot(ch_annot.unit == lev_unit(i_u),:); 0100 spike.timestamp{i_tot_unit} = bml_time2idx(roi,u_ch_annot.starts); 0101 spike.label(i_tot_unit) = strcat(lev_channel(i_ch),unit_delimiter,num2str(lev_unit(i_u))); 0102 if has_spike_idx 0103 spike_idx{i_tot_unit} = u_ch_annot.spike_idx; 0104 channel{i_tot_unit} = lev_channel(i_ch); 0105 end 0106 i_tot_unit = i_tot_unit + 1; 0107 end 0108 end 0109 0110 if has_spike_idx && ~isempty(spike_waveform) 0111 %getting waveforms from spike_waveform 0112 spike.waveform=cell(1,length(spike_idx)); 0113 for i_wf=1:length(spike_idx) 0114 orig_wf_idx = bml_getidx(channel{i_wf},spike_waveform.label); 0115 spike.waveform{1,i_wf} = waveform_mult .* spike_waveform.waveform{orig_wf_idx}(:,:,spike_idx{i_wf}); 0116 end 0117 end 0118 0119 if ~isempty(raw) && waveform_extract 0120 error("waveform extraction not implemented yet"); 0121 end 0122 0123 0124 0125 0126 0127 0128 0129