Visualization¶
Shaded Error Plot¶
- naplib.visualization.shaded_error_plot(*args, ax=None, reduction='mean', err_method='stderr', color=None, alpha=0.4, plt_args={}, shade_args={'alpha': 0.4, 'color': '#d62728'}, nan_policy='omit')[source]¶
Plot the average/median value at each time point and a shaded region indicating error or confidence level above and below the line. See Examples below for a depiction.
- Parameters:
x (array-like, shape (n_samples,), optional) -- x values are optional and default to
range(len(y)).y (array-like, shape (n_samples, n_points)) -- Data to plot, providing the vertical coordinates. y values should be two-dimensional, and statistics used to compute shaded region interval are computed over the second dimension.
fmt (str, optional) -- A format string, e.g. 'ro' for red circles. See the matplotlib Axes.plot Notes section for a full description of the format strings. Format strings are just an abbreviation for quickly setting basic line properties. All of these and more can also be controlled by keyword arguments within color or plt_args. This argument cannot be passed as keyword.
ax (plt.Axes instance, optional) -- Axes to use. If not specified, will use current axes.
reduction (str, default='mean') -- Reduction method, either 'mean' or 'median'.
err_method (string or float, default='stderr') -- The method to use to calculate error bars. If a string, one of ['stderr','std']. If a float, defines the confidence interval desired. For example 0.95 specifies a 95% confidence interval around the mean (i.e. the interval from the 2.5th percentile to the 97.5th percentile). Note, if the data have significant outliers and reduction='mean' then the confidence interval bounds might not surround the mean value line.
color (str, default=None) -- Color to plot line and shaded region. Defaults to next color in color cycle.
alpha (float, default=0.4) -- Shading alpha. Value between 0 and 1.
plt_args (dict, default={}) -- Dict of args to be passed to plt.plot(). e.g. {'linewidth': 2}, etc.
shade_args (dict, default={}) -- Dict of args to be passed to plt.fill_between(). e.g. {'alpha': 0.2}, etc.
nan_policy (string, default='omit') -- One of ['omit','raise','propogate']. If 'omit', will ignore any nan in the inputs, if 'raise', will raise a ValueError if nan is found in input, if 'propogate', do not do anything special with nan values.
- Returns:
ax -- matplotlib axes containing the plot
- Return type:
Examples
>>> from naplib.visualization import shaded_error_plot as sep >>> import matplotlib.pyplot as plt >>> import numpy as np >>> rng = np.random.default_rng(1) >>> x, y = np.linspace(0, 1, 10), rng.normal(size=(10,5)) >>> fig, ax = plt.subplots(3,1) >>> sep(y, ax=axes[0]) # plot mean of y, with shaded error regions >>> sep(y, 'r--', ax=axes[1]) # same plot but color is red and line is dashed >>> sep(x, y, ax=axes[2], err_method='std') # plot vs specific x values and use std. error >>> plt.show()
- Raises:
ValueError -- if nan found in input and
nan_policyis 'raise'.
Kernel Density and Histogram¶
- naplib.visualization.kde_plot(data, groupings=None, hist=True, alpha=0.2, bins=None, **kwargs)[source]¶
Plot kernel density estimate of distribution for data, along with histogram underneath. Can plot multiple densities, one per grouping. See Examples below for a depiction.
- Parameters:
data (list or array-like or list of np.ndarrays) -- Data to plot density of. If of shape (N_points,) and groupings is None, then it is assumed to be a single distribution to plot. Otherwise, can be either an array of shape (N_points, M_groups), or a list of length M_groups containing arrays of shape (N_points_i). See
groupingsargument for more on how data should be formatted depending on the groupings desired.groupings (list or array-like, optional) -- Grouping method for separating data into different distributions, or labels for those distributions. If groupings is given when data is 1-dimensional, groupings should provide categorical labels for each point in data and also be shape (N_points,). Alternatively, can be a list or array-like of shape/length M_groups, with each element specifying a label for each group/column in
data. You must specify groupings for the axis legend to be shown.hist (bool, default=True) -- If True (default), plots a histogram underneath the kernel density estimate.
alpha (float, default=0.2) -- Alpha value for transparency of histogram. Ignored if
hist=False.bins (int or sequence or str, default = :rc:`hist.bins`) -- Bins for histogram. Ignored if
hist=False.**kwargs (kwargs) -- kwargs for seaborn.kdeplot. Cannot include 'data', 'x', 'y', or 'hue'. See below for some examples of frequently used kwargs.
ax (matplotlib.axes.Axes, optional) -- Axes to plot on.
bw_method (string, scalar, or callable, optional) -- Method for determining the smoothing bandwidth to use; passed to scipy.stats.gaussian_kde. Can be a single float to determine the bandwidth.
color (str or matplotlib color, or list of colors, optional) -- Color to use if only providing 1 grouping of data (e.g. if
groupings=None), or an iterable of the color to use for each group.
- Returns:
ax -- matplotlib axes containing the plot
- Return type:
Examples
>>> from naplib.visualization import kde_plot >>> import numpy as np >>> rng = np.random.default_rng(1) >>> rng = np.random.default_rng(1) >>> data = rng.normal(size=(100,)) >>> data[50:] += 0.5 # shift the second half of the samples >>> groupings = np.array(['G0'] * 100) # define grouping vector >>> groupings[50:] = 'G1' # set a different label for the samples we shifted >>> # plot the density for each group, as well as a histogram underneath each >>> ax = kde_plot(data, groupings=groupings, bw_method=0.25, bins=15, color=['k','r'])
>>> # plot the exact same figure from a list of arrays and grouping labels of same length >>> data_list = [data[:50],data[50:]] >>> kde_plot(data_list, groupings=['G0','G1'], bw_method=0.25, bins=15, color=['k','r']) >>> # plot the exact same figure from a 2D numpy array >>> data_mat = np.concatenate([data[:50,np.newaxis],data[50:,np.newaxis]], axis=1) >>> kde_plot(data_mat, groupings=['G0','G1'], bw_method=0.25, bins=15, color=['k','r']) >>> # if we don't pass in groupings but data is still a 2D array or a list, >>> # then there just won't be a legend, but the plot will be the same >>> kde_plot(data_mat, bw_method=0.25, bins=15, color=['k','r'])
Hierarchical Cluster Plot¶
- naplib.visualization.hierarchical_cluster_plot(data, axes=None, varnames=None, cmap='bwr', n_clusters=2, metric='euclidean', linkage='ward')[source]¶
Perform hierarchical clustering and plot dendrogram and clustered values as an image underneath. See Examples below for a depiction.
- Parameters:
data (shape (n_samples, n_features)) -- Data to cluster and display.
axes (list of plt.Axes, length 2, optional) -- Array of length 2 containing matplotlib axes to plot on. axes[0] will be for the dendrogram and axes[1] will be for the data. If not specified, will create new axes in subplots.
varnames (list of strings, length must = n_features, default=None) -- Variable names which will be printed as yticklabels on the data plot
cmap (string, default='bwr') -- colormap for the data plot
n_clusters (int, default=2) -- Number of clusters which will be used when computing cluster labels that are returned, and also for coloring the dendrogram by cluster.
metric (str, default='euclidean') -- Distance metric. See scipy.spatial.distance.pdist for valid metrics.
linkage (str, default='ward') -- Linkage method. Must be one of 'single','complete','average','weighted','centroid', 'median', or 'ward'. Some linkage methods are only valid for certain distance metrics.
- Returns:
cluster_dict (dict) -- output from scipy.cluster.hierarchy.dendrogram
cluster_labels (np.ndarray) -- cluster labels from sklearn.cluster.AgglomerativeClustering, shape=(n_samples,)
fig (matplotlib figure) -- Figure where data was plotted. Only returned if axes were not passed in.
axes (np.ndarray of matplotlib.axes.Axes) -- Axes where data was plotted. Only returned if axes were not passed in.
Examples
>>> from naplib.visualization import hierarchical_cluster_plot as hcp >>> import matplotlib.pyplot as plt >>> import numpy as np >>> rng = np.random.default_rng(10) >>> x = rng.normal(size=(100,5)) >>> x[:,1] += rng.normal(loc=1, scale=3, size=(100,)) >>> x[:,2] += rng.normal(loc=-1, scale=3, size=(100,)) >>> varnames = ['var1','var2','var3','var4','var5'] >>> clust, labels, fig, axes = hcp(x, n_clusters=3, varnames=varnames)
STRF Plot¶
- naplib.visualization.strf_plot(coef, tmin=None, tmax=None, freqs=None, ax=None, smooth=True, vmax=None)[source]¶
Plot STRF weights as image. Colormap is automatically centered at 0 so that 0 corresponds to white, positive values are red, and negative values are blue.
- Parameters:
coef (np.array, shape (freq, lag)) -- STRF weights.
tmin (float, optional) -- Time of first lag (first column in coef)
tmax (float, optional) -- Time of final lag (last column in coef)
freqs (list or array-like, length=2, optional) -- Frequency of lowest and highest frequency bin in STRF.
ax (plt.Axes, optional) -- Axes to plot on. If not specified, will use current axes.
smooth (bool, default=True) -- Whether or not to smooth the STRF image. Smoothing is done with 'gouraud' shading in plt.pcolormesh().
vmax (float, optional) -- If provided, colormap will be between [-vmax, vmax]. If not given, uses the max absolute value of the coef.
- Returns:
ax -- Axes where STRF coef is plotted.
- Return type:
Examples
>>> from naplib.visualization import strf_plot >>> import numpy as np >>> from scipy.stats import multivariate_normal >>> # generate example STRF weights following mne's example: >>> # https://mne.tools/stable/auto_tutorials/machine-learning/30_strf.html >>> fs = 100 >>> n_freqs = 32 >>> tmin, tmax = 0, 0.4 >>> delays_samp = np.arange(np.round(tmin * fs), ... np.round(tmax * fs) + 1).astype(int) >>> delays_sec = delays_samp / fs >>> freqs = np.linspace(50, 5000, n_freqs) >>> grid = np.array(np.meshgrid(delays_sec, freqs)) >>> # We need data to be shaped as n_epochs, n_features, n_times, so swap axes here >>> grid = grid.swapaxes(0, -1).swapaxes(0, 1) >>> # Simulate a temporal receptive field with a Gabor filter >>> means_high = [.1, 500] >>> means_low = [.2, 2500] >>> cov = [[.001, 0], [0, 500000]] >>> gauss_high = multivariate_normal.pdf(grid, means_high, cov) >>> gauss_low = -1 * multivariate_normal.pdf(grid, means_low, cov) >>> weights = gauss_high + gauss_low # Combine to create the "true" STRF >>> strf_plot(weights, tmin=tmin, tmax=tmax)
Intracranial Electrodes¶
- naplib.visualization.plot_brain_elecs(brain, elecs, isleft=None, values=None, colors='k', hemi='both', view='lateral', snap_to_surface=None, elec_size=4, cortex='classic', cmap='cool', alpha=1, vmin=None, vmax=None, brain_alpha=None, figsize=6, backend='mpl', **kwargs)[source]¶
Plot electrodes on the brain using a simple matplotlib backend, or an interactive 3D figure using the plotly backend.
Due to the limitation of matplotlib being unable to render 3D surfaces in order as they would truly be seen by the camera angle, electrodes which are behind the cortical surface will still be visible as if they were in front of it.
- Parameters:
brain (nl.localization.Brain) -- Brain instance to plot on.
elecs (np.ndarray) -- Array of shape (num_elecs, 3) of electrode coordinates in pial space.
isleft (np.ndarray, optional) -- Boolean array of length (num_elecs) indicating whether a given electrode belongs to the left hemisphere. If not given, they are assumed based on the sign of the first component of the elecs coordinates (negative is left, positive is right)
values (np.ndarray, optional) -- Float values of length (num_elecs) which will be converted by the colormap colors for each electrode.
colors (np.ndarray | list[str] | str, default='k') -- Colors to plot for each electrode. Ignored if values is not None. This can be a single string specifiying a color for all electrodes, a list of strings of the same length as elecs, or a numpy array of shape (num_elecs, 4) specifying the RGBA value for each electrode.
hemi ({'both', 'lh', 'rh'}, default='both') -- Hemisphere(s) to plot. If 'both', then 2 subplots are created, one for each hemisphere. Otherwise only one hemisphere is displayed with its electrodes.
view ({'lateral','frontal','occipital',medial','top','bottom',best'} | tuple, default='lateral') -- View of the brain to display. A tuple can specify the (elevation, azimuth) for matplotlib backend, or a tuple of dicts for (eye, center), which are the plotly.graph_objects.layout.scene.camera.eye and plotly.graph_objects.layout.scene.camera.center for plotly backend.
snap_to_surface (bool, optional) -- Whether to snap electrodes to the nearest point on the pial cortical surface. If plotting an 'inflated' brain, this should be set to True (default) to map through the pial surface, since coordinates are assumed to represent coordinates in the pial space. If plotting pial, then this can be set to False (default) to show true electrode placement, or True to map to the surface.
elec_size (int | np.ndarray, default=4) -- Size of the markers representing electrodes. If an array, should give the size for each electrode.
cortex ({'classic','high_contrast','mid_contrast','low_contrast','bone'}, default='classic') -- How to map the sulci to greyscale. 'classic' will leave sulci untouched, which may be better for plotting the pial surface, but 'high_contrast' will enhance the contrast between gyri and sulci, which may be better for inflated surfaces.
cmap (str, default='cool') -- Colormap for electrode values if values are provided.
alpha (float | np.ndarray, optional, default=1) -- Opacity of the electrodes. Either a single float or an array of same length as number of electrodes. If None, then the colors provided should be an array of RGBA values, not just RGB.
vmin (float, optional) -- Minimum value for colormap normalization. If None, uses the min of valus.
vmax (float, optional) -- Maximum value for colormap normalization. If None, uses the max of values.
brain_alpha (float, optional) -- Opacity of the brain surface. The default sets this to a reasonable value based on both the surface type ('pial' or not) and the backend ('plotly' vs 'mpl')
figsize (int, default=6) -- Size of the figure to display. This will be multiplied by the number of hemispheres to plot to specify the width.
backend ({'mpl','plotly'}, default='mpl') -- Backend used for plotting. Matplotlib produces a figure and list of axes, each with a hemisphere as a static image. Plotly produces a 3D plot figure widget which can be saved as an image or interacted with in HTML form.
**kwargs -- Additional keyword arguments to be passed to the matplotlib.pyplot.scatter function.
- Returns:
fig (matplotlib Figure or plotly Figure, depending on backend)
axes (list of matplotlib Axes, only if using mpl backend, otherwise None)
Notes
When using within a jupyter notebook, it may be required to run these lines in this specific order before doing any plotting with the plotly backend.
>>> import plotly.offline as pyo >>> pyo.init_notebook_mode(connected=True) >>> import plotly.io as pio >>> pio.renderers.default = 'iframe' # or possibly 'notebook'
If plots still don't show in the notebook, you may need to install nbformat if you do not have it, or you may need to enable certain ipywidgets for displaying plotly in notebooks. Regardless, it should still be possible to save the the figure as either HTML or static image file. See plotly examples documentation for details on saving figures.
Examples
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> from naplib.localization import Brain >>> from naplib.visualization import plot_brain_elecs, plot_brain_overlay >>> brain = Brain('pial', subject_dir='path/to/subjects/').split_hg('midpoint').split_stg().simplify_labels() >>> coords = np.array([[-47.281147 , 17.026093 , -21.833099 ], [-48.273964 , 16.155487 , -20.162935 ], [-51.101261 , 13.711058 , -16.258459 ]]) >>> values = np.array([1, 1.5, 3]) # one value per electrode for color >>> # plot with matplotlib >>> fig, axes = plot_brain_elecs(brain, coords, values=values, hemi='lh', view='lateral') >>> plt.show() >>> # plot interactive figure with plotly >>> fig, axes = plot_brain_elecs(brain, coords, isleft, colors=colors, backend='plotly') >>> fig.write_html("interactive_brain_plot.html") # save as an interactive html plot >>> fig.show() # show the interactive plot in the notebook
Brain Surface Overlay¶
- naplib.visualization.plot_brain_overlay(brain, cmap='coolwarm', ax=None, hemi='both', view='best', vmin=None, vmax=None, cmap_quantile=1.0, threshold=None, light_source=False, **kwargs)[source]¶
Plot brain overlay on the 3D cortical surface using matplotlib. If certain regions have been set as visible using brain.set_visible(), only those regions will be shown.
- Parameters:
brain (nl.localization.Brain) -- Brain instance to plot on.
cmap (str, default='coolwarm') -- Colormap to use.
ax (list | tuple of matplotlib Axes) -- 2 Axes to plot the left and right hemispheres with.
hemi ({'both', 'lh', 'rh'}, default='both') -- Hemisphere(s) to plot. If 'both', then 2 subplots are created, one for each hemisphere. Otherwise only one hemisphere is displayed with its overlay.
view ({'lateral','medial','frontal','occipital',top','bottom',best'} | tuple, default='best') -- View of the brain to display. A tuple can specify the (elevation, azimuth) for matplotlib backend, or a tuple of dicts for (eye, center), which are the plotly.graph_objects.layout.scene.camera.eye and plotly.graph_objects.layout.scene.camera.center for plotly backend.
vmin (float, optional) -- Minimum value for colormap. If not given, will use cmap_quantile or range or overlay values.
vmax (float, optional) -- Maximum value for colormap. If not given, will use cmap_quantile or range or overlay values.
cmap_quantile (float | tuple of floats (optional), default=1.0) -- If a single float less than 1, will only use the central
cmap_quantileportion of the range of values to create the vmin and vmax for the colormap. For example, if set to 0.95, then only the middle 95% of the values will be used to set the range of the colormap. If a tuple, then it should specify 2 quantiles, one for the vmin and one for the vmax, such as (0.025, 0.975), which would be equivalent to passing a single value of 0.95.threshold (positive float, optional) -- If given, then only values on the overlay which are less -threshold or greater than threshold will be shown.
light_source (None, bool, or tuple of int, optional) -- Whether to apply a light source for shading. If True, the light source position is inferred from elev and azim. If a tuple of (alt, az), these values will be used to specify the light source position. If None or False, no shading is applied. Default is True.
**kwargs (kwargs) -- Any other kwargs to pass to matplotlib.pyplot.figure (such as figsize)
- Returns:
fig (matplotlib Figure)
axes (tuple of matplotlib Axes)
Frequency Response¶
- naplib.visualization.freq_response(ba, fs, ax=None, units='Hz')[source]¶
Plot frequency response of a digital filter.
- Parameters:
ba (tuple of length 2) -- Tuple containing (b, a), the filter numerator and denominator polynomials.
fs (int) -- Sampling rate in Hz.
ax (plt.Axes instance, optional) -- Axes to use. If not specified, will use current axes.
units (string) -- One of {'Hz', 'rad/s'} specifying whether to plot frequencies in Hz or radians per second.
- Returns:
ax -- Axes where STRF coef is plotted.
- Return type:
Examples
>>> import naplib as nl >>> from naplib.visualization import freq_response >>> from naplib.preprocessing import filter_butter >>> # Load sample data to filter >>> data = nl.io.load_speech_task_data() >>> alpha_band_data, filters = filter_butter(data, btype='bandpass', ... Wn=[10, 20], ... return_filters=True) >>> ax = freq_response(filters[0], fs=data[0]['dataf'])
EEG Channel Locs¶
- naplib.visualization.eeg_locs(setup='gtec62')[source]¶
Load EEG cap positions for a gtec locs file. By default, loads the gtec 62-channel EEG setup.
These can be put into mne.viz.plot_topomap
- Parameters:
setup (str or pathlike, default='gtec62') -- The setup to use. By default, uses the gtec62.locs file in the same directory. If another string or path is specified, that is assumed to be a path to a .locs file, and this will try to load that as an EEGLab .locs file. The coordinates in such a file must be polar coordinates with a head disk radius of 0.5.
- Returns:
pos -- 2D positions, shape (n_channels, 2)
- Return type:
np.ndarray
Examples
>>> import mne >>> import numpy as np >>> from naplib.visualization import eeg_locs >>> arr = np.random.rand(62,) >>> # using the default locs >>> mne.viz.plot_topomap(arr, eeg_locs()) >>> # using a custom .locs file in the current directory >>> mne.viz.plot_topomap(arr, eeg_locs('custom.locs'))