EEG Topoplots

The eeg_topoplot recipe adds a bit of convenience for plotting Topoplots from EEG data, like drawing a head shape and automatically looking up default positions for known sensors. Otherwise, it supports the same attributes as topoplot.

TopoPlots.eeg_topoplotFunction
eeg_topoplot(data::Vector{<: Real}, labels::Vector{<: AbstractString})

Attributes:

  • positions::Vector{<: Point} = Makie.automatic: Can be calculated from label (channel) names. Currently, only 10/20 montage has default coordinates provided.
  • labels::AbstractVector{<:AbstractString} = Makie.automatic: Add custom labels, when label_text is set to true. If positions is not specified, labels are used to look up the 10/20 coordinates.
  • head = (color=:black, linewidth=3): draw the outline of the head. Set to nothing to not draw the head outline, otherwise set to a namedtuple that get passed down to the line! call that draws the shape.

Some attributes from topoplot are set to different defaults:

  • label_scatter = true
  • contours = true
  • enlarge = 1`

Otherwise the recipe just uses the topoplot defaults and passes through the attributes.

Note

The 10-05 channel locations are "perfect" spherical locations based on https://github.com/sappelhoff/eegpositions/ - the mne-default 10-20 locations are _not, they were warped to a fsaverage head. Which makes the locations provided here good for visualizations, but not good for source localisation.

Note

You MUST set label_text=true for labels to display.

source

For the standard 10/20 (or 10/05) montage, one can drop the positions attribute:

using TopoPlots, CairoMakie

labels = TopoPlots.CHANNELS_10_05 # TopoPlots.CHANNELS_10_20 contains the 10/20 subset

f,ax,h = TopoPlots.eeg_topoplot(rand(348); labels=labels, axis=(aspect=DataAspect(),), label_text=true, label_scatter=(markersize=2, strokewidth=2,),colorrange=[-5,5])
Example block output

If the channels aren't 10/05, one can still plot them, but then the positions need to be passed as well:

data, positions = TopoPlots.example_data()
labels = ["s$i" for i in 1:size(data, 1)]
TopoPlots.eeg_topoplot(data[:, 340, 1]; labels, label_text = true, positions=positions, axis=(aspect=DataAspect(),))
Example block output

Subset of channels

If you only ask to plot a subset of channels, we highly recommend to define your bounding geometry yourself. We follow MNE functionality and normalize the positions prior to interpolation / plotting. If you only use a subset of channels, the positions will be relative to each other, not at absolute coordinates.

f = Figure()
ax1 = f[1,1] = Axis(f;aspect=DataAspect())
ax2 = f[1,2] = Axis(f;aspect=DataAspect())
kwlist = (;label_text=true,label_scatter=(markersize=10, strokewidth=2,color=:white))
TopoPlots.eeg_topoplot!(ax1,[1,0.5,0]; labels=["Cz","Fz","Fp1"],kwlist...)
TopoPlots.eeg_topoplot!(ax2,[1,0.5,05]; labels=["Cz","Fz","Fp1"], bounding_geometry=Circle(Point2f(0.5,0.5), 0.5),kwlist...)

f
Example block output

As visible in the left plot, the positions are normalized to the bounding geometry. The right plot shows the same data, but with Cz correctly centered.

Example data

TopoPlots.example_dataFunction
example_data()

Load EEG example data.

Returns a two-tuple:

  • data: a (64, 400, 3) Float32 array of channel x timepoint x stat array. Timepoints corresponds to samples at 500Hz from -0.3s to 0.5s relative to stimulus onset. Stats are mean over subjects, standard errors over subjects, and associated p-value from a t-test. For demonstration purposes, the first stat dimension is generally the most applicable.
  • positions: a length-64 Point2f vector of positions for each channel in data.

Data source

Ehinger, B. V., König, P., & Ossandón, J. P. (2015). Predictions of Visual Content across Eye Movements and Their Modulation by Inferred Information. The Journal of Neuroscience, 35(19), 7403–7413. https://doi.org/10.1523/JNEUROSCI.5114-14.2015

source