R functions for checking and fixing vmrk files from BrainVision

Electroencephalography (EEG) has become a cornerstone for understanding the intricate workings of the human brain in the field of neuroscience. However, EEG software and hardware come with their own set of constraints, particularly in the management of markers, also known as triggers. This article aims to shed light on these limitations and future prospects of marker management in EEG studies, while also introducing R functions that can help deal with vmrk files from BrainVision.

Markers, serving as timestamps that indicate specific events during data collection, play a crucial role in EEG studies. These events could range from the onset of a stimulus to the participant’s response. However, one of the major constraints in current EEG systems is the limitation of markers to numbers between 1 and 255. This limitation is due to the fact that markers are typically stored as 8-bit unsigned integers in computer memory, which can only represent numbers in the range of 0 to 255. However, the number 0 is usually reserved for system use, leaving only the numbers 1 to 255 available for markers.

This numerical constraint can pose significant challenges in the interpretation of markers, especially in complex experimental designs where a multitude of events need to be marked and differentiated. It necessitates careful documentation of each marker’s purpose prior to running the study. This means that researchers must meticulously map each number to a specific event or condition in their experiment, which can be a daunting task, especially for complex studies with numerous conditions and events.

Looking towards the future, one might wonder if it will become possible to send markers with semantic information, instead of being constrained to numbers between 1 and 255. This would allow researchers to encode more detailed information in each marker, such as the type of stimulus presented or the specific condition being tested. Such a development could revolutionize the way we conduct and analyze EEG studies, offering greater flexibility in experimental design and more nuanced insights into brain activity.

Below, we’ll demonstrate some functions from this GitHub repository that help inspect and fix vmrk files. We’ll work with the vmrk file shown below.

# Read the file into a vector of lines
readLines('https://raw.githubusercontent.com/pablobernabeu/EEG-tools-and-tips/main/example.vmrk')
##  [1] "Brain Vision Data Exchange Marker File, Version 1.0"                               
##  [2] ""                                                                                  
##  [3] "[Common Infos]"                                                                    
##  [4] "DataFile=3.eeg"                                                                    
##  [5] "Codepage=utf-8"                                                                    
##  [6] ""                                                                                  
##  [7] "[Marker Infos]"                                                                    
##  [8] "; Each entry: Mk<Marker number>=<Type>,<Description>,<Position in data points>,"   
##  [9] "; <Size in data points>, <Channel number (0 = marker is related to all channels)>,"
## [10] "; <Date (YYYYMMDDhhmmssuuuuuu)>"                                                   
## [11] "; Fields are delimited by commas, some fields might be omited (empty)."            
## [12] "; Commas in type or description text are coded as \"\\1\"."                        
## [13] "Mk1=New Segment,,1,1,0,20240318111955090000"                                       
## [14] "Mk2=Stimulus,S254,20419,1,0"                                                       
## [15] "Mk3=Stimulus,S  5,22332,1,0"                                                       
## [16] "Mk4=Stimulus,S 42,23095,1,0"                                                       
## [17] "Mk5=Stimulus,S143,23100,1,0"                                                       
## [18] "Mk6=Stimulus,S  2,23106,1,0"                                                       
## [19] "Mk7=Stimulus,S102,23111,1,0"                                                       
## [20] "Mk8=Stimulus,S  6,25882,1,0"                                                       
## [21] "Mk9=Stimulus,S  5,28106,1,0"                                                       
## [22] "Mk10=Stimulus,S 50,29053,1,0"                                                      
## [23] "Mk11=Stimulus,S241,29058,1,0"                                                      
## [24] "Mk12=Stimulus,S  1,29063,1,0"                                                      
## [25] "Mk13=Stimulus,S101,29069,1,0"                                                      
## [26] "Mk14=Stimulus,S  6,31830,1,0"                                                      
## [27] "Mk15=Stimulus,S  5,34056,1,0"                                                      
## [28] "Mk16=Stimulus,S 49,35055,1,0"                                                      
## [29] "Mk17=Stimulus,S226,35060,1,0"                                                      
## [30] "Mk18=Stimulus,S  2,35066,1,0"                                                      
## [31] "Mk19=Stimulus,S103,35071,1,0"                                                      
## [32] "Mk20=Stimulus,S  6,37242,1,0"                                                      
## [33] "Mk21=Stimulus,S  5,39436,1,0"                                                      
## [34] "Mk22=Stimulus,S 43,40417,1,0"                                                      
## [35] "Mk23=Stimulus,S155,40423,1,0"                                                      
## [36] "Mk24=Stimulus,S  2,40429,1,0"                                                      
## [37] "Mk25=Stimulus,S103,40434,1,0"                                                      
## [38] "Mk26=Stimulus,S  6,42481,1,0"                                                      
## [39] "Mk27=Stimulus,S  5,44662,1,0"                                                      
## [40] "Mk28=Stimulus,S 40,45678,1,0"                                                      
## [41] "Mk29=Stimulus,S118,45683,1,0"                                                      
## [42] "Mk30=Stimulus,S  1,45688,1,0"                                                      
## [43] "Mk31=Stimulus,S103,45693,1,0"                                                      
## [44] "Mk32=Stimulus,S  6,47621,1,0"                                                      
## [45] "Mk33=Stimulus,S  5,49809,1,0"                                                      
## [46] "Mk34=Stimulus,S 50,50808,1,0"                                                      
## [47] "Mk35=Stimulus,S237,50813,1,0"                                                      
## [48] "Mk36=Stimulus,S  3,50818,1,0"                                                      
## [49] "Mk37=Stimulus,S101,50823,1,0"                                                      
## [50] "Mk38=Stimulus,S  6,53823,1,0"                                                      
## [51] "Mk39=Stimulus,S  5,56042,1,0"                                                      
## [52] "Mk40=Stimulus,S 40,57129,1,0"                                                      
## [53] "Mk41=Stimulus,S114,57134,1,0"                                                      
## [54] "Mk42=Stimulus,S  3,57140,1,0"                                                      
## [55] "Mk43=Stimulus,S103,57145,1,0"                                                      
## [56] "Mk44=Stimulus,S  6,59661,1,0"


