<jupyter_start><jupyter_text>Emotiv EEG Data Visualization OptionsA short overview of what's possible with the MNE library and what we should focus on including into the first iteration of the BrainWaves app.<jupyter_code>from mne import Epochs, find_events, set_eeg_reference, read_epochs, viz, combine_evoked
from time import time, strftime, gmtime
from collections import OrderedDict
from glob import glob
from collections import OrderedDict
from mne import create_info, concatenate_raws
from mne.io import RawArray
from mne.channels import read_montage
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import sys, os
sys.path.append(os.path.join(os.path.dirname(os.getcwd()), 'app','utils','jupyter'))
import utils
%matplotlib inline
import warnings
warnings.filterwarnings("ignore")<jupyter_output><empty_output><jupyter_text>This is a dataset that has been collected and cleaned in the app. It is comprised of two 2-minute runs of the Faces Houses experiment and, although it doesn't show a classic N170, there is some interesting event-related potential information in the data. It actually looks like there may be P300s.<jupyter_code>epochs = read_epochs('/home/dano/BrainWaves Workspaces/Dano Nelson Faces Houses/Data/Subash_2-epo.fif')
face_epochs = epochs['Face']
house_epochs = epochs['House']
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from mne.datasets import sample
from mne import read_evokeds

house_evoked = house_epochs.average()
face_evoked = face_epochs.average()<jupyter_output><empty_output><jupyter_text>The way I see it, the students have to demonstrate that they can make three types of comparisons on this screen: comparing between conditions (faces and house, etc.), comparing between channels, and comparing between subjects. This gets a bit complicated because the comparisons between channels and subjects should really be based on the *difference between conditions that they've found by comparing between conditions*I've broken up the different visualizations into these different 'jobs'. I'm not sure which order these tasks should necessarily be completed, but I'm putting them in the order that makes most sense for how I would explore a dataset. Job 1: Comparing Between Conditions  Averaged Epoch Difference PlotThis is our standard, which is good at showing differences between conditions with statistical significance indicated by the colored background confidence interval.However, it kind of sucks because it only displays one channel at a time<jupyter_code># Computation
conditions = OrderedDict({key: [value] for (key, value) in event_id.items()})

# Output
X, y = utils.plot_conditions(epochs, ch_ind=4, conditions=conditions, 
                                ci=97.5, n_boot=1000, title='', diff_waveform=None)<jupyter_output><empty_output><jupyter_text>Epochs SpectrogramThis is the first new interesting viz we could consider using. The colors correspond to the amplitude of the EEG, with red being positive and blue being negative. The epochs are all lined up in rows on the y axis and ERPs should be visible as vertical colored bands.Unfortunately, here we also can only view one plot at a time<jupyter_code>face_epochs.plot_image(title="Faces T7",picks=[3])
house_epochs.plot_image(title="Houses T7",picks=[3])<jupyter_output><empty_output><jupyter_text>Joint PlotThis is a very cool plot that I just discovered. Essentially, it has all the potential comparisons we could make in one plot. The colored lines show each channels average epoch stacked on top of each other ('Butterfly plot'). In addition, there is an algorithm that will automatically find peaks (3 by default) in the data, mark those times, and display a topomap of the EEG at that point in time.I think this could be a great plot to use, but it may be a little overwhelming without much instruction.<jupyter_code>ace_evoked.plot_joint(times="peaks", title="Faces");
house_evoked.plot_joint(times="peaks", title="Houses");<jupyter_output>time_unit defaults to "ms" in 0.16 but will change to "s" in 0.17, set it explicitly to avoid this warning
time_unit defaults to "ms" in 0.16 but will change to "s" in 0.17, set it explicitly to avoid this warning<jupyter_text>Evoked power comparisonThis is an interesting plot that could be used for comparing directly between conditions. It averages over all channels to compute global field power and plots the difference between conditionsWill have to spend more time figuring out how to add legend. A nice example is here: https://martinos.org/mne/stable/auto_tutorials/plot_visualize_evoked.html<jupyter_code>viz.plot_compare_evokeds([house_evoked, face_evoked]);<jupyter_output>No picks, plotting the GFP ...<jupyter_text>Job 2: Comparing Between ChannelsThese should help students pick out which channels are showing the most powerful ERPs and interesting effects  Topographic Map of Averaged EpochsI think this is a fun one that will correspond nicely with our head diagram. All the averaged epochs are spaced out like the electrodes are.Unfortunately, there isn't a convenient way to plot both conditions together on the same map. The best I can do is plot the difference epochs<jupyter_code>diff_evoked = combine_evoked([face_evoked, house_evoked], weights=[1, -1])
house_evoked.plot_topo();
face_evoked.plot_topo();
diff_evoked.plot_topo();<jupyter_output><empty_output><jupyter_text>Averaged Epochs SpectrogramI think this is the easiest way to pick out which channels contained an ERP. However, it's a little bit more complex than a spatial map. Not sure how to go from channel index to channel name, though (I think it's possible, though)<jupyter_code>house_evoked.plot_image(titles="Houses", time_unit="s");
face_evoked.plot_image(titles="Faces", time_unit="s");<jupyter_output><empty_output><jupyter_text>Topomap SeriesThis is a decent way to show what's happening in the different electrode locations during the epoch. However, I think it's prone to displaying a lot of info that's prone to being misinterpreted by students. This kind of viz will also be nearly useless for the Muse because of its low channel count<jupyter_code># set time instants in seconds (from 50 to 150ms in a step of 10ms)
times = np.arange(0.1, 0.5, 0.025)
# compute a 50 ms bin to stabilize topographies
house_evoked.plot_topomap(times, title='Houses',  ch_type='eeg', average=0.025, time_unit='s');
face_evoked.plot_topomap(times, title='Faces',  ch_type='eeg', average=0.025, time_unit='s');<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.06634056863344542, 'fraction_numerical': 0.009477224090492203, 'mean_word_length': 5.938494167550371, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '121353', 'license': 'MIT', 'n_tokens_mistral': 1904, 'n_tokens_neox': 1814, 'n_words': 805, 'path': 'notebooks/N170 Emotiv Exploratory.ipynb', 'repo_name': 'sjburwell/BrainWaves', 'size': '6542'}