Waveform plots
EEGPhasePy provides a helper function to plot the pre/post-trigger waveform
average with a standard deviation highlight. The function returns a
matplotlib.figure.Figure object, so you can continue customizing it
after creation.
Basic usage
If you already have an EEGPhasePy estimator fitted to your data, the simplest
path is plot_mean_std_waveform_from_triggers().
Pass your raw EEG array, the sample indices where each trigger fired, and the
time window (in seconds) to include on either side of t = 0:
waveform_fig = etp.plot_mean_std_waveform_from_triggers(
testing_signal, triggers, tmin=0.1, tmax=0.1
)
You can also plot directly from a 2-D array of waveform segments using
EEGPhasePy.viz.plot_waveform_average() — useful when you have
already extracted epochs or want to skip the estimator entirely:
import numpy as np
import scipy.signal as signal
import EEGPhasePy.viz as viz
fs = 2000
time_data = np.arange(0, 30, 1 / fs)
raw = np.sin(2 * np.pi * 10 * time_data) + 0.3 * np.random.default_rng(0).standard_normal(len(time_data))
peaks = signal.find_peaks(np.sin(2 * np.pi * 10 * time_data))[0]
win_samples = int(0.1 * fs)
segments = [
raw[p - win_samples: p + win_samples]
for p in peaks
if p - win_samples >= 0 and p + win_samples < len(raw)
]
waveforms = np.array(segments)
fig = viz.plot_waveform_average(waveforms, fs, t_trigger=win_samples)
(Source code, png, hires.png, pdf)
Basic waveform average
Hiding the standard deviation highlight
Pass show_std=False to suppress the shaded region and show only the mean
waveform:
import numpy as np
import scipy.signal as signal
import EEGPhasePy.viz as viz
fs = 2000
time_data = np.arange(0, 30, 1 / fs)
raw = np.sin(2 * np.pi * 10 * time_data) + 0.3 * np.random.default_rng(0).standard_normal(len(time_data))
peaks = signal.find_peaks(np.sin(2 * np.pi * 10 * time_data))[0]
win_samples = int(0.1 * fs)
segments = [
raw[p - win_samples: p + win_samples]
for p in peaks
if p - win_samples >= 0 and p + win_samples < len(raw)
]
waveforms = np.array(segments)
fig = viz.plot_waveform_average(waveforms, fs, t_trigger=win_samples, show_std=False)
(Source code, png, hires.png, pdf)
Mean waveform without standard deviation
Color customization
plot_waveform_average() accepts color for the
waveform line and std_color for the shaded region. Both accept any
matplotlib color: a named string, a hex code, or an RGB tuple.
When std_color is not set it inherits from color.
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
import EEGPhasePy.viz as viz
fs = 2000
time_data = np.arange(0, 30, 1 / fs)
raw = np.sin(2 * np.pi * 10 * time_data) + 0.3 * np.random.default_rng(0).standard_normal(len(time_data))
peaks = signal.find_peaks(np.sin(2 * np.pi * 10 * time_data))[0]
win_samples = int(0.1 * fs)
segments = [
raw[p - win_samples: p + win_samples]
for p in peaks
if p - win_samples >= 0 and p + win_samples < len(raw)
]
waveforms = np.array(segments)
# Purple waveform with a separate orange std shading
fig = viz.plot_waveform_average(
waveforms, fs, t_trigger=win_samples,
color="#7B2D8B",
std_color="#F4A300",
)
(Source code, png, hires.png, pdf)
Custom line and shading colors
Advanced matplotlib customization
The function returns a standard matplotlib.figure.Figure, so you
can reach into its axes and apply any matplotlib customization after the fact.
Post-hoc axes edits
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
import EEGPhasePy.viz as viz
fs = 2000
time_data = np.arange(0, 30, 1 / fs)
raw = np.sin(2 * np.pi * 10 * time_data) + 0.3 * np.random.default_rng(0).standard_normal(len(time_data))
peaks = signal.find_peaks(np.sin(2 * np.pi * 10 * time_data))[0]
win_samples = int(0.1 * fs)
segments = [
raw[p - win_samples: p + win_samples]
for p in peaks
if p - win_samples >= 0 and p + win_samples < len(raw)
]
waveforms = np.array(segments)
fig = viz.plot_waveform_average(waveforms, fs, t_trigger=win_samples)
ax = fig.axes[0]
ax.set_title("Mu-band waveform average — C3")
ax.axvline(0, color="gray", linestyle="--", linewidth=0.8, label="Trigger")
ax.legend()
ax.spines[["top", "right"]].set_visible(False)
(Source code, png, hires.png, pdf)
Customizing the returned figure
Global style sheets
Apply a matplotlib.pyplot.style.use() call before plotting and the
style will take effect inside the function, since the figure is created on the
call:
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
import EEGPhasePy.viz as viz
fs = 2000
time_data = np.arange(0, 30, 1 / fs)
raw = np.sin(2 * np.pi * 10 * time_data) + 0.3 * np.random.default_rng(0).standard_normal(len(time_data))
peaks = signal.find_peaks(np.sin(2 * np.pi * 10 * time_data))[0]
win_samples = int(0.1 * fs)
segments = [
raw[p - win_samples: p + win_samples]
for p in peaks
if p - win_samples >= 0 and p + win_samples < len(raw)
]
waveforms = np.array(segments)
plt.style.use("ggplot")
fig = viz.plot_waveform_average(waveforms, fs, t_trigger=win_samples)
plt.style.use("default") # reset so other plots in the session are unaffected
(Source code, png, hires.png, pdf)
Using a matplotlib style sheet
Note
Because the figure is created inside the function, you cannot pass a
pre-existing Axes to embed the waveform plot
in a larger subplot grid. To work around this, create your subplot grid
first, call plot_waveform_average() to get the
figure, copy its axes content, and paste it into your target axes — or
simply save the returned figure and assemble a composite image afterwards.