Numbering trials

The antediluvian limitation of markers often prevents us from storing the order of trials using markers. Thus, when we need to inspect or fix vmrk files, we must mentally divide the lines into trials. For instance, in our example vmrk file, all trials begin with the marker S 5. The function below allows us to temporarily number trials by appending the number to the first marker of each trial. The parameters of the function allow us to select the start_line to skip the metadata at the top of the vmrk file, as well as to select the number of lines_per_trial and the first_number to use in the first trial.

# Create temporary vmrk file with numbered trials

source('https://raw.githubusercontent.com/pablobernabeu/EEG-tools-and-tips/main/number_trials.R')

number_trials('https://raw.githubusercontent.com/pablobernabeu/EEG-tools-and-tips/main/example.vmrk', 
              start_line = 15, lines_per_trial = 6, first_number = 1)
##  [1] "Brain Vision Data Exchange Marker File, Version 1.0"                               
##  [2] ""                                                                                  
##  [3] "[Common Infos]"                                                                    
##  [4] "DataFile=3.eeg"                                                                    
##  [5] "Codepage=utf-8"                                                                    
##  [6] ""                                                                                  
##  [7] "[Marker Infos]"                                                                    
##  [8] "; Each entry: Mk<Marker number>=<Type>,<Description>,<Position in data points>,"   
##  [9] "; <Size in data points>, <Channel number (0 = marker is related to all channels)>,"
## [10] "; <Date (YYYYMMDDhhmmssuuuuuu)>"                                                   
## [11] "; Fields are delimited by commas, some fields might be omited (empty)."            
## [12] "; Commas in type or description text are coded as \"\\1\"."                        
## [13] "Mk1=New Segment,,1,1,0,20240318111955090000"                                       
## [14] "Mk2=Stimulus,S254,20419,1,0"                                                       
## [15] "Mk3=Stimulus,S  5,22332,1,0  1"                                                    
## [16] "Mk4=Stimulus,S 42,23095,1,0"                                                       
## [17] "Mk5=Stimulus,S143,23100,1,0"                                                       
## [18] "Mk6=Stimulus,S  2,23106,1,0"                                                       
## [19] "Mk7=Stimulus,S102,23111,1,0"                                                       
## [20] "Mk8=Stimulus,S  6,25882,1,0"                                                       
## [21] "Mk9=Stimulus,S  5,28106,1,0  2"                                                    
## [22] "Mk10=Stimulus,S 50,29053,1,0"                                                      
## [23] "Mk11=Stimulus,S241,29058,1,0"                                                      
## [24] "Mk12=Stimulus,S  1,29063,1,0"                                                      
## [25] "Mk13=Stimulus,S101,29069,1,0"                                                      
## [26] "Mk14=Stimulus,S  6,31830,1,0"                                                      
## [27] "Mk15=Stimulus,S  5,34056,1,0  3"                                                   
## [28] "Mk16=Stimulus,S 49,35055,1,0"                                                      
## [29] "Mk17=Stimulus,S226,35060,1,0"                                                      
## [30] "Mk18=Stimulus,S  2,35066,1,0"                                                      
## [31] "Mk19=Stimulus,S103,35071,1,0"                                                      
## [32] "Mk20=Stimulus,S  6,37242,1,0"                                                      
## [33] "Mk21=Stimulus,S  5,39436,1,0  4"                                                   
## [34] "Mk22=Stimulus,S 43,40417,1,0"                                                      
## [35] "Mk23=Stimulus,S155,40423,1,0"                                                      
## [36] "Mk24=Stimulus,S  2,40429,1,0"                                                      
## [37] "Mk25=Stimulus,S103,40434,1,0"                                                      
## [38] "Mk26=Stimulus,S  6,42481,1,0"                                                      
## [39] "Mk27=Stimulus,S  5,44662,1,0  5"                                                   
## [40] "Mk28=Stimulus,S 40,45678,1,0"                                                      
## [41] "Mk29=Stimulus,S118,45683,1,0"                                                      
## [42] "Mk30=Stimulus,S  1,45688,1,0"                                                      
## [43] "Mk31=Stimulus,S103,45693,1,0"                                                      
## [44] "Mk32=Stimulus,S  6,47621,1,0"                                                      
## [45] "Mk33=Stimulus,S  5,49809,1,0  6"                                                   
## [46] "Mk34=Stimulus,S 50,50808,1,0"                                                      
## [47] "Mk35=Stimulus,S237,50813,1,0"                                                      
## [48] "Mk36=Stimulus,S  3,50818,1,0"                                                      
## [49] "Mk37=Stimulus,S101,50823,1,0"                                                      
## [50] "Mk38=Stimulus,S  6,53823,1,0"                                                      
## [51] "Mk39=Stimulus,S  5,56042,1,0  7"                                                   
## [52] "Mk40=Stimulus,S 40,57129,1,0"                                                      
## [53] "Mk41=Stimulus,S114,57134,1,0"                                                      
## [54] "Mk42=Stimulus,S  3,57140,1,0"                                                      
## [55] "Mk43=Stimulus,S103,57145,1,0"                                                      
## [56] "Mk44=Stimulus,S  6,59661,1,0"


