Note
Go to the end to download the full example code.
22: Shapes and maps across space¶
Share shapes across channels, map a parameter on the electrodes, and screen volume conduction.
Introduction¶
The earlier tutorials fitted each channel on its own. But channels sit in space, and a
stimulation drives many at once, so there is structure across them. evoparam.spatial
uses it:
shared shapes: find a few waveform shapes that, combined, explain all the channels of one stimulation, instead of a free fit per channel (the “basis profile curves” idea);
parameter maps: put one parameter (amplitude, latency) on the electrode coordinates, ready to plot on the brain;
connectivity: a site-by-channel matrix of a parameter, the input to a connectivity analysis;
a volume-conduction screen: tell a true local response from the passive spread of a big response nearby.
We simulate one stimulation on a 12-electrode grid, most of them responding.
import warnings
import numpy as np
from evoparam import models, spatial
from evoparam.sim import simulate_ccep
trials, _ = simulate_ccep(
20, n_channels=12, p_response=0.7, p_n2=1.0, artifact=False, layout="grid",
sfreq=512.0, seed=0,
) # fmt: skip
with warnings.catch_warnings():
warnings.simplefilter("ignore")
group = models.fit(trials, "ccep", random_state=0)
A parameter map¶
parameter_map returns one row per channel with the chosen parameter and the electrode
coordinates, the table you hand to a brain plot. Here the N1 amplitude of each channel,
with its position.
with warnings.catch_warnings():
warnings.simplefilter("ignore")
amplitude_map = spatial.parameter_map(group, parameter="amplitude", component="N1")
columns = ["channel", "amplitude", "marker"]
print(amplitude_map[columns].round(2).head(8).to_string(index=False))
channel amplitude marker
G01 -310.59 response
G02 NaN no_response
G03 -446.70 response
G04 -286.85 response
G05 -310.01 response
G06 -155.19 response
G07 -417.32 response
G08 -132.48 response
Each row also carries the electrode coordinates (x, y, z) when the montage has
them. plots.plot_parameter_map draws the map; with a full montage it goes on a brain
surface through MNE (tutorial on MNE). Our simulated grid has only partial coordinates, so
here it stays a table.
A connectivity matrix¶
connectivity_matrix lays a parameter out as stimulated site by recorded channel:
with several stimulations it becomes the matrix a connectivity analysis works on (who
drives whom, and how strongly). Here there is one site, so it is one row.
matrix = spatial.connectivity_matrix(group, "amplitude", component="N1")
print(matrix.round(1).to_string())
channel G01 G02 G03 G04 G05 G06 G07 G08 G09 G10 G11 G12
stim_site
-310.6 NaN -446.7 -286.8 -310.0 -155.2 -417.3 -132.5 -195.1 NaN NaN -94.9
Screening for volume conduction¶
A big response on one contact spreads passively to its neighbours (volume conduction);
that spread is not a local response and should not be read as one. screen_volume_conduction
flags it: it checks for a polarity reversal across the contact, how fast the response
decays with distance, and whether a different reference removes it. volume_conduction_risk
is the verdict per channel.
screen = spatial.screen_volume_conduction(trials, group)
columns = ["channel", "distance_mm", "reversal", "decay", "reference", "volume_conduction_risk"]
print(screen[columns].head(8).to_string(index=False))
channel distance_mm reversal decay reference volume_conduction_risk
G01 18.027756 False False False medium
G02 11.180340 False False True high
G03 11.180340 False False False medium
G04 18.027756 False False True high
G05 26.925824 False False False medium
G06 36.400549 False False False medium
G07 46.097722 False False False medium
G08 55.901699 False False True high
A channel with no polarity reversal, a slow decay and a response that survives a change of reference is a real local response (low risk); one that reverses, decays fast and vanishes under another reference is likely passive spread (high risk). Use the screen to drop the passive channels before reading a map as connectivity.
Conclusion¶
The spatial module reads the structure across channels that a per-channel fit ignores: shared shapes group the channels driven alike, parameter maps put the numbers on the anatomy, the connectivity matrix feeds a network analysis, and the volume-conduction screen keeps passive spread out of it. It is the bridge from one stimulation’s fit to a map of the brain.
Total running time of the script: (0 minutes 1.958 seconds)