[Eeglablist] Creating new event codes based on previous combination of event codes in each trial

Cedric Cannard ccannard at protonmail.com
Mon Oct 12 11:50:46 PDT 2020


Hi Renzo,

I'm glad it's helping.

Much easier with the event structure, thanks!

Here is attached a new script (and pasted below for list members if needed) with a different strategy, which I think, should do what you want.

This new code keeps only the first event (stimulus) of each epoch and the corresponding awareness score, and ignores all the other irrelevant events. Each row is an epoch with stimulus marker, stimulus latency = 0, awareness marker, epoch number (i.e. trial), and combination code (i.e. combining stim and awareness markers).
Note that latencies of awareness scores are adjusted to be in X samples after stimulus in each epoch (instead of accumulated over the whole recording as it was originally). If you want it in milliseconds, I believe you need to divide that number by your sampling rate, and multiply by 1000.

If you only need this last one you can remove the lines doing the other columns.

Please check that everything is correct. Especially these trials that have 2 stims and 2 awareness scores. I kept only the awareness score that was closest in time to 1st stimulus of the epoch. The next stimuli and awareness scores from that same epoch are ignored as you suggested. But they should be the next trial of new_events.

Here is the code for other people from the list that might need it:
stim_codes = [11:16 21:26 31:36 41:46 51:56 61:66]; % Stim code shown at time zero
% resp_codes = 71:74; % accuracy response given somewhere between stimulus offset and time +1500ms
awareness_codes = 81:84; % awareness report given somwhere between accuracy response+300ms and response+2000ms

%Create index of stimulus events
indx_stim = ismember([EEG.event.type], stim_codes) > 0;

%Create index of awareness events
indx_awareness = ismember([EEG.event.type], awareness_codes) > 0;

counter = 1;
disp('Processing events...');
for iEvent = 1:length(indx_stim)

%Find which event is 1st stimulus of current epoch
epoch = EEG.event(iEvent).epoch;
indx_epoch = find([EEG.event.epoch] == epoch);
stim = min(indx_epoch);

%If current event is the 1st stimulus, export in new_events
if indx_stim(iEvent) == true && iEvent == stim
new_events(counter).stim = EEG.event(stim).type;
new_events(counter).lat_stim = 0;

%Then, get the time distance between each awareness response and this stimulus
for iAware = 1:length(indx_awareness)
if indx_awareness(iAware) == true
distance(iAware) = EEG.event(iAware).latency - EEG.event(iEvent).latency;
if distance(iAware) < 0
distance(iAware) = NaN; %dont include event with negative distance as they are from previous trial
end
else
distance(iAware) = NaN;
end
end

%Get closest awareness response (i.e. match)
match = find(distance == min(distance));

if EEG.event(stim).epoch == EEG.event(match).epoch %Make sure it is from same epoch

%get wareness event info in same epoch as corresponding stimulus:
new_events(counter).awareness = EEG.event(match).type;
new_events(counter).lat_awareness = EEG.event(match).latency - EEG.event(iEvent).latency;
new_events(counter).epoch = counter;

%Combination of both stim and awareness response
new_events(counter).comb = [num2str(EEG.event(iEvent).type) num2str(EEG.event(match).type)];

counter = counter + 1;
end
end
end
disp('Done.');

best,

Cedric

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Friday, October 9, 2020 4:33 PM, Renzo Lanfranco <renzo.lanfranco at gmail.com> wrote:

