Source code for neurokit2.eda.eda_plot

# -*- coding: utf-8 -*-
from warnings import warn

import matplotlib.collections
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from ..misc import NeuroKitWarning


[docs] def eda_plot(eda_signals, info=None, static=True): """**Visualize electrodermal activity (EDA) data** Parameters ---------- eda_signals : DataFrame DataFrame obtained from :func:`eda_process()`. info : dict The information Dict returned by ``eda_process()``. Defaults to ``None``. static : bool If True, a static plot will be generated with matplotlib. If False, an interactive plot will be generated with plotly. Defaults to True. Returns ------- See :func:`.ecg_plot` for details on how to access the figure, modify the size and save it. Examples -------- .. ipython:: python import neurokit2 as nk eda_signal = nk.eda_simulate(duration=30, scr_number=5, drift=0.1, noise=0, sampling_rate=250) eda_signals, info = nk.eda_process(eda_signal, sampling_rate=250) @savefig p_eda_plot1.png scale=100% nk.eda_plot(eda_signals, info) @suppress plt.close() See Also -------- eda_process """ 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, } # Determine peaks, onsets, and half recovery. peaks = np.where(eda_signals["SCR_Peaks"] == 1)[0] onsets = np.where(eda_signals["SCR_Onsets"] == 1)[0] half_recovery = np.where(eda_signals["SCR_Recovery"] == 1)[0] # clean peaks that do not have onsets if len(peaks) > len(onsets): peaks = peaks[1:] # Determine unit of x-axis. x_label = "Time (seconds)" x_axis = np.linspace(0, len(eda_signals) / info["sampling_rate"], len(eda_signals)) if static: fig, (ax0, ax1, ax2) = plt.subplots(nrows=3, ncols=1, sharex=True) last_ax = fig.get_axes()[-1] last_ax.set_xlabel(x_label) # Plot cleaned and raw electrodermal activity. ax0.set_title("Raw and Cleaned Signal") fig.suptitle("Electrodermal Activity (EDA)", fontweight="bold") ax0.plot(x_axis, eda_signals["EDA_Raw"], color="#B0BEC5", label="Raw", zorder=1) ax0.plot( x_axis, eda_signals["EDA_Clean"], color="#9C27B0", label="Cleaned", linewidth=1.5, zorder=1, ) ax0.legend(loc="upper right") # Plot skin conductance response. ax1.set_title("Skin Conductance Response (SCR)") # Plot Phasic. ax1.plot( x_axis, eda_signals["EDA_Phasic"], color="#E91E63", label="Phasic Component", linewidth=1.5, zorder=1, ) # Mark segments. risetime_coord, amplitude_coord, halfr_coord = _eda_plot_dashedsegments( eda_signals, ax1, x_axis, onsets, peaks, half_recovery ) risetime = matplotlib.collections.LineCollection( risetime_coord, colors="#FFA726", linewidths=1, linestyle="dashed" ) ax1.add_collection(risetime) amplitude = matplotlib.collections.LineCollection( amplitude_coord, colors="#1976D2", linewidths=1, linestyle="solid" ) ax1.add_collection(amplitude) halfr = matplotlib.collections.LineCollection( halfr_coord, colors="#FDD835", linewidths=1, linestyle="dashed" ) ax1.add_collection(halfr) ax1.legend(loc="upper right") # Plot Tonic. ax2.set_title("Skin Conductance Level (SCL)") ax2.plot( x_axis, eda_signals["EDA_Tonic"], color="#673AB7", label="Tonic Component", linewidth=1.5, ) ax2.legend(loc="upper right") else: # Create interactive plot with plotly. try: import plotly.graph_objects as go from plotly.subplots import make_subplots except ImportError as e: raise ImportError( "NeuroKit error: ppg_plot(): the 'plotly'", " module is required when 'static' is False.", " Please install it first (`pip install plotly`).", ) from e fig = make_subplots( rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.05, subplot_titles=( "Raw and Cleaned Signal", "Skin Conductance Response (SCR)", "Skin Conductance Level (SCL)", ), ) # Plot cleaned and raw electrodermal activity. fig.add_trace( go.Scatter( x=x_axis, y=eda_signals["EDA_Raw"], mode="lines", name="Raw", line=dict(color="#B0BEC5"), showlegend=True, ), row=1, col=1, ) fig.add_trace( go.Scatter( x=x_axis, y=eda_signals["EDA_Clean"], mode="lines", name="Cleaned", line=dict(color="#9C27B0"), showlegend=True, ), row=1, col=1, ) # Plot skin conductance response. fig.add_trace( go.Scatter( x=x_axis, y=eda_signals["EDA_Phasic"], mode="lines", name="Phasic Component", line=dict(color="#E91E63"), showlegend=True, ), row=2, col=1, ) # Mark segments. _, _, _ = _eda_plot_dashedsegments( eda_signals, fig, x_axis, onsets, peaks, half_recovery, static=static ) # TODO add dashed segments to plotly version # Plot skin conductance level. fig.add_trace( go.Scatter( x=x_axis, y=eda_signals["EDA_Tonic"], mode="lines", name="Tonic Component", line=dict(color="#673AB7"), showlegend=True, ), row=3, col=1, ) # Add title to entire figure. fig.update_layout(title_text="Electrodermal Activity (EDA)", title_x=0.5) return fig
# ============================================================================= # Internals # ============================================================================= def _eda_plot_dashedsegments( eda_signals, ax, x_axis, onsets, peaks, half_recovery, static=True ): # Mark onsets, peaks, and half-recovery. onset_x_values = x_axis[onsets] onset_y_values = eda_signals["EDA_Phasic"][onsets].values peak_x_values = x_axis[peaks] peak_y_values = eda_signals["EDA_Phasic"][peaks].values halfr_x_values = x_axis[half_recovery] halfr_y_values = eda_signals["EDA_Phasic"][half_recovery].values end_onset = pd.Series( eda_signals["EDA_Phasic"][onsets].values, eda_signals["EDA_Phasic"][peaks].index ) risetime_coord = [] amplitude_coord = [] halfr_coord = [] for i in range(len(onsets)): # Rise time. start = (onset_x_values[i], onset_y_values[i]) end = (peak_x_values[i], onset_y_values[i]) risetime_coord.append((start, end)) for i in range(len(peaks)): # SCR Amplitude. start = (peak_x_values[i], onset_y_values[i]) end = (peak_x_values[i], peak_y_values[i]) amplitude_coord.append((start, end)) for i in range(len(half_recovery)): # Half recovery. end = (halfr_x_values[i], halfr_y_values[i]) peak_x_idx = np.where(peak_x_values < halfr_x_values[i])[0][-1] start = (peak_x_values[peak_x_idx], halfr_y_values[i]) halfr_coord.append((start, end)) if static: # Plot with matplotlib. # Mark onsets, peaks, and half-recovery. ax.scatter( x_axis[onsets], eda_signals["EDA_Phasic"][onsets], color="#FFA726", label="SCR - Onsets", zorder=2, ) ax.scatter( x_axis[peaks], eda_signals["EDA_Phasic"][peaks], color="#1976D2", label="SCR - Peaks", zorder=2, ) ax.scatter( x_axis[half_recovery], eda_signals["EDA_Phasic"][half_recovery], color="#FDD835", label="SCR - Half recovery", zorder=2, ) ax.scatter(x_axis[end_onset.index], end_onset.values, alpha=0) else: # Create interactive plot with plotly. try: import plotly.graph_objects as go except ImportError as e: raise ImportError( "NeuroKit error: ppg_plot(): the 'plotly'", " module is required when 'static' is False.", " Please install it first (`pip install plotly`).", ) from e # Plot with plotly. # Mark onsets, peaks, and half-recovery. ax.add_trace( go.Scatter( x=x_axis[onsets], y=eda_signals["EDA_Phasic"][onsets], mode="markers", name="SCR - Onsets", marker=dict(color="#FFA726"), showlegend=True, ), row=2, col=1, ) ax.add_trace( go.Scatter( x=x_axis[peaks], y=eda_signals["EDA_Phasic"][peaks], mode="markers", name="SCR - Peaks", marker=dict(color="#1976D2"), showlegend=True, ), row=2, col=1, ) ax.add_trace( go.Scatter( x=x_axis[half_recovery], y=eda_signals["EDA_Phasic"][half_recovery], mode="markers", name="SCR - Half recovery", marker=dict(color="#FDD835"), showlegend=True, ), row=2, col=1, ) ax.add_trace( go.Scatter( x=x_axis[end_onset.index], y=end_onset.values, mode="markers", marker=dict(color="#FDD835", opacity=0), showlegend=False, ), row=2, col=1, ) return risetime_coord, amplitude_coord, halfr_coord