Removing trial numbers

Now, we will unnumber the trials. This can be especially useful after fixing any errors in the markers. For this demo, we’ll use an example file with numbered trials that looks just like the output from number_trials() shown above.

# Remove trial numbers from temporary vmrk file

source('https://raw.githubusercontent.com/pablobernabeu/EEG-tools-and-tips/main/remove_trial_numbers.R')

remove_trial_numbers('https://raw.githubusercontent.com/pablobernabeu/EEG-tools-and-tips/main/example_numbered_trials.vmrk')
##  [1] "Brain Vision Data Exchange Marker File, Version 1.0"                               
##  [2] ""                                                                                  
##  [3] "[Common Infos]"                                                                    
##  [4] "DataFile=3.eeg"                                                                    
##  [5] "Codepage=utf-8"                                                                    
##  [6] ""                                                                                  
##  [7] "[Marker Infos]"                                                                    
##  [8] "; Each entry: Mk<Marker number>=<Type>,<Description>,<Position in data points>,"   
##  [9] "; <Size in data points>, <Channel number (0 = marker is related to all channels)>,"
## [10] "; <Date (YYYYMMDDhhmmssuuuuuu)>"                                                   
## [11] "; Fields are delimited by commas, some fields might be omited (empty)."            
## [12] "; Commas in type or description text are coded as \"\\1\"."                        
## [13] "Mk1=New Segment,,1,1,0,20240318111955090000"                                       
## [14] "Mk2=Stimulus,S254,20419,1,0"                                                       
## [15] "Mk3=Stimulus,S  5,22332,1,0"                                                       
## [16] "Mk4=Stimulus,S 42,23095,1,0"                                                       
## [17] "Mk5=Stimulus,S143,23100,1,0"                                                       
## [18] "Mk6=Stimulus,S  2,23106,1,0"                                                       
## [19] "Mk7=Stimulus,S102,23111,1,0"                                                       
## [20] "Mk8=Stimulus,S  6,25882,1,0"                                                       
## [21] "Mk9=Stimulus,S  5,28106,1,0"                                                       
## [22] "Mk10=Stimulus,S 50,29053,1,0"                                                      
## [23] "Mk11=Stimulus,S241,29058,1,0"                                                      
## [24] "Mk12=Stimulus,S  1,29063,1,0"                                                      
## [25] "Mk13=Stimulus,S101,29069,1,0"                                                      
## [26] "Mk14=Stimulus,S  6,31830,1,0"                                                      
## [27] "Mk15=Stimulus,S  5,34056,1,0"                                                      
## [28] "Mk16=Stimulus,S 49,35055,1,0"                                                      
## [29] "Mk17=Stimulus,S226,35060,1,0"                                                      
## [30] "Mk18=Stimulus,S  2,35066,1,0"                                                      
## [31] "Mk19=Stimulus,S103,35071,1,0"                                                      
## [32] "Mk20=Stimulus,S  6,37242,1,0"                                                      
## [33] "Mk21=Stimulus,S  5,39436,1,0"                                                      
## [34] "Mk22=Stimulus,S 43,40417,1,0"                                                      
## [35] "Mk23=Stimulus,S155,40423,1,0"                                                      
## [36] "Mk24=Stimulus,S  2,40429,1,0"                                                      
## [37] "Mk25=Stimulus,S103,40434,1,0"                                                      
## [38] "Mk26=Stimulus,S  6,42481,1,0"                                                      
## [39] "Mk27=Stimulus,S  5,44662,1,0"                                                      
## [40] "Mk28=Stimulus,S 40,45678,1,0"                                                      
## [41] "Mk29=Stimulus,S118,45683,1,0"                                                      
## [42] "Mk30=Stimulus,S  1,45688,1,0"                                                      
## [43] "Mk31=Stimulus,S103,45693,1,0"                                                      
## [44] "Mk32=Stimulus,S  6,47621,1,0"                                                      
## [45] "Mk33=Stimulus,S  5,49809,1,0"                                                      
## [46] "Mk34=Stimulus,S 50,50808,1,0"                                                      
## [47] "Mk35=Stimulus,S237,50813,1,0"                                                      
## [48] "Mk36=Stimulus,S  3,50818,1,0"                                                      
## [49] "Mk37=Stimulus,S101,50823,1,0"                                                      
## [50] "Mk38=Stimulus,S  6,53823,1,0"                                                      
## [51] "Mk39=Stimulus,S  5,56042,1,0"                                                      
## [52] "Mk40=Stimulus,S 40,57129,1,0"                                                      
## [53] "Mk41=Stimulus,S114,57134,1,0"                                                      
## [54] "Mk42=Stimulus,S  3,57140,1,0"                                                      
## [55] "Mk43=Stimulus,S103,57145,1,0"                                                      
## [56] "Mk44=Stimulus,S  6,59661,1,0"


Counting markers

source('https://raw.githubusercontent.com/pablobernabeu/EEG-tools-and-tips/main/count_markers.R')

count_markers(file = 'https://raw.githubusercontent.com/pablobernabeu/EEG-tools-and-tips/main/example.vmrk', 
              marker = 'S  2')
## Count of "S  2": 3 instances
count_markers(file = 'https://raw.githubusercontent.com/pablobernabeu/EEG-tools-and-tips/main/example.vmrk', 
              marker = 'S  3')
## Count of "S  3": 2 instances


comments powered by Disqus