Added/modified few plot functions. Cleaned up simulation/plotting scripts regarding Thresh-LP.
290 lines
11 KiB
Python
290 lines
11 KiB
Python
import string
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
from matplotlib.transforms import Bbox, BboxTransformTo, TransformedBbox
|
|
|
|
def hide_ticks(ax, side='bottom', ticks=True):
|
|
axis = 'x' if side in ['top', 'bottom'] else 'y'
|
|
params = {side: ticks, 'label' + side: False}
|
|
ax.tick_params(axis=axis, which='both', **params)
|
|
return None
|
|
|
|
def hide_axis(ax, side='bottom'):
|
|
ax.spines[side].set_visible(False)
|
|
params = {side: False, 'label' + side: False}
|
|
ax.tick_params(axis='x' if side in ['top', 'bottom'] else 'y',
|
|
which='both', **params)
|
|
return None
|
|
|
|
def get_trans_artist(artist):
|
|
artist_type = type(artist).__name__
|
|
if artist_type == 'Axes':
|
|
return artist.transAxes
|
|
elif artist_type == 'Figure':
|
|
return artist.transFigure
|
|
elif artist_type == 'Subfigure':
|
|
return artist.transSubfigure
|
|
elif hasattr(artist, 'bbox'):
|
|
return BboxTransformTo(artist.bbox)
|
|
renderer = artist.get_figure(root=True).canvas.get_renderer()
|
|
if hasattr(artist, 'get_window_extent'):
|
|
return BboxTransformTo(artist.get_window_extent(renderer))
|
|
elif hasattr(artist, 'get_tightbbox'):
|
|
return BboxTransformTo(artist.get_tightbbox(renderer))
|
|
raise ValueError('Artist does not have a bounding box to use as transform.')
|
|
|
|
def shift_subplot(ax, dx=0, dy=0, ref=None):
|
|
if ref is not None:
|
|
transform = get_trans_artist(ref) + get_trans_artist(ax.figure).inverted()
|
|
dx, dy = transform.transform((dx, dy)) - transform.transform((0, 0))
|
|
pos = ax.get_position()
|
|
ax.set_position([pos.x0 + dx, pos.y0 + dy, pos.width, pos.height])
|
|
return None
|
|
|
|
def title_subplot(artist, title, x=0.5, y=1.0, xref=None, yref=None, ref=None,
|
|
ha='center', va='bottom', fontsize=16, fontweight='normal', **kwargs):
|
|
trans_artist = get_trans_artist(artist)
|
|
if xref is not None or yref is not None:
|
|
transform = get_trans_artist(ref) + trans_artist.inverted()
|
|
if xref is not None:
|
|
x = transform.transform((xref, 0))[0]
|
|
if yref is not None:
|
|
y = transform.transform((0, yref))[1]
|
|
return artist.text(x, y, title, transform=trans_artist, ha=ha, va=va,
|
|
fontsize=fontsize, fontweight=fontweight, **kwargs)
|
|
|
|
def letter_subplot(artist, label, x=None, y=None, xref=None, yref=None, ref=None,
|
|
ha='left', va='bottom', fontsize=16, fontweight='bold', **kwargs):
|
|
trans_artist = get_trans_artist(artist)
|
|
if x is None or y is None:
|
|
transform = get_trans_artist(ref) + trans_artist.inverted()
|
|
if x is None:
|
|
x = transform.transform([xref, 0])[0]
|
|
if y is None:
|
|
y = transform.transform([0, yref])[1]
|
|
return artist.text(x, y, label, transform=trans_artist, ha=ha, va=va,
|
|
fontsize=fontsize, fontweight=fontweight, **kwargs)
|
|
|
|
def letter_subplots(artists, labels=None, x=None, y=None, xref=None, yref=None, ref=None,
|
|
ha='left', va='bottom', fontsize=16, fontweight='bold', **kwargs):
|
|
if labels is None:
|
|
labels = string.ascii_lowercase
|
|
handles = []
|
|
for artist, label in zip(artists, labels):
|
|
handles.append(letter_subplot(artist, label, x, y, xref, yref, ref,
|
|
ha=ha, va=va, fontsize=fontsize, fontweight=fontweight, **kwargs))
|
|
return handles
|
|
|
|
def xlimits(time, ax=None, minval=None, maxval=None, pad=0.05):
|
|
if minval is not None and maxval is not None:
|
|
if ax is not None:
|
|
return ax.set_xlim([minval, maxval])
|
|
return [minval, maxval]
|
|
limits = [minval, maxval]
|
|
if minval is None:
|
|
limits[0] = time[0]
|
|
if maxval is None:
|
|
limits[1] = time[-1]
|
|
span = limits[1] - limits[0]
|
|
if pad and minval is None:
|
|
limits[0] -= span * pad
|
|
if pad and maxval is None:
|
|
limits[1] += span * pad
|
|
if ax is not None:
|
|
return ax.set_xlim(limits)
|
|
return limits
|
|
|
|
def ylimits(signal, ax=None, minval=None, maxval=None, pad=0.05):
|
|
if minval is not None and maxval is not None:
|
|
if ax is not None:
|
|
return ax.set_ylim([minval, maxval])
|
|
return [minval, maxval]
|
|
limits = [minval, maxval]
|
|
if minval is None:
|
|
limits[0] = signal.min()
|
|
if maxval is None:
|
|
limits[1] = signal.max()
|
|
span = limits[1] - limits[0]
|
|
if pad and minval is None:
|
|
limits[0] -= span * pad
|
|
if pad and maxval is None:
|
|
limits[1] += span * pad
|
|
if ax is not None:
|
|
return ax.set_ylim(limits)
|
|
return limits
|
|
|
|
def xlabel(ax, label, x=None, y=-0.1, fontsize=20, transform=None, **kwargs):
|
|
if x is None:
|
|
x = 0.5
|
|
if transform is not None:
|
|
x = (ax.transAxes + transform.inverted()).transform((x, 0))[0]
|
|
ax.xaxis.set_label_coords(x, y, transform=transform)
|
|
return ax.set_xlabel(label, fontsize=fontsize, **kwargs)
|
|
|
|
def ylabel(ax, label, x=-0.2, y=None, fontsize=20, transform=None, **kwargs):
|
|
if y is None:
|
|
y = 0.5
|
|
if transform is not None:
|
|
y = (ax.transAxes + transform.inverted()).transform((0, y))[1]
|
|
ax.yaxis.set_label_coords(x, y, transform=transform)
|
|
return ax.set_ylabel(label, fontsize=fontsize, **kwargs)
|
|
|
|
def super_xlabel(label, fig, left_ax, right_ax, y=0.005,
|
|
left_fig=None, right_fig=None, **kwargs):
|
|
left_x = left_ax.get_position().x0
|
|
right_x = right_ax.get_position().x1
|
|
if left_fig is not None or right_fig is not None:
|
|
trans_fig = get_trans_artist(fig)
|
|
if left_fig is not None:
|
|
transform = get_trans_artist(left_fig) + trans_fig.inverted()
|
|
left_x = transform.transform((left_x, 0))[0]
|
|
if right_fig is not None:
|
|
transform = get_trans_artist(right_fig) + trans_fig.inverted()
|
|
right_x = transform.transform((right_x, 0))[0]
|
|
return fig.supxlabel(label, x=(left_x + right_x) / 2, y=y, **kwargs)
|
|
|
|
def super_ylabel(label, fig, low_ax, high_ax, x=0.005,
|
|
high_fig=None, low_fig=None, **kwargs):
|
|
low_y = high_ax.get_position().y0
|
|
high_y = low_ax.get_position().y1
|
|
if low_fig is not None or high_fig is not None:
|
|
trans_fig = get_trans_artist(fig)
|
|
if low_fig is not None:
|
|
transform = get_trans_artist(low_fig) + trans_fig.inverted()
|
|
low_y = transform.transform((0, low_y))[1]
|
|
if high_fig is not None:
|
|
transform = get_trans_artist(high_fig) + trans_fig.inverted()
|
|
high_y = transform.transform((0, high_y))[1]
|
|
return fig.supylabel(label, x=x, y=(low_y + high_y) / 2, **kwargs)
|
|
|
|
def plot_line(ax, time, signal, ymin=None, ymax=None, xmin=None, xmax=None,
|
|
xpad=None, ypad=0.05, yloc=None, xloc=None, **kwargs):
|
|
handles = ax.plot(time, signal, **kwargs)
|
|
xlimits(time, ax=ax, minval=xmin, maxval=xmax, pad=xpad)
|
|
ylimits(signal, ax=ax, minval=ymin, maxval=ymax, pad=ypad)
|
|
if xloc is not None:
|
|
ax.xaxis.set_major_locator(plt.MultipleLocator(xloc))
|
|
if yloc is not None:
|
|
ax.yaxis.set_major_locator(plt.MultipleLocator(yloc))
|
|
return handles
|
|
|
|
def plot_barcode(ax, time, binary, offset=0.5, xmin=None, xmax=None, **kwargs):
|
|
if binary.ndim == 1:
|
|
binary = binary[:, None]
|
|
lower, upper, handles = 0, 1, []
|
|
for i in range(binary.shape[1]):
|
|
h = ax.fill_between(time, lower, upper, where=binary[:, i], **kwargs)
|
|
handles.append(h)
|
|
if i < binary.shape[1] - 1:
|
|
lower += offset + 1
|
|
upper += offset + 1
|
|
xlimits(time, ax=ax, minval=xmin, maxval=xmax, pad=0)
|
|
ax.set_ylim(0, upper)
|
|
hide_axis(ax, 'bottom')
|
|
hide_axis(ax, 'left')
|
|
return handles
|
|
|
|
def indicate_zoom(fig, high_ax, low_ax, zoom_abs, **kwargs):
|
|
y0 = low_ax.get_position().y0
|
|
y1 = high_ax.get_position().y1
|
|
transform = low_ax.transData + fig.transFigure.inverted()
|
|
x0 = transform.transform((zoom_abs[0], 0))[0]
|
|
x1 = transform.transform((zoom_abs[1], 0))[0]
|
|
return fig.add_artist(plt.Rectangle((x0, y0), x1 - x0, y1 - y0,
|
|
transform=fig.transFigure, **kwargs))
|
|
|
|
def assign_colors(handles, types, colors):
|
|
for handle, type_id in zip(handles, types):
|
|
handle.set_color(colors[str(int(type_id))])
|
|
return None
|
|
|
|
def reorder_traces(handles, signal, zlow=2, zhigh=2.5):
|
|
inds = np.argsort(signal.std(axis=0))
|
|
zorders = np.linspace(zlow, zhigh, len(inds))[::-1]
|
|
for ind, z in zip(inds, zorders):
|
|
handles[ind].set_zorder(z)
|
|
return None
|
|
|
|
def strip_zeros(num, right_digits=5):
|
|
if isinstance(num, int):
|
|
return num
|
|
num = f'{num:.{right_digits}f}'
|
|
left, right = num.split('.')
|
|
right = right.rstrip('0')
|
|
if right:
|
|
return f'{left}.{right}'
|
|
return left
|
|
|
|
def time_bar(ax, dur, y0=0.9, y1=0.95, xshift=0.5, parent=None,
|
|
text_pos=None, text_str=None, text_kwargs={}, **kwargs):
|
|
if parent is None:
|
|
parent = ax
|
|
trans_parent = get_trans_artist(parent)
|
|
transform = ax.transData + trans_parent.inverted()
|
|
t0 = ax.get_xlim()[0]
|
|
x0 = transform.transform((t0, 0))[0]
|
|
x1 = transform.transform((t0 + dur, 0))[0]
|
|
dur = x1 - x0
|
|
x0 = (1 - dur) * xshift
|
|
rect = parent.add_artist(plt.Rectangle((x0, y0), dur, y1 - y0,
|
|
transform=trans_parent, **kwargs))
|
|
if text_pos is not None:
|
|
trans_bar = get_trans_artist(rect)
|
|
text_pos = (trans_bar + trans_parent.inverted()).transform(text_pos)
|
|
if text_str is None:
|
|
text_str = f'{dur:.2f} s'
|
|
t = parent.text(*text_pos, text_str, transform=trans_parent, **text_kwargs)
|
|
return rect, t
|
|
return rect
|
|
|
|
def zoom_inset(ax, inset, handle, x0=None, x1=None, y0=None, y1=None, ref='x',
|
|
transform=None,
|
|
low_left=False, up_left=False, low_right=False, up_right=False,
|
|
props=['c', 'lw', 'ls', 'zorder', 'alpha'], **kwargs):
|
|
if not kwargs:
|
|
kwargs = dict(edgecolor='k', alpha=1, lw=2)
|
|
|
|
if transform is not None:
|
|
transform = transform + ax.transData.inverted()
|
|
xlims = ax.get_xlim()
|
|
ylims = ax.get_ylim()
|
|
if x0 is None:
|
|
x0 = xlims[0]
|
|
elif transform is not None:
|
|
x0 = transform.transform((x0, 0))[0]
|
|
if x1 is None:
|
|
x1 = xlims[1]
|
|
elif transform is not None:
|
|
x1 = transform.transform((x1, 0))[0]
|
|
if y0 is None:
|
|
y0 = ylims[0]
|
|
elif transform is not None:
|
|
y0 = transform.transform((0, y0))[1]
|
|
if y1 is None:
|
|
y1 = ylims[1]
|
|
elif transform is not None:
|
|
y1 = transform.transform((0, y1))[1]
|
|
inset.set_xlim(x0, x1)
|
|
inset.set_ylim(y0, y1)
|
|
|
|
x = handle.get_xdata()
|
|
y = handle.get_ydata()
|
|
if ref == 'x':
|
|
zoom_inds = (x >= x0) & (x <= x1)
|
|
elif ref == 'y':
|
|
zoom_inds = (y >= y0) & (y <= y1)
|
|
x = x[zoom_inds]
|
|
y = y[zoom_inds]
|
|
|
|
inset_handle = inset.plot(x, y)[0]
|
|
inset_handle.set(**{prop: plt.getp(handle, prop) for prop in props})
|
|
elements = ax.indicate_inset_zoom(inset, **kwargs)
|
|
|
|
visibility = low_left, up_left, low_right, up_right
|
|
[l.set_visible(v) for l, v in zip(elements.connectors, visibility)]
|
|
return inset_handle, elements.rectangle, elements.connectors
|
|
|
|
def set_clip_box(artist, ax, bounds=[[0, -0.05], [1, 1.05]]):
|
|
artist.set_clip_box(TransformedBbox(Bbox(bounds), ax.transAxes))
|
|
return None
|