phy 2.1.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- phy/__init__.py +53 -0
- phy/apps/__init__.py +260 -0
- phy/apps/base.py +1887 -0
- phy/apps/kwik/__init__.py +10 -0
- phy/apps/kwik/gui.py +276 -0
- phy/apps/kwik/static/state.json +90 -0
- phy/apps/kwik/tests/__init__.py +0 -0
- phy/apps/kwik/tests/test_gui.py +103 -0
- phy/apps/template/__init__.py +9 -0
- phy/apps/template/gui.py +226 -0
- phy/apps/template/static/state.json +95 -0
- phy/apps/template/tests/__init__.py +0 -0
- phy/apps/template/tests/test_gui.py +223 -0
- phy/apps/tests/__init__.py +0 -0
- phy/apps/tests/test_base.py +576 -0
- phy/apps/trace/__init__.py +8 -0
- phy/apps/trace/gui.py +101 -0
- phy/apps/trace/tests/__init__.py +0 -0
- phy/apps/trace/tests/test_gui.py +26 -0
- phy/cluster/__init__.py +8 -0
- phy/cluster/_history.py +174 -0
- phy/cluster/_utils.py +362 -0
- phy/cluster/clustering.py +517 -0
- phy/cluster/supervisor.py +1273 -0
- phy/cluster/tests/__init__.py +0 -0
- phy/cluster/tests/conftest.py +44 -0
- phy/cluster/tests/test_clustering.py +502 -0
- phy/cluster/tests/test_history.py +142 -0
- phy/cluster/tests/test_supervisor.py +772 -0
- phy/cluster/tests/test_utils.py +217 -0
- phy/cluster/views/__init__.py +19 -0
- phy/cluster/views/amplitude.py +311 -0
- phy/cluster/views/base.py +703 -0
- phy/cluster/views/cluscatter.py +392 -0
- phy/cluster/views/correlogram.py +315 -0
- phy/cluster/views/feature.py +526 -0
- phy/cluster/views/histogram.py +352 -0
- phy/cluster/views/probe.py +185 -0
- phy/cluster/views/raster.py +218 -0
- phy/cluster/views/scatter.py +123 -0
- phy/cluster/views/template.py +287 -0
- phy/cluster/views/tests/__init__.py +7 -0
- phy/cluster/views/tests/conftest.py +27 -0
- phy/cluster/views/tests/test_amplitude.py +127 -0
- phy/cluster/views/tests/test_base.py +74 -0
- phy/cluster/views/tests/test_cluscatter.py +108 -0
- phy/cluster/views/tests/test_correlogram.py +56 -0
- phy/cluster/views/tests/test_feature.py +107 -0
- phy/cluster/views/tests/test_histogram.py +70 -0
- phy/cluster/views/tests/test_probe.py +50 -0
- phy/cluster/views/tests/test_raster.py +119 -0
- phy/cluster/views/tests/test_scatter.py +119 -0
- phy/cluster/views/tests/test_template.py +118 -0
- phy/cluster/views/tests/test_trace.py +320 -0
- phy/cluster/views/tests/test_waveform.py +108 -0
- phy/cluster/views/trace.py +873 -0
- phy/cluster/views/waveform.py +544 -0
- phy/conftest.py +95 -0
- phy/gui/__init__.py +22 -0
- phy/gui/actions.py +722 -0
- phy/gui/gui.py +917 -0
- phy/gui/qt.py +700 -0
- phy/gui/state.py +248 -0
- phy/gui/static/fa-solid-900.ttf +0 -0
- phy/gui/static/icons/f015.png +0 -0
- phy/gui/static/icons/f01e.png +0 -0
- phy/gui/static/icons/f060.png +0 -0
- phy/gui/static/icons/f061.png +0 -0
- phy/gui/static/icons/f0a8.png +0 -0
- phy/gui/static/icons/f0a9.png +0 -0
- phy/gui/static/icons/f0c7.png +0 -0
- phy/gui/static/icons/f0e2.png +0 -0
- phy/gui/static/icons/f247.png +0 -0
- phy/gui/static/index.html +17 -0
- phy/gui/static/list.min.js +2 -0
- phy/gui/static/styles.css +134 -0
- phy/gui/static/table.min.js +50 -0
- phy/gui/tests/__init__.py +3 -0
- phy/gui/tests/conftest.py +36 -0
- phy/gui/tests/test_actions.py +409 -0
- phy/gui/tests/test_gui.py +315 -0
- phy/gui/tests/test_qt.py +201 -0
- phy/gui/tests/test_state.py +91 -0
- phy/gui/tests/test_widgets.py +411 -0
- phy/gui/widgets.py +1151 -0
- phy/plot/__init__.py +33 -0
- phy/plot/axes.py +258 -0
- phy/plot/base.py +939 -0
- phy/plot/gloo/__init__.py +27 -0
- phy/plot/gloo/array.py +84 -0
- phy/plot/gloo/atlas.py +171 -0
- phy/plot/gloo/buffer.py +105 -0
- phy/plot/gloo/framebuffer.py +404 -0
- phy/plot/gloo/gl.py +110 -0
- phy/plot/gloo/globject.py +141 -0
- phy/plot/gloo/gpudata.py +152 -0
- phy/plot/gloo/parser.py +238 -0
- phy/plot/gloo/program.py +632 -0
- phy/plot/gloo/shader.py +440 -0
- phy/plot/gloo/snippet.py +575 -0
- phy/plot/gloo/texture.py +489 -0
- phy/plot/gloo/uniforms.py +247 -0
- phy/plot/gloo/variable.py +453 -0
- phy/plot/glsl/constants.glsl +48 -0
- phy/plot/glsl/histogram.frag +5 -0
- phy/plot/glsl/histogram.vert +17 -0
- phy/plot/glsl/image.frag +6 -0
- phy/plot/glsl/image.vert +9 -0
- phy/plot/glsl/line.frag +5 -0
- phy/plot/glsl/line.vert +8 -0
- phy/plot/glsl/line_agg_geom.frag +88 -0
- phy/plot/glsl/line_agg_geom.vert +18 -0
- phy/plot/glsl/markers/arrow.glsl +12 -0
- phy/plot/glsl/markers/asterisk.glsl +16 -0
- phy/plot/glsl/markers/chevron.glsl +14 -0
- phy/plot/glsl/markers/clover.glsl +20 -0
- phy/plot/glsl/markers/club.glsl +31 -0
- phy/plot/glsl/markers/cross.glsl +17 -0
- phy/plot/glsl/markers/diamond.glsl +12 -0
- phy/plot/glsl/markers/disc.glsl +9 -0
- phy/plot/glsl/markers/ellipse.glsl +67 -0
- phy/plot/glsl/markers/hbar.glsl +9 -0
- phy/plot/glsl/markers/heart.glsl +15 -0
- phy/plot/glsl/markers/infinity.glsl +15 -0
- phy/plot/glsl/markers/markers.glsl +24 -0
- phy/plot/glsl/markers/pin.glsl +18 -0
- phy/plot/glsl/markers/ring.glsl +11 -0
- phy/plot/glsl/markers/spade.glsl +28 -0
- phy/plot/glsl/markers/square.glsl +10 -0
- phy/plot/glsl/markers/tag.glsl +11 -0
- phy/plot/glsl/markers/triangle.glsl +14 -0
- phy/plot/glsl/markers/vbar.glsl +15 -0
- phy/plot/glsl/msdf.frag +69 -0
- phy/plot/glsl/msdf.vert +60 -0
- phy/plot/glsl/patch.frag +6 -0
- phy/plot/glsl/patch.vert +13 -0
- phy/plot/glsl/plot.frag +14 -0
- phy/plot/glsl/plot.vert +22 -0
- phy/plot/glsl/plot_agg.frag +23 -0
- phy/plot/glsl/plot_agg.vert +109 -0
- phy/plot/glsl/polygon.frag +5 -0
- phy/plot/glsl/polygon.vert +7 -0
- phy/plot/glsl/scatter.frag +15 -0
- phy/plot/glsl/scatter.vert +19 -0
- phy/plot/glsl/simple.frag +5 -0
- phy/plot/glsl/simple.vert +6 -0
- phy/plot/glsl/text.frag +14 -0
- phy/plot/glsl/text.vert +58 -0
- phy/plot/glsl/uni_plot.frag +14 -0
- phy/plot/glsl/uni_plot.vert +19 -0
- phy/plot/glsl/uni_scatter.frag +40 -0
- phy/plot/glsl/uni_scatter.vert +20 -0
- phy/plot/glsl/utils.glsl +101 -0
- phy/plot/interact.py +549 -0
- phy/plot/panzoom.py +589 -0
- phy/plot/plot.py +447 -0
- phy/plot/static/SourceCodePro-Regular.npy.gz +0 -0
- phy/plot/tests/__init__.py +63 -0
- phy/plot/tests/conftest.py +30 -0
- phy/plot/tests/test_axes.py +37 -0
- phy/plot/tests/test_base.py +229 -0
- phy/plot/tests/test_interact.py +312 -0
- phy/plot/tests/test_panzoom.py +323 -0
- phy/plot/tests/test_plot.py +214 -0
- phy/plot/tests/test_transform.py +274 -0
- phy/plot/tests/test_utils.py +56 -0
- phy/plot/tests/test_visuals.py +474 -0
- phy/plot/transform.py +540 -0
- phy/plot/utils.py +243 -0
- phy/plot/visuals.py +1579 -0
- phy/utils/__init__.py +29 -0
- phy/utils/color.py +342 -0
- phy/utils/config.py +85 -0
- phy/utils/context.py +218 -0
- phy/utils/plugin.py +160 -0
- phy/utils/profiling.py +145 -0
- phy/utils/tests/__init__.py +0 -0
- phy/utils/tests/conftest.py +37 -0
- phy/utils/tests/test_color.py +159 -0
- phy/utils/tests/test_config.py +141 -0
- phy/utils/tests/test_context.py +153 -0
- phy/utils/tests/test_plugin.py +85 -0
- phy/utils/tests/test_profiling.py +28 -0
- phy-2.1.0rc1.dist-info/METADATA +217 -0
- phy-2.1.0rc1.dist-info/RECORD +189 -0
- phy-2.1.0rc1.dist-info/WHEEL +5 -0
- phy-2.1.0rc1.dist-info/entry_points.txt +2 -0
- phy-2.1.0rc1.dist-info/licenses/LICENSE.md +12 -0
- phy-2.1.0rc1.dist-info/top_level.txt +1 -0
phy/__init__.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# flake8: noqa
|
|
2
|
+
|
|
3
|
+
"""phy: interactive visualization and manual spike sorting of large-scale ephys data."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# ------------------------------------------------------------------------------
|
|
7
|
+
# Imports
|
|
8
|
+
# ------------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
import atexit
|
|
11
|
+
import logging
|
|
12
|
+
import os.path as op
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
from io import StringIO
|
|
16
|
+
|
|
17
|
+
from phylib.utils import Bunch
|
|
18
|
+
from phylib.utils._misc import _git_version
|
|
19
|
+
from phylib.utils.event import connect, unconnect, emit
|
|
20
|
+
from .utils.config import load_master_config
|
|
21
|
+
from .utils.plugin import IPlugin, get_plugin, discover_plugins
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ------------------------------------------------------------------------------
|
|
25
|
+
# Global variables and functions
|
|
26
|
+
# ------------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
__author__ = 'Cyrille Rossant'
|
|
29
|
+
__email__ = 'cyrille.rossant at gmail.com'
|
|
30
|
+
__version__ = '2.1.0rc1'
|
|
31
|
+
__version_git__ = __version__ + _git_version()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Set a null handler on the root logger
|
|
35
|
+
logger = logging.getLogger()
|
|
36
|
+
logger.setLevel(logging.DEBUG)
|
|
37
|
+
logger.addHandler(logging.NullHandler())
|
|
38
|
+
logger.propagate = False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@atexit.register
|
|
42
|
+
def on_exit(): # pragma: no cover
|
|
43
|
+
# Close the logging handlers.
|
|
44
|
+
for handler in logger.handlers:
|
|
45
|
+
handler.close()
|
|
46
|
+
logger.removeHandler(handler)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test(): # pragma: no cover
|
|
50
|
+
"""Run the full testing suite of phy."""
|
|
51
|
+
import pytest
|
|
52
|
+
|
|
53
|
+
pytest.main()
|
phy/apps/__init__.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""CLI tool."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# ------------------------------------------------------------------------------
|
|
5
|
+
# Imports
|
|
6
|
+
# ------------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import sys
|
|
10
|
+
from contextlib import contextmanager
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from traceback import format_exception
|
|
13
|
+
|
|
14
|
+
import click
|
|
15
|
+
from phylib import _Formatter, _logger_date_fmt, _logger_fmt, add_default_handler # noqa # noqa
|
|
16
|
+
|
|
17
|
+
from phy import __version_git__
|
|
18
|
+
from phy.gui.qt import QtDialogLogger
|
|
19
|
+
from phy.utils.profiling import _enable_pdb, _enable_profiler
|
|
20
|
+
|
|
21
|
+
from .base import BaseController, FeatureMixin, TemplateMixin, TraceMixin, WaveformMixin # noqa
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ------------------------------------------------------------------------------
|
|
27
|
+
# CLI utils
|
|
28
|
+
# ------------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
DEBUG = False
|
|
31
|
+
if '--debug' in sys.argv: # pragma: no cover
|
|
32
|
+
DEBUG = True
|
|
33
|
+
sys.argv.remove('--debug')
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if '--pdb' in sys.argv: # pragma: no cover
|
|
37
|
+
sys.argv.remove('--pdb')
|
|
38
|
+
_enable_pdb()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Add `profile` in the builtins.
|
|
42
|
+
if '--lprof' in sys.argv or '--prof' in sys.argv: # pragma: no cover
|
|
43
|
+
_enable_profiler('--lprof' in sys.argv)
|
|
44
|
+
if '--prof' in sys.argv:
|
|
45
|
+
sys.argv.remove('--prof')
|
|
46
|
+
if '--lprof' in sys.argv:
|
|
47
|
+
sys.argv.remove('--lprof')
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# ------------------------------------------------------------------------------
|
|
51
|
+
# Set up logging with the CLI tool
|
|
52
|
+
# ------------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def exceptionHandler(exception_type, exception, traceback): # pragma: no cover
|
|
56
|
+
tb = ''.join(format_exception(exception_type, exception, traceback))
|
|
57
|
+
logger.error('An error has occurred (%s): %s\n%s', exception_type.__name__, exception, tb)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@contextmanager
|
|
61
|
+
def capture_exceptions(): # pragma: no cover
|
|
62
|
+
"""Log exceptions instead of crashing the GUI, and display an error dialog on errors."""
|
|
63
|
+
logger.debug('Start capturing exceptions.')
|
|
64
|
+
|
|
65
|
+
# Add a custom exception hook.
|
|
66
|
+
excepthook = sys.excepthook
|
|
67
|
+
sys.excepthook = exceptionHandler
|
|
68
|
+
|
|
69
|
+
# Add a dialog exception handler.
|
|
70
|
+
handler = QtDialogLogger()
|
|
71
|
+
handler.setLevel(logging.ERROR)
|
|
72
|
+
logging.getLogger('phy').addHandler(handler)
|
|
73
|
+
|
|
74
|
+
yield
|
|
75
|
+
|
|
76
|
+
# Reset the original exception hook.
|
|
77
|
+
sys.excepthook = excepthook
|
|
78
|
+
|
|
79
|
+
# Remove the dialog exception handler.
|
|
80
|
+
logging.getLogger('phy').removeHandler(handler)
|
|
81
|
+
|
|
82
|
+
logger.debug('Stop capturing exceptions.')
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# ------------------------------------------------------------------------------
|
|
86
|
+
# Root CLI tool
|
|
87
|
+
# ------------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@click.group()
|
|
91
|
+
@click.version_option(version=__version_git__)
|
|
92
|
+
@click.help_option('-h', '--help')
|
|
93
|
+
@click.pass_context
|
|
94
|
+
def phycli(ctx):
|
|
95
|
+
"""Interactive visualization and manual spike sorting of large-scale ephys data."""
|
|
96
|
+
add_default_handler(level='DEBUG' if DEBUG else 'INFO', logger=logging.getLogger('phy'))
|
|
97
|
+
add_default_handler(level='DEBUG' if DEBUG else 'INFO', logger=logging.getLogger('phylib'))
|
|
98
|
+
add_default_handler(level='DEBUG' if DEBUG else 'INFO', logger=logging.getLogger('mtscomp'))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# ------------------------------------------------------------------------------
|
|
102
|
+
# GUI command wrapper
|
|
103
|
+
# ------------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _gui_command(f):
|
|
107
|
+
"""Command options for GUI commands."""
|
|
108
|
+
f = click.option(
|
|
109
|
+
'--clear-cache/--no-clear-cache',
|
|
110
|
+
default=False,
|
|
111
|
+
help='Clear the .phy cache in the data directory.',
|
|
112
|
+
)(f)
|
|
113
|
+
f = click.option(
|
|
114
|
+
'--clear-state/--no-clear-state',
|
|
115
|
+
default=False,
|
|
116
|
+
help='Clear the GUI state in `~/.phy/` and in `.phy`.',
|
|
117
|
+
)(f)
|
|
118
|
+
return f
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ------------------------------------------------------------------------------
|
|
122
|
+
# Raw data GUI
|
|
123
|
+
# ------------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@phycli.command('trace-gui') # pragma: no cover
|
|
127
|
+
@click.argument('dat-path', type=click.Path(exists=True))
|
|
128
|
+
@click.option('-s', '--sample-rate', type=float)
|
|
129
|
+
@click.option('-d', '--dtype', type=str)
|
|
130
|
+
@click.option('-n', '--n-channels', type=int)
|
|
131
|
+
@click.option('-h', '--offset', type=int)
|
|
132
|
+
@click.option('-f', '--fortran', type=bool, is_flag=True)
|
|
133
|
+
@_gui_command
|
|
134
|
+
@click.pass_context
|
|
135
|
+
def cli_trace_gui(ctx, dat_path, **kwargs):
|
|
136
|
+
"""Launch the trace GUI on a raw data file."""
|
|
137
|
+
from .trace.gui import trace_gui
|
|
138
|
+
|
|
139
|
+
with capture_exceptions():
|
|
140
|
+
kwargs['n_channels_dat'] = kwargs.pop('n_channels')
|
|
141
|
+
kwargs['order'] = 'F' if kwargs.pop('fortran', None) else None
|
|
142
|
+
trace_gui(dat_path, **kwargs)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# ------------------------------------------------------------------------------
|
|
146
|
+
# Template GUI
|
|
147
|
+
# ------------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@phycli.command('template-gui') # pragma: no cover
|
|
151
|
+
@click.argument('params-path', type=click.Path(exists=True))
|
|
152
|
+
@_gui_command
|
|
153
|
+
@click.pass_context
|
|
154
|
+
def cli_template_gui(ctx, params_path, **kwargs):
|
|
155
|
+
"""Launch the template GUI on a params.py file."""
|
|
156
|
+
from .template.gui import template_gui
|
|
157
|
+
|
|
158
|
+
prof = __builtins__.get('profile', None)
|
|
159
|
+
with capture_exceptions():
|
|
160
|
+
if prof:
|
|
161
|
+
from phy.utils.profiling import _profile
|
|
162
|
+
|
|
163
|
+
return _profile(prof, 'template_gui(params_path)', globals(), locals())
|
|
164
|
+
template_gui(params_path, **kwargs)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@phycli.command('template-describe')
|
|
168
|
+
@click.argument('params-path', type=click.Path(exists=True))
|
|
169
|
+
@click.pass_context
|
|
170
|
+
def cli_template_describe(ctx, params_path):
|
|
171
|
+
"""Describe a template file."""
|
|
172
|
+
from .template.gui import template_describe
|
|
173
|
+
|
|
174
|
+
template_describe(params_path)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# ------------------------------------------------------------------------------
|
|
178
|
+
# Kwik GUI
|
|
179
|
+
# ------------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# Create the `phy cluster-manual file.kwik` command.
|
|
183
|
+
@phycli.command('kwik-gui') # pragma: no cover
|
|
184
|
+
@click.argument('path', type=click.Path(exists=True))
|
|
185
|
+
@click.option('--channel-group', type=int)
|
|
186
|
+
@click.option('--clustering', type=str)
|
|
187
|
+
@_gui_command
|
|
188
|
+
@click.pass_context
|
|
189
|
+
def cli_kwik_gui(ctx, path, channel_group=None, clustering=None, **kwargs):
|
|
190
|
+
"""Launch the Kwik GUI on a Kwik file."""
|
|
191
|
+
from .kwik.gui import kwik_gui
|
|
192
|
+
|
|
193
|
+
with capture_exceptions():
|
|
194
|
+
assert path
|
|
195
|
+
kwik_gui(path, channel_group=channel_group, clustering=clustering, **kwargs)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@phycli.command('kwik-describe')
|
|
199
|
+
@click.argument('path', type=click.Path(exists=True))
|
|
200
|
+
@click.option('--channel-group', type=int, help='channel group')
|
|
201
|
+
@click.option('--clustering', type=str, help='clustering')
|
|
202
|
+
@click.pass_context
|
|
203
|
+
def cli_kwik_describe(ctx, path, channel_group=0, clustering='main'):
|
|
204
|
+
"""Describe a Kwik file."""
|
|
205
|
+
from .kwik.gui import kwik_describe
|
|
206
|
+
|
|
207
|
+
assert path
|
|
208
|
+
kwik_describe(path, channel_group=channel_group, clustering=clustering)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# ------------------------------------------------------------------------------
|
|
212
|
+
# Conversion
|
|
213
|
+
# ------------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@phycli.command('alf-convert')
|
|
217
|
+
@click.argument('subdirs', nargs=-1, type=click.Path(exists=True, file_okay=False, dir_okay=True))
|
|
218
|
+
@click.argument('out_dir', type=click.Path())
|
|
219
|
+
@click.pass_context
|
|
220
|
+
def cli_alf_convert(ctx, subdirs, out_dir):
|
|
221
|
+
"""Convert an ephys dataset into ALF. If several directories are specified, it is assumed
|
|
222
|
+
that each directory contains the data for one probe of the same recording."""
|
|
223
|
+
from phylib.io.alf import EphysAlfCreator
|
|
224
|
+
from phylib.io.merge import Merger
|
|
225
|
+
from phylib.io.model import load_model
|
|
226
|
+
|
|
227
|
+
out_dir = Path(out_dir)
|
|
228
|
+
|
|
229
|
+
if len(subdirs) >= 2:
|
|
230
|
+
# Merge in the `merged` subdirectory inside the output directory.
|
|
231
|
+
m = Merger(subdirs, out_dir / '_tmp_merged')
|
|
232
|
+
model = m.merge()
|
|
233
|
+
else:
|
|
234
|
+
model = load_model(Path(subdirs[0]) / 'params.py')
|
|
235
|
+
|
|
236
|
+
c = EphysAlfCreator(model)
|
|
237
|
+
c.convert(out_dir)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
# ------------------------------------------------------------------------------
|
|
241
|
+
# Waveform extraction
|
|
242
|
+
# ------------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@phycli.command('extract-waveforms')
|
|
246
|
+
@click.argument('params-path', type=click.Path(exists=True))
|
|
247
|
+
@click.argument('n_spikes_per_cluster', type=int, default=500)
|
|
248
|
+
@click.option('--nc', type=int, default=16)
|
|
249
|
+
@click.pass_context
|
|
250
|
+
def template_extract_waveforms(
|
|
251
|
+
ctx, params_path, n_spikes_per_cluster, nc=None
|
|
252
|
+
): # pragma: no cover
|
|
253
|
+
"""Extract spike waveforms."""
|
|
254
|
+
from phylib.io.model import load_model
|
|
255
|
+
|
|
256
|
+
model = load_model(params_path)
|
|
257
|
+
model.save_spikes_subset_waveforms(
|
|
258
|
+
max_n_spikes_per_template=n_spikes_per_cluster, max_n_channels=nc
|
|
259
|
+
)
|
|
260
|
+
model.close()
|