Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move RAUC calculations to load_dataset and store them as annotations #188

Merged
merged 2 commits into from
Feb 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions docs/metadata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,8 @@ Rectified Area Under the Curve (RAUC)
-------------------------------------

One way to simplify a high-frequency signal is by plotted a time series of the
rectified area under the curve (RAUC). Note that RAUCs are calculated
automatically only in the standalone application and only if fast loading is
off (``lazy=False``).
rectified area under the curve (RAUC). Note that RAUCs are calculated only if
fast loading is off (``lazy=False``).

For each signal, the baseline (mean or median) is optionally subtracted off.
The signal is then rectified (absolute value) and divided into non-overlapping
Expand Down
24 changes: 21 additions & 3 deletions neurotic/datasets/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ def load_dataset(metadata, lazy=False, signal_group_mode='split-all', filter_eve
``epoch_encoder_file`` and spike trains loaded from ``tridesclous_file``
are added to the Neo Block.

If ``lazy=False``, filters given in ``metadata`` are applied to the
signals and amplitude discriminators are run to detect spikes.
If ``lazy=False``, parameters given in ``metadata`` are used to apply
filters to the signals, to detect spikes using amplitude discriminators, to
detect bursts of spikes, and to calculate the rectified area under the
curve (RAUC) for each signal.
"""

# read in the electrophysiology data
Expand Down Expand Up @@ -83,6 +85,22 @@ def load_dataset(metadata, lazy=False, signal_group_mode='split-all', filter_eve
blk.segments[0].epochs.sort(key=lambda ep: ep.name)
blk.segments[0].events.sort(key=lambda ev: ev.name)

# compute rectified area under the curve (RAUC) for each signal if not
# using lazy loading of signals
if not lazy:
for sig in blk.segments[0].analogsignals:
rauc_sig = _elephant_tools.rauc(
signal=sig,
baseline=metadata['rauc_baseline'],
bin_duration=metadata['rauc_bin_duration']*pq.s,
)
rauc_sig.name = sig.name + ' RAUC'
sig.annotate(
rauc_sig=rauc_sig,
rauc_baseline=metadata['rauc_baseline'],
rauc_bin_duration=metadata['rauc_bin_duration']*pq.s,
)

return blk

def _get_io(metadata):
Expand Down Expand Up @@ -610,7 +628,7 @@ def _run_burst_detectors(metadata, blk):

spikeTrainNameToIndex = {st.name:i for i, st in enumerate(blk.segments[0].spiketrains)}

# detect bursts spikes using frequency thresholds
# detect bursts of spikes using frequency thresholds
for detector in metadata['burst_detectors']:

index = spikeTrainNameToIndex.get(detector['spiketrain'], None)
Expand Down
14 changes: 2 additions & 12 deletions neurotic/example/example-notebook.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -173,23 +173,13 @@
"# - this decreases loading time and consumes much less memory, especially\n",
"# for large files\n",
"# - to take advantage of these benefits, signal filtering, amplitude\n",
"# window spike discrimination, and rauc computation must be disabled\n",
"# window spike discrimination, and RAUC computation must be disabled\n",
"# - spike markers on signals are currently incompatible with lazy loading\n",
"lazy = False\n",
"\n",
"blk = neurotic.load_dataset(metadata, lazy=lazy)\n",
"\n",
"# compute rectified area under the curve (RAUC) for each signal\n",
"# - these computations require loading the entire file now, so only\n",
"# perform them if we're not using lazy loading\n",
"rauc_sigs = []\n",
"if not lazy:\n",
" for sig in blk.segments[0].analogsignals:\n",
" rauc = neurotic._elephant_tools.rauc(sig, baseline=metadata['rauc_baseline'], bin_duration=metadata['rauc_bin_duration']*pq.s)\n",
" rauc.name = sig.name + ' RAUC'\n",
" rauc_sigs.append(rauc)\n",
"\n",
"ephyviewer_config = neurotic.EphyviewerConfiguratorWidget(metadata, blk, rauc_sigs, lazy)\n",
"ephyviewer_config = neurotic.EphyviewerConfiguratorWidget(metadata, blk, lazy)\n",
"ephyviewer_config.show_all()\n",
"display(ephyviewer_config)"
]
Expand Down
107 changes: 55 additions & 52 deletions neurotic/gui/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,13 @@ class EphyviewerConfigurator():
and should be used if there is already a Qt app running.
"""

def __init__(self, metadata, blk, rauc_sigs = None, lazy = False):
def __init__(self, metadata, blk, lazy = False):
"""
Initialize a new EphyviewerConfigurator.
"""

self.metadata = metadata
self.blk = blk
self.rauc_sigs = rauc_sigs
self.lazy = lazy

self.viewer_settings = {
Expand Down Expand Up @@ -100,10 +99,10 @@ def __init__(self, metadata, blk, rauc_sigs = None, lazy = False):
}

# hide and disable viewers for which inputs are missing
if not self.rauc_sigs:
if not [sig.annotations['rauc_sig'] for sig in blk.segments[0].analogsignals if 'rauc_sig' in sig.annotations]:
self.viewer_settings['traces_rauc']['show'] = False
self.viewer_settings['traces_rauc']['disabled'] = True
self.viewer_settings['traces_rauc']['reason'] = 'Cannot enable because rauc_sigs is empty'
self.viewer_settings['traces_rauc']['reason'] = 'Cannot enable because there are no RAUC signals'
if not self.blk.segments[0].spiketrains:
self.viewer_settings['spike_trains']['show'] = False
self.viewer_settings['spike_trains']['disabled'] = True
Expand Down Expand Up @@ -424,54 +423,58 @@ def create_ephyviewer_window(self, theme='light', support_increased_line_width=F
########################################################################
# TRACES OF RAUC

if self.is_shown('traces_rauc') and self.rauc_sigs is not None:

sig_rauc_source = ephyviewer.InMemoryAnalogSignalSource(
signals = np.concatenate([self.rauc_sigs[p['index']].as_array() for p in self.metadata['plots']], axis = 1),
sample_rate = self.rauc_sigs[0].sampling_rate, # assuming all AnalogSignals have the same sampling rate
t_start = self.rauc_sigs[0].t_start, # assuming all AnalogSignals start at the same time
channel_names = [p['ylabel'] + ' RAUC' for p in self.metadata['plots']],
)
sources['signal_rauc'] = [sig_rauc_source]

trace_rauc_view = ephyviewer.TraceViewer(source = sources['signal_rauc'][0], name = 'signals rauc')

if 'signals' in win.viewers:
win.add_view(trace_rauc_view, tabify_with = 'signals')
else:
win.add_view(trace_rauc_view)

trace_rauc_view.params['line_width'] = line_width
trace_rauc_view.params['display_labels'] = True
trace_rauc_view.params['display_offset'] = True
trace_rauc_view.params['antialias'] = True

# set the theme
if theme != 'original':
trace_rauc_view.params['background_color'] = self.themes[theme]['background_color']
trace_rauc_view.params['vline_color'] = self.themes[theme]['vline_color']
trace_rauc_view.params['label_fill_color'] = self.themes[theme]['label_fill_color']
trace_rauc_view.params_controller.combo_cmap.setCurrentText(self.themes[theme]['cmap'])
trace_rauc_view.params_controller.on_automatic_color()

# set explicitly assigned signal colors
for name, color in sig_colors.items():
try:
index = [p['channel'] for p in self.metadata['plots']].index(name)
trace_rauc_view.by_channel_params['ch{}'.format(index), 'color'] = color
except ValueError:
# sig name may not have been found in the rauc trace list
pass

# adjust plot range
trace_rauc_view.params['ylim_max'] = 0.5
trace_rauc_view.params['ylim_min'] = -trace_rauc_view.source.nb_channel + 0.5
trace_rauc_view.params['scale_mode'] = 'by_channel'
for i, p in enumerate(self.metadata['plots']):
ylim_span = np.median(self.rauc_sigs[p['index']].magnitude) * 10
ylim_center = ylim_span / 2
trace_rauc_view.by_channel_params['ch{}'.format(i), 'gain'] = 1/ylim_span # rescale [ymin,ymax] across a unit
trace_rauc_view.by_channel_params['ch{}'.format(i), 'offset'] = -i - ylim_center/ylim_span # center [ymin,ymax] within the unit
if self.is_shown('traces_rauc'):

rauc_sigs = [sig.annotations['rauc_sig'] for sig in sigs if 'rauc_sig' in sig.annotations]

if rauc_sigs:

sig_rauc_source = ephyviewer.InMemoryAnalogSignalSource(
signals = np.concatenate([rauc_sigs[p['index']].as_array() for p in self.metadata['plots']], axis = 1),
sample_rate = rauc_sigs[0].sampling_rate, # assuming all AnalogSignals have the same sampling rate
t_start = rauc_sigs[0].t_start, # assuming all AnalogSignals start at the same time
channel_names = [p['ylabel'] + ' RAUC' for p in self.metadata['plots']],
)
sources['signal_rauc'] = [sig_rauc_source]

trace_rauc_view = ephyviewer.TraceViewer(source = sources['signal_rauc'][0], name = 'signals rauc')

if 'signals' in win.viewers:
win.add_view(trace_rauc_view, tabify_with = 'signals')
else:
win.add_view(trace_rauc_view)

trace_rauc_view.params['line_width'] = line_width
trace_rauc_view.params['display_labels'] = True
trace_rauc_view.params['display_offset'] = True
trace_rauc_view.params['antialias'] = True

# set the theme
if theme != 'original':
trace_rauc_view.params['background_color'] = self.themes[theme]['background_color']
trace_rauc_view.params['vline_color'] = self.themes[theme]['vline_color']
trace_rauc_view.params['label_fill_color'] = self.themes[theme]['label_fill_color']
trace_rauc_view.params_controller.combo_cmap.setCurrentText(self.themes[theme]['cmap'])
trace_rauc_view.params_controller.on_automatic_color()

# set explicitly assigned signal colors
for name, color in sig_colors.items():
try:
index = [p['channel'] for p in self.metadata['plots']].index(name)
trace_rauc_view.by_channel_params['ch{}'.format(index), 'color'] = color
except ValueError:
# sig name may not have been found in the rauc trace list
pass

# adjust plot range
trace_rauc_view.params['ylim_max'] = 0.5
trace_rauc_view.params['ylim_min'] = -trace_rauc_view.source.nb_channel + 0.5
trace_rauc_view.params['scale_mode'] = 'by_channel'
for i, p in enumerate(self.metadata['plots']):
ylim_span = np.median(rauc_sigs[p['index']].magnitude) * 10
ylim_center = ylim_span / 2
trace_rauc_view.by_channel_params['ch{}'.format(i), 'gain'] = 1/ylim_span # rescale [ymin,ymax] across a unit
trace_rauc_view.by_channel_params['ch{}'.format(i), 'offset'] = -i - ylim_center/ylim_span # center [ymin,ymax] within the unit

########################################################################
# FREQUENCY (EXPERIMENTAL AND COMPUTATIONALLY EXPENSIVE!)
Expand Down
3 changes: 1 addition & 2 deletions neurotic/gui/notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class EphyviewerConfiguratorWidget(EphyviewerConfigurator):
ephyviewer.
"""

def __init__(self, metadata, blk, rauc_sigs = None, lazy = False):
def __init__(self, metadata, blk, lazy = False):
"""
Initialize a new EphyviewerConfiguratorWidget.
"""
Expand All @@ -165,7 +165,6 @@ def __init__(self, metadata, blk, rauc_sigs = None, lazy = False):
self,
metadata=metadata,
blk=blk,
rauc_sigs=rauc_sigs,
lazy=lazy)

self.viewer_settings['traces'].update({ 'icon': 'line-chart', 'description': 'Traces'})
Expand Down
9 changes: 1 addition & 8 deletions neurotic/gui/standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,14 +281,7 @@ def launch(self):

blk = load_dataset(metadata, lazy=self.lazy)

rauc_sigs = []
if not self.lazy:
for sig in blk.segments[0].analogsignals:
rauc = _elephant_tools.rauc(sig, baseline=metadata['rauc_baseline'], bin_duration=metadata['rauc_bin_duration']*pq.s)
rauc.name = sig.name + ' RAUC'
rauc_sigs.append(rauc)

ephyviewer_config = EphyviewerConfigurator(metadata, blk, rauc_sigs, self.lazy)
ephyviewer_config = EphyviewerConfigurator(metadata, blk, self.lazy)
ephyviewer_config.show_all()

win = ephyviewer_config.create_ephyviewer_window(theme=self.theme, support_increased_line_width=self.support_increased_line_width, show_datetime=self.show_datetime)
Expand Down