# -*- coding: utf-8 -*-
from warnings import warn
import matplotlib.gridspec
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from ..epochs import epochs_create, epochs_to_array, epochs_to_df
from ..misc import NeuroKitWarning
from ..stats import standardize
[docs]
def eog_plot(eog_signals, info=None):
"""**Visualize EOG data**
Parameters
----------
eog_signals : DataFrame
DataFrame obtained from :func:`.eog_process`.
info : dict
The information Dict returned by ``eog_process()``. Defaults to ``None``.
See Also
--------
eog_process
Returns
-------
Though the function returns nothing, the figure can be retrieved and saved as follows:
.. code-block:: console
# To be run after eog_plot()
fig = plt.gcf()
fig.savefig("myfig.png")
Examples
--------
.. ipython:: python
import neurokit2 as nk
# Simulate data
eog_signal = nk.data('eog_100hz')
# Process signal
eog_signals, info = nk.eog_process(eog_signal, sampling_rate=100)
# Plot
@savefig p_eog_plot.png scale=100%
nk.eog_plot(eog_signals, info)
@suppress
plt.close()
"""
if info is None:
warn(
"'info' dict not provided. Some information might be missing."
+ " Sampling rate will be set to 1000 Hz.",
category=NeuroKitWarning,
)
info = {
"sampling_rate": 1000,
}
# Sanity-check input.
if not isinstance(eog_signals, pd.DataFrame):
raise ValueError(
"NeuroKit error: eog_plot(): The `eog_signals` argument must"
" be the DataFrame returned by `eog_process()`."
)
# Prepare figure
x_axis = np.linspace(
0, eog_signals.shape[0] / info["sampling_rate"], eog_signals.shape[0]
)
gs = matplotlib.gridspec.GridSpec(2, 2, width_ratios=[1 - 1 / np.pi, 1 / np.pi])
fig = plt.figure(constrained_layout=False)
ax0 = fig.add_subplot(gs[0, :-1])
ax1 = fig.add_subplot(gs[1, :-1])
ax2 = fig.add_subplot(gs[:, -1])
ax0.set_xlabel("Time (seconds)")
ax1.set_xlabel("Time (seconds)")
ax2.set_xlabel("Time (seconds)")
fig.suptitle("Electrooculography (EOG)", fontweight="bold")
plt.tight_layout(h_pad=0.3, w_pad=0.2)
# Plot cleaned and raw EOG
ax0.set_title("Raw and Cleaned Signal")
ax0.plot(x_axis, eog_signals["EOG_Raw"], color="#B0BEC5", label="Raw", zorder=1)
ax0.plot(
x_axis,
eog_signals["EOG_Clean"],
color="#49A4FD",
label="Cleaned",
zorder=1,
linewidth=1.5,
)
ax0.set_ylabel("Amplitude (mV)")
# Plot blinks
blinks = np.where(eog_signals["EOG_Blinks"] == 1)[0]
ax0.scatter(
x_axis[blinks],
eog_signals["EOG_Clean"][blinks],
color="#0146D7",
label="Blinks",
zorder=2,
)
ax0.legend(loc="upper right")
# Rate
ax1.set_title("Blink Rate")
ax1.set_ylabel("Blinks per minute")
blink_rate_mean = eog_signals["EOG_Rate"].mean()
ax1.plot(
x_axis, eog_signals["EOG_Rate"], color="#9C5AFF", label="Rate", linewidth=1.5
)
ax1.axhline(y=blink_rate_mean, label="Mean", linestyle="--", color="#CEAFFF")
ax1.legend(loc="upper right")
# Plot individual blinks
ax2.set_title("Individual Blinks")
# Create epochs
events = epochs_create(
eog_signals["EOG_Clean"],
info["EOG_Blinks"],
sampling_rate=info["sampling_rate"],
epochs_start=-0.3,
epochs_end=0.7,
)
events_array = epochs_to_array(events) # Convert to 2D array
events_array = standardize(
events_array
) # Rescale so that all the blinks are on the same scale
blinks_df = epochs_to_df(events)
blinks_wide = blinks_df.pivot(index="Time", columns="Label", values="Signal")
blinks_wide = standardize(blinks_wide)
cmap = iter(plt.cm.RdBu(np.linspace(0, 1, num=len(events))))
for x, color in zip(blinks_wide, cmap):
ax2.plot(blinks_wide[x], color=color, linewidth=0.4, zorder=1)
# Plot with their median (used here as a robust average)
ax2.plot(
np.array(blinks_wide.index),
np.median(events_array, axis=1),
linewidth=2,
linestyle="--",
color="black",
label="Median",
)
ax2.legend(loc="upper right")