> Hi Cedric,
>
> It’s actually in the for loop. This loop bases its counter on the event numbers (iEvent), therefore it compares every row in the eeg.event structure to the vector created at the beginning containing (‘stim_codes’) the stimulus codes. When the loop encounters one of those event codes (‘stim_codes’), it creates a new event (‘new_events’) including the awareness report event code (‘awareness_codes’) of that epoch, depending on the outcome of the comparison. So far, that’s great. However, many epochs contain up to 5 event codes. Only the first 3 event codes of each epoch are relevant (stimulus type, accuracy response, and awareness report, in that order). The fourth and fifth event code in an epoch are stuff that belong to the next trial and should be completely ignored (as they will appear properly in the next epoch). But when the code compares that fourth event code in an epoch, it compares it to the vector list ‘stim_codes’ and if the comparison is successful, it assumes it’s a new trial so it adds it to ‘new_events’ as it were a different trial.
>
> The solution, I think, is to make the code read only the event codes in the first row of each epoch as they will always be the stimulus code of the trial, and then compare it to the third row of the same event code to create the new_event that contains both the stimulus information code and the awareness report information.
>
> I’m attaching an extract of the eeg.event structure where you can see that each epoch has between 3 and 5 rows (event codes), and your code. Again, thanks so much. You’ve been incredibly helpful!
>
> Renzo
>
> From: Cédric Cannard <ccannard at protonmail.com>
> Sent: 07 October 2020 20:56
> To: LANFRANCO GUEVARA Renzo <renzo.lanfranco at gmail.com>
> Cc: 'Clement Lee' <cll008 at eng.ucsd.edu>; 'EEGLAB List' <eeglablist at sccn.ucsd.edu>
> Subject: RE: [Eeglablist] Creating new event codes based on previous combination of event codes in each trial
>
> Hi Renzo,
>
> Glad to hear it worked.
>
> I am not sure where that takes place in the process. Is this happening in the new_events variable? Is it adding the extra markers in a new row in the new_events or on the same row?
>
> Does it fix it if you add a "break" below "count = count+1"?
>
> If not, could you send me one of your EEG file? it will be easier.
>
> Cédric
>
> ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
>
> On Wednesday, October 7, 2020 7:10 AM, LANFRANCO GUEVARA Renzo <renzo.lanfranco at gmail.com> wrote:
>
>> [Hi Cédric,]
>>
>> Thank you very much. I’ve adapted the code you wrote and it works perfectly fine. There’s only one issue, though, that I haven’t been able to sort out:
>>
>> It turns out that some epochs have EEG marks that belong to the next trial. This is because in each trial (epoch) you have 3 relevant EEG marks: (1) stimulus (always at zero), (2) accuracy response (always between 300 and 1500 ms after stimulus onset), and (3) awareness response (always between 300 and 2000 ms after accuracy response). Therefore, the second and third EEG marks are variable in latency. All the epochs contain these 3 EEG marks (and in this specific order), but some epochs also contain EEG marks from the next trial that of course are irrelevant to that given trial as they are properly contained in the next epoch.
>>
>> I was wondering, how one can adapt your code in a way that only takes into account the first three EEG marks of each epoch ignoring any other EEG mark after that (if there are any) in the epoch?
>>
>> Again, many thanks! Your code has been very useful.
>>
>> Renzo
>>
>> [From:][Cédric Cannard](mailto:ccannard at protonmail.com)
>> Sent: 25 September 2020 21:20
>> To: [Renzo Lanfranco](mailto:renzo.lanfranco at gmail.com)
>> Cc: [Clement Lee](mailto:cll008 at eng.ucsd.edu); [EEGLAB List](mailto:eeglablist at sccn.ucsd.edu)
>> Subject: Re: [Eeglablist] Creating new event codes based on previous combination of event codes in each trial
>>
>> Hi Renzo,
>>
>> I think I understand this time :) Sorry it is not easy through emails to know exactly what you are trying to code.
>>
>> How about this:
>>
>> stim_codes = 11:66;
>>
>> resp_codes = 71:74;
>>
>> aware_codes = 81:84;
>>
>> new_events = [];
>>
>> count = 1;
>>
>> for iEvent = 1:size(EEG.event,2)
>>
>> %check if event is a stimulus
>>
>> if sum(ismember(stim_codes, EEG.event(iEvent).type)) > 0
>>
>> new_events(count).stim_type = EEG.event(iEvent).type;
>>
>> new_events(count).stim_latency = 0;
>>
>> %look for match and put them together in new_events
>>
>> for match = 1:size(EEG.event,2)
>>
>> if EEG.event(match).epoch == EEG.event(iEvent).epoch && sum(ismember(aware_codes, EEG.event(match).type)) > 0
>>
>> new_events(count).aware_type = EEG.event(match).type; %Get awareness response category
>>
>> new_events(count).aware_latency = EEG.event(match).latency - EEG.event(iEvent).latency; %get latency from stimulus
>>
>> new_events(count).comb_latency = 0; %get 3rd code represnting combination of both stim and awareness
>>
>> new_events(count).epoch = EEG.event(iEvent).epoch; %get epoch number
>>
>> new_events(count).combination = [num2str(EEG.event(iEvent).type) '_' num2str(EEG.event(match).type)]; %get 3rd code represnting combination of both stim and awareness
>>
>> count = count + 1;
>>
>> end
>>
>> end
>>
>> end
>>
>> end
>>
>> I don't know if this format works for your toolbox, but this should provide you with the coding tools to gather the information you need.
>>
>> I am not sure about your 3rd arbitrary event code you want to create. I made one called "combination" using the combination of the stimulus and the awareness response together.
>>
>> You should be able to adjust it to what you want using my line.
>>
>> I hope this helps!
>>
>> Best,
>>
>> Cédric
>>
>> ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
>>
>> On Friday, September 25, 2020 10:42 AM, Renzo Lanfranco <renzo.lanfranco at gmail.com> wrote:
>>
>>> Thanks, Cédric. I think I didn't express myself correctly. Sorry about that!
>>>
>>> So, each epoch has a number of event codes, regarding stimulus class (first event code), accuracy response (second event code), and awareness response (third event code). What I'm trying to figure out is how to create a *new* event code based on the stimulus class event code and on the awareness response event code. A new event code in the same epoch, at time zero. These are the events already found in each epoch:
>>>
>>> stimulus_events = [11 12 13 14 15 16 21 22 23 24 25 26 31 32 33 34 35 36 41 42 43 44 45 46 51 52 53 53 54 56 61 62 63 64 65 66]; % located around time zero
>>>
>>> response_events = [71 72 73 74]; % accuracy responses not relevant for this analysis
>>>
>>> awareness_events = [81 82 83 84]; % located anywhere in the epoch after 300 ms post-stimulus presentation.
>>>
>>> For example, if epoch 1's first event code is 11 (a stimulus event) and the third event code is 81 (an awareness response event), I'd like to create a new event code at time zero for that particular epoch called, let's say, 91. In other words to make a new list of event codes that comprise the stimulus_event codes and the awareness_event code. Because all the epochs have the same length but in this experiment trials varied in time length, only the epoch's first three event codes are relevant as sometimes the epoch segments included the stimulus event from the following trial. Therefore, the code I'm trying to write (though unsuccessfully so far) has to take every epoch (trial), read the first event code (stimulus_events list above) and the third event code (awareness_events list above) and then create a new event code (at time zero). This new event code is of course arbitrary. It will have to be from a list of 144 event codes as it needs to include all the possible combinations between those two lists (length(stim_events)*length(awareness_events)), but that's something I can define in an if statement, like in your example code, using:
>>>
>>> if EEG.event(1).epoch(iEpoch) == 11 && EEG.event(3).epoch(iEpoch) == 81 ......
>>>
>>> I mean, that's the idea, but I've failed so far to create a code that can do this succesfully in a For loop.
>>>
>>> Thanks so much!
>>>
>>> Renzo
>>>
>>> On Thu, 24 Sep 2020 at 20:44, Cédric Cannard <ccannard at protonmail.com> wrote:
>>>
>>>> If I understand correctly, you want to predict the which stimulus was presented based on the response?
>>>>
>>>> And you basically need each row to have the stimulus and the response together
>>>>
>>>> If this is correct, maybe you something like this would work?
>>>>
>>>> new_events = [];
>>>>
>>>> for iEvent = 1:10
>>>>
>>>> if iEvent == 1
>>>>
>>>> trial = EEG.event(iEvent).epoch;
>>>>
>>>> new_events(trial).stimulus = EEG.event(iEvent).type;
>>>>
>>>> new_events(trial).stimulus_latency = 0;
>>>>
>>>> new_events(trial).trial = trial;
>>>>
>>>> elseif EEG.event(iEvent).epoch ~= EEG.event(iEvent-1).epoch
>>>>
>>>> trial = EEG.event(iEvent).epoch;
>>>>
>>>> new_events(trial).stimulus = EEG.event(iEvent).type;
>>>>
>>>> new_events(trial).stimulus_latency = 0;
>>>>
>>>> new_events(trial).trial = trial;
>>>>
>>>> elseif EEG.event(iEvent).epoch == EEG.event(iEvent-1).epoch
>>>>
>>>> new_events(trial).response = EEG.event(iEvent).type;
>>>>
>>>> new_events(trial).response_latency = EEG.event(iEvent).latency - EEG.event(iEvent-1).latency;
>>>>
>>>> end
>>>>
>>>> end
>>>>
>>>> Cédric
>>>>
>>>> ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
>>>>
>>>> On Thursday, September 24, 2020 11:40 AM, LANFRANCO GUEVARA Renzo <renzo.lanfranco at gmail.com> wrote:
>>>>
>>>>> Hi Cédric,
>>>>>
>>>>> Thanks for your reply. The decoding analysis assumes that the event codes at time zero refer to stimulus classes, as it often is. It’s not flexible enough to include other aspects that could be decoded such as responses – in the case of this experiment, awareness reports. So, by creating new event codes at time zero that comprise both the stimulus class and the awareness response given, I can sort the trials in the way this toolbox requires them. I know that this doesn’t make sense for most time-locked analyses, but it makes sense for this toolbox.
>>>>>
>>>>> For example, if all epochs (trials) go from -200 to +600 ms (time zero is stimulus presentation), and there’s an event code at time zero indicating what kind of stimulus was shown, and another event code somewhere between 400 and 600 ms indicating what key was pressed, I’d need to create a new event code (located at time zero) that accounts for both the stimulus that was presented *and* the response that was given later. That way, I can instruct the toolbox to define the classes to decode the right way. Because we’re trying to decode the stimulus classes for different awareness reports.
>>>>>
>>>>> Thanks so much!
>>>>>
>>>>> Best,
>>>>>
>>>>> Renzo
>>>>>
>>>>> From: [Cédric Cannard](mailto:ccannard at protonmail.com)
>>>>>
>>>>> Sent: 24 September 2020 19:25
>>>>>
>>>>> To: [Renzo Lanfranco](mailto:renzo.lanfranco at gmail.com)
>>>>>
>>>>> Cc: [Clement Lee](mailto:cll008 at eng.ucsd.edu); [EEGLAB List](mailto:eeglablist at sccn.ucsd.edu)
>>>>>
>>>>> Subject: RE: [Eeglablist] Creating new event codes based on previous combination of event codes in each trial
>>>>>
>>>>> Hi Renzo,
>>>>>
>>>>> Bringing all events to time 0 does not make any sense as EEG is time series data, if you lose the event's time information, they become useless. I really don't understand why the toolbox would require you to do that.
>>>>>
>>>>> There must be some mistake. Are you sure it is not just referring to the stimulus events regarding the event being at time 0? Normally, stimuli are at time 0, and responses are at X latency after stimulus. So when you epoch data in EEGLAB, you choose your epoch size (tags before and after stimulus) and it gives you all trials of same length, with the stimuli at time 0, and responses at for example +300 ms, + 450 ms, etc.
>>>>>
>>>>> Cédric
>>>>>
>>>>> ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
>>>>>
>>>>> On Wednesday, September 23, 2020 5:18 PM, Renzo Lanfranco <renzo.lanfranco at gmail.com> wrote:
>>>>>
>>>>>> Thanks, Clement and Cédric, this is really helpful.
>>>>>>
>>>>>> Indeed, I need to create a new event code for each epoch (trial) at stimulus onset (time zero) that puts together the information from the previous stimulus-related event code and the response-related event code. I’m using a decoding toolbox that requires the data to be submitted that way (all events at time zero). Your code, Cédric, is very helpful. Checking Clement’s link to the Wiki, I found some information that might indirectly help too (https://sccn.ucsd.edu/wiki/Chapter_03:_Event_Processing#Scripts_for_creating_new_events_based_on_context).
>>>>>>
>>>>>> But you’re right, it’s better to keep all the different numbers. So I have a new question now: is there any way to move *all* the event codes in all the dataset's epochs to time zero? I know this may sound very messy, but I should be able to set up this decoding analysis this way too, without losing any event codes.
>>>>>>
>>>>>> Thanks so much for your help!
>>>>>>
>>>>>> Renzo
>>>>>>
>>>>>> [From:][Cédric Cannard](mailto:ccannard at protonmail.com)
>>>>>>
>>>>>> Sent: 23 September 2020 23:37
>>>>>>
>>>>>> To: [Clement Lee](mailto:cll008 at eng.ucsd.edu)
>>>>>>
>>>>>> Cc: [Renzo Lanfranco](mailto:renzo.lanfranco at gmail.com); [EEGLAB List](mailto:eeglablist at sccn.ucsd.edu)
>>>>>>
>>>>>> Subject: Re: [Eeglablist] Creating new event codes based on previous combination of event codes in each trial
>>>>>>
>>>>>> Hi Renzo,
>>>>>>
>>>>>> I agree with Clement, you normally want to keep the event names as they refer to the same type of stimulus/response across epochs, and it is easier to analyze event-related activity like this than if they all have different numbers.
>>>>>>
>>>>>> So I wouldn't recommend it, but if you just want to just rename them in a linear growing manner (not sure how you want to rename them exactly), you can do so with something like this:
>>>>>>
>>>>>> for iEvent = 1:size(EEG.event,2)
>>>>>>
>>>>>> EEG.event(iEvent).type = num2str(iEvent);
>>>>>>
>>>>>> end
>>>>>>
>>>>>> Cédric
>>>>>>
>>>>>> ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
>>>>>>
>>>>>> On Wednesday, September 23, 2020 1:43 PM, Clement Lee <cll008 at eng.ucsd.edu> wrote:
>>>>>>
>>>>>>> Hi Renzo,
>>>>>>
>>>>>>>
>>>>>>
>>>>>>> What are you trying to accomplish by recoding the stimulus event to contain
>>>>>>
>>>>>>> information about the response? Depending on your goal, there may be easier
>>>>>>
>>>>>>> or more common pipelines to follow.
>>>>>>
>>>>>>> Have you looked through the EEGLAB wiki's tutorial pages?
>>>>>>
>>>>>>> https://sccn.ucsd.edu/wiki/I.Single_subject_data_processing_tutorial
>>>>>>
>>>>>>> https://sccn.ucsd.edu/wiki/I.Single_subject_data_processing_tutorial.
>>>>>>
>>>>>>> Particularly, Ch. 3 (https://sccn.ucsd.edu/wiki/Chapter_03:_Event_Processing
>>>>>>
>>>>>>> ) seems relevant in your case.
>>>>>>
>>>>>>>
>>>>>>
>>>>>>> Best,
>>>>>>
>>>>>>> Clement Lee
>>>>>>
>>>>>>> Applications Programmer
>>>>>>
>>>>>>> Swartz Center for Computational Neuroscience
>>>>>>
>>>>>>> Institute for Neural Computation, UC San Diego
>>>>>>
>>>>>>> 858-822-7535
>>>>>>
>>>>>>>
>>>>>>
>>>>>>> On Wed, Sep 23, 2020 at 12:20 PM Renzo Lanfranco renzo.lanfranco at gmail.com
>>>>>>
>>>>>>> wrote:
>>>>>>
>>>>>>>
>>>>>>
>>>>>>> > Hi everybody,
>>>>>>
>>>>>>> > Thanks in advance. I was hoping someone could lend me a hand. I need to
>>>>>>
>>>>>>> > perform the following analysis and don't know how:
>>>>>>
>>>>>>> > This is for an EEG decoding analysis, but the EEG data (Biosemi 64) was
>>>>>>
>>>>>>> > pre-processed in EEGLAB. Each epoch has two relevant event codes: the
>>>>>>
>>>>>>> > stimulus class code (printed at time zero) and a response type code
>>>>>>
>>>>>>> > (printed at the moment the participant pressed a key). Therefore, the
>>>>>>
>>>>>>> > second event code can vary in time whereas the first event code doesn't.
>>>>>>
>>>>>>> > What do I need to do?
>>>>>>
>>>>>>> > Based on these event codes, I need to create new event codes for every
>>>>>>
>>>>>>> > trial and print new codes at time zero that can comprise the previous event
>>>>>>
>>>>>>> > codes. For example, if event code at time zero can be 1, 2 or 3, and
>>>>>>
>>>>>>> > response code printed later can also be 4, 5 or 6., I now need to have
>>>>>>
>>>>>>> > event codes at time zeroes that account for all those combinations, e.g.
>>>>>>
>>>>>>> > 14, 15, 16, 24, 25, 26, 34, 35, and 36.
>>>>>>
>>>>>>> > Any ideas how can I accomplish this? I don't have much experience working
>>>>>>
>>>>>>> > with EEGLAB structures.
>>>>>>
>>>>>>> > Thanks so much,
>>>>>>
>>>>>>> > R
>>>>>>
>>>>>>> >
>>>>>>
>>>>>>> > Eeglablist page: http://sccn.ucsd.edu/eeglab/eeglabmail.html
>>>>>>
>>>>>>> > To unsubscribe, send an empty email to
>>>>>>
>>>>>>> > eeglablist-unsubscribe at sccn.ucsd.edu
>>>>>>
>>>>>>> > For digest mode, send an email with the subject "set digest mime" to
>>>>>>
>>>>>>> > eeglablist-request at sccn.ucsd.edu
>>>>>>
>>>>>>>
>>>>>>
>>>>>>> Eeglablist page: http://sccn.ucsd.edu/eeglab/eeglabmail.html
>>>>>>
>>>>>>> To unsubscribe, send an empty email to eeglablist-unsubscribe at sccn.ucsd.edu
>>>>>>
>>>>>>> For digest mode, send an email with the subject "set digest mime" to eeglablist-request at sccn.ucsd.edu
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: Stim_PAS_event_relist_new.m
URL: <http://sccn.ucsd.edu/pipermail/eeglablist/attachments/20201012/f68ae393/attachment.ksh>


More information about the eeglablist mailing list