BCI2000Tools.EventRelated
Analysis of Event-Related Potentials from BCI2000 Files with Python
These instructions assume you are OK with typing commands at a command prompt. If you are not, read this: https://bitbucket.org/jezhill/doc/wiki/CommandLine
1. Obtain the code
BCI2000Tools is a set of Python modules and command-line programs. It is
part of the BCI2000 distribution, where it resides inside the tools/python
directory. If you already have these files, that's great. If you still need to download them, the best way to do it is by using Subversion,
a.k.a. svn:
- On Windows, you should download and install TortoiseSVN, and during installation, remember to explicitly select "command line client tools" because the installer might not select by default. After installation, start a whole new Command Prompt.
- macOS may already come with a command-line svn built-in, or you may need
to install the "XCode Command-line Tools" with sudo xcode-select --install.
If all else fails you can install https://brew.sh and then brew install svn.
Once you have subversion, you will need a BCI2000 username and password: if you do not already have one, go to https://www.bci2000.org/useradmin/
When you are ready, decide where you're going to put the BCI2000 files. You do not need a separate copy for every project (you could, but that could lead to version-confusion very easily in future). Pick a place, then choose whether to download the whole (quite large) BCI2000 source distribution:
svn checkout https://bci2000.org/svn/trunk bci2000-svn
or just the minimal set of files needed for Python:
svn checkout https://bci2000.org/svn/trunk/tools/python bci2000-tools-python
If you are going to use the real-time BCI2000 system on this computer, there are advantages to going the first route and keeping everything in one place. If this computer is only going to be used for analysis, then the second route is fine.
2. Tell Python where the code is
Let's assume that when you type python at the command-line, you get the intended
version of Python, in the environment you are comfortable with (with all the sciencey
third-party packages you're accustomed to for your other analyses). Getting to this
point is non-trivial in itself and will not be covered here, except to say:
on Windows, maybe download and install Anaconda, then launch the "Anaconda Prompt"?
On a non-Windows system, maybe you need to be typing python3 instead of python?
Maybe it's a good idea to set up a virtual environment first, then activate that?
The hardest program to write in Python is "Hello World" and this document unfortunately
cannot help with that. Things have got somewhat better since https://xkcd.com/1987
but there's probably still some way to go.
First change your working directory to the directory you just checked out with svn. For example:
cd bci2000-tools-python
if that's what you called it on the checkout line. Or maybe it's:
cd C:\Somewhere\Somewhere\Somewhere\bci2000-svn\tools\python
if you're on Windows and you checked out the whole distro. Either way, you should now
be working in the directory that contains the file setup.py. From there, you type:
python -m pip install -e .
Make sure to include the -e. And the space and the dot at the end. In fact, include
all the words and all punctuation: computers don't do the right thing unless the
command is exactly right, you know that. Copy-and-paste is your friend.
The -e causes your Python distribution (or virtual environment) to make a note of
where the BCI2000Tools reside, so in future Python will be able know what to reach for
when you import BCI2000Tools.EventRelated or %run -m BCI2000Tools.EventRelated.
The advantage of doing it this way is that you can later get bugfixes and updates simply
by running the command svn update from that directory. The one thing that could go
wrong is that, after telling Python where the files are, you decide to drag and move them
somewhere else. Then Python will not know where to find them any more, and you'll have to
tell it again.
3. Invoke BCI2000Tools.EventRelated
You can invoke the BCI2000Tools.EventRelated code in various different ways. From
your system command prompt:
python -m BCI2000Tools.EventRelated ...
or from the IPython command prompt (after launching with python -m IPython):
%run -m BCI2000Tools.EventRelated ...
or from your own Python program:
from BCI2000Tools.EventRelated import EpochSet x = EpochSet( ... )
These are all roughly equivalent. The command-line invocations that use
-m BCI2000Tools.EventRelated merely translate your command-line arguments into
parameters that get passed to the EpochSet constructor, creating an EpochSet
instance that happens to be called self (if you're in IPython, you can then
reassign it to a more meaningfully-named variable and continue from there).
In all cases the ... stands for additional arguments. The main arguments will
be names of (or paths to) BCI2000 .dat files. Various other options are
explained from the command-line help (let's assume you're using IPython):
%run -m BCI2000Tools.EventRelated . --help
Note that BCI2000Tools.EventRelated produces interactive plots by default:
you can click on the raster-plot to see the waveform an scalp topography that
cut through the time and place you select. If you are running IPython in a
"notebook" interface, you may need to run the %matplotlib notebook or
%matplotlib widget command, or otherwise enable interactivity in your notebook
after consulting the relevant documentation.
Here is a simple example command-line:
%run -m BCI2000Tools.EventRelated testS001R@.dat -t DigitalInput1 -p 2-1B
The @ symbol equivalent to a *—so this example will match all files that
conform to the pattern testS001R*.dat—but unlike * it will not get
intercepted and expanded by IPython itself.
The -t option (a.k.a. --trigger) is critical. It specifies the name of a
channel or state variable whose value becomes non-zero whenever a stimulus event
occurs. You could use the StimulusCode state variable itself here, but then
you are relying on software timing; you will get much better results if you use
a digital trigger activated by some kind of trigger box that senses the light or
sound signal in hardware. In the example above, we are imagining that the trigger
pulse got digitized into the DigitalInput1 state variable, which is provided by
BCI2000 modules that support g.tec devices. Once the program has used this to
establish when an event occurred, it will work backwards to find the most
recent change of the StimulusCode state variable to a non-zero value, and read
that value to determine what kind of event occurred.
The -p option (a.k.a. --plot) signifies that a plot is required, but it also
takes an argument that specifies what should be plotted. The example string here,
2-1B, is a densely coded shorthand that translates to "subtract the average of
StimulusCode=1 events from the average of StimulusCode=2 events, and perform
subtractive baseline correction". Obviously, you need to know what StimulusCode
value corresponds to what stimulus in your experiment, and adjust accordingly.
You can pool stimulus codes, you can plot average responses with or without
contrasting, you can turn baseline correction on or off, you can z-score, you can
plot signed r-squared values. All of these options are explained in the
documentation for the Processing class, which in IPython can be examined by
saying:
from BCI2000Tools.EventRelated import Processing Processing?
or:
%run -m BCI2000Tools.EventRelated . --help-processing
It is also worth emphasizing the role of the -c option (a.k.a.
--highlightChannel): this gives you versatile options for automatically
picking positive and/or negative peaks within certain spatial and temporal
constraints, and initializing the interactive plot at that location. In doing
so, the program also attaches the results of its search to self.highlighted
for later examination and processing. Like the -p option, the -c option
also takes a shorthand argument: read the --help.
Example Output
> python -m IPython
In [1]: run -m BCI2000Tools.EventRelated S05S005R@.dat -t DigitalInput3 -d A2 -p 1-2ZN -c Pz+@250-600 -s "Auditory (Sham Stim.)"