Skip to content

Commit a8e93d1

Browse files
committed
2 parents 4ab2a6c + 7a4fba9 commit a8e93d1

File tree

15 files changed

+897
-239
lines changed

15 files changed

+897
-239
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# User data
2+
.DS_Store
3+
14
# Byte-compiled / optimized / DLL files
25
__pycache__/
36
*.py[cod]

Background.md

Lines changed: 0 additions & 73 deletions
This file was deleted.

README.md

Lines changed: 103 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,148 @@
11
# DataJoint Element - Array Electrophysiology Element
2-
DataJoint Element for array electrophysiology.
32

4-
This repository features DataJoint pipeline design for extracellular array electrophysiology,
5-
with ***Neuropixels*** probe and ***kilosort*** spike sorting method.
3+
+ This repository features DataJoint pipeline design for extracellular array electrophysiology,
4+
with Neuropixels probe and Kilosort spike sorting method.
65

7-
The pipeline presented here is not a complete pipeline by itself, but rather a modular
6+
+ The pipeline presented here is not a complete pipeline by itself, but rather a modular
87
design of tables and dependencies specific to the extracellular electrophysiology workflow.
98

10-
This modular pipeline element can be flexibly attached downstream
9+
+ This modular pipeline element can be flexibly attached downstream
1110
to any particular design of experiment session, thus assembling a fully functional
1211
ephys pipeline.
1312

14-
See [Background](Background.md) for the background information and development timeline.
13+
+ See the [Element Array Electrophysiology documentation](https://elements.datajoint.org/description/array_ephys/) for the background information and development timeline.
1514

16-
## The Pipeline Architecture
15+
+ For more information on the DataJoint Elements project, please visit https://elements.datajoint.org. This work is supported by the National Institutes of Health.
16+
17+
## Element architecture
1718

1819
![element-array-ephys diagram](images/attached_array_ephys_element.svg)
1920

20-
As the diagram depicts, the array ephys element starts immediately downstream from ***Session***,
21-
and also requires some notion of ***Location*** as a dependency for ***InsertionLocation***.
21+
As the diagram depicts, the array ephys element starts immediately downstream from `Session`,
22+
and also requires some notion of `Location` as a dependency for `InsertionLocation`. We
23+
provide an [example workflow](https://github.com/datajoint/workflow-array-ephys/) with a
24+
[pipeline script](https://github.com/datajoint/workflow-array-ephys/blob/main/workflow_array_ephys/pipeline.py)
25+
that models (a) combining this Element with the corresponding [Element-Session](https://github.com/datajoint/element-session)
26+
, and (b) declaring a `SkullReference` table to provide Location.
27+
28+
## Table descriptions
29+
30+
### Probe & electrodes
31+
32+
The `probe` schema contains information regarding the Neuropixels probe and electrode configuration.
2233

23-
### The design of probe
34+
<details>
35+
<summary>Click to expand details</summary>
2436

25-
+ ***ProbeType*** - a lookup table specifying the type of Neuropixels probe (e.g. "neuropixels 1.0", "neuropixels 2.0 single-shank")
26-
+ ***ProbeType.Electrode*** - all electrode and their properties for a particular probe type
37+
+ `ProbeType` - a lookup table specifying the type of Neuropixels probe (e.g. "neuropixels 1.0", "neuropixels 2.0 single-shank")
38+
39+
+ `ProbeType.Electrode` - all electrode and their properties for a particular probe type
2740
+ An electrode here refers to one recordable electrode site on the Neuropixels probe (e.g. for Neuropixels 1.0, there are 960 sites per shank)
28-
+ ***Probe*** - record of an actual physical probe, identifiable by some unique ID (e.g. probe's serial number)
29-
+ ***ElectrodeConfig*** - particular electrode configuration to be used for ephys recording
30-
+ ***ElectrodeConfig.Electrode*** - corresponding electrodes in ***ProbeType.Electrode*** that are used for recording in this electrode configuration (e.g. for Neuropixels 1.0 or 2.0, there can be at most 384 electrodes usable for recording per probe)
3141

32-
### Extracellular ephys recording
42+
+ `Probe` - record of an actual physical probe, identifiable by some unique ID (e.g. probe's serial number)
43+
44+
+ `ElectrodeConfig` - particular electrode configuration to be used for ephys recording
45+
46+
+ `ElectrodeConfig.Electrode` - corresponding electrodes in `ProbeType.Electrode` that are used for recording in this electrode configuration (e.g. for Neuropixels 1.0 or 2.0, there can be at most 384 electrodes usable for recording per probe)
47+
48+
</details>
49+
50+
### Extracellular electrophysiology recording
51+
52+
The `ephys` schema stores information regarding the recording from a probe for a given session.
53+
54+
<details>
55+
<summary>Click to expand details</summary>
56+
57+
+ `ProbeInsertion` - a surgical insertion of a probe in the brain. Every experimental session consists of one or more entries in `ProbeInsertion` with a corresponding `InsertionLocation` each
58+
59+
+ `EphysRecording` - each `ProbeInsertion` is accompanied by a corresponding `EphysRecording`, specifying the `ElectrodeConfig` used for the recording from the `Probe` defined in such `ProbeInsertion`
60+
61+
</details>
3362

34-
+ ***ProbeInsertion*** - a surgical insertion of a probe in the brain. Every experimental session consists of one or more entries in ***ProbeInsertion*** with a corresponding ***InsertionLocation*** each
35-
+ ***EphysRecording*** - each ***ProbeInsertion*** is accompanied by a corresponding ***EphysRecording***, specifying the ***ElectrodeConfig*** used for the recording from the ***Probe*** defined in such ***ProbeInsertion***
36-
3763
### Clusters and spikes
3864

39-
This ephys element features automatic ingestion for spike sorting results from the ***kilosort*** method.
65+
The `ephys` schema features automatic ingestion of spike sorting results from the `Kilosort` analysis method.
66+
67+
<details>
68+
<summary>Click to expand details</summary>
4069

41-
+ ***Clustering*** - specify instance(s) of clustering on an ***EphysRecording***, by some ***ClusteringMethod***
42-
+ ***Curation*** - specify instance(s) of curations performed on the output of a given ***Clustering***
43-
+ ***CuratedClustering*** - set of results from a particular round of clustering/curation
44-
+ ***CuratedClustering.Unit*** - Identified unit(s) from one ***Curation***, and the associated properties (e.g. cluster quality, spike times, spike depths, etc.)
45-
+ ***WaveformSet*** - A set of spike waveforms for units from a given CuratedClustering
70+
+ `Clustering` - specify instance(s) of clustering on an `EphysRecording`, by some `ClusteringMethod`
71+
72+
+ `Curation` - specify instance(s) of curations performed on the output of a given `Clustering`
73+
74+
+ `CuratedClustering` - set of results from a particular round of clustering/curation
75+
+ `CuratedClustering.Unit` - Identified unit(s) from one `Curation`, and the associated properties (e.g. cluster quality, spike times, spike depths, etc.)
76+
+ `WaveformSet` - A set of spike waveforms for units from a given CuratedClustering
77+
78+
</details>
4679

4780
## Installation
48-
```
49-
pip install element-array-ephys
50-
```
81+
<details>
82+
<summary>Click to expand details</summary>
83+
84+
+ Install `element-array-ephys`
85+
```
86+
pip install element-array-ephys
87+
```
5188
52-
If you already have an older version of ***element-array-ephys*** installed using `pip`, upgrade with
53-
```
54-
pip install --upgrade element-array-ephys
55-
```
89+
+ Upgrade `element-array-ephys` previously installed with `pip`
90+
```
91+
pip install --upgrade element-array-ephys
92+
```
93+
94+
+ Install `element-interface`
95+
+ `element-interface` is a dependency of `element-array-ephys`, however it is not contained within `requirements.txt`.
96+
```
97+
pip install "element-interface @ git+https://github.com/datajoint/element-interface"
98+
```
99+
100+
</details>
56101
57102
## Usage
58103
59104
### Element activation
60105
106+
When using this Element, one needs to run `ephys.activate` to declare the schemas and tables on the database.
107+
108+
<details>
109+
<summary>Click to expand details</summary>
110+
61111
To activate the `element-array-ephys`, ones need to provide:
62112
63113
1. Schema names
64114
+ schema name for the probe module
65115
+ schema name for the ephys module
66116
67117
2. Upstream tables
68-
+ Session table
69-
+ SkullReference table (Reference table for InsertionLocation, specifying the skull reference)
118+
+ Session table: A set of keys identifying a recording session (see [Element-Session](https://github.com/datajoint/element-session)).
119+
+ SkullReference table: A reference table for InsertionLocation, specifying the skull reference (see [example pipeline](https://github.com/datajoint/workflow-array-ephys/blob/main/workflow_array_ephys/pipeline.py)).
70120
71-
3. Utility functions
72-
+ get_ephys_root_data_dir()
73-
+ get_session_directory()
121+
3. Utility functions. See [example definitions here](https://github.com/datajoint/workflow-array-ephys/blob/main/workflow_array_ephys/paths.py)
122+
+ get_ephys_root_data_dir(): Returns your root data directory.
123+
+ get_session_directory(): Returns the path of the session data relative to the root.
74124
75125
For more detail, check the docstring of the `element-array-ephys`:
76126
77127
help(probe.activate)
78128
help(ephys.activate)
79129
130+
</details>
131+
80132
### Example usage
81133
82134
See [this project](https://github.com/datajoint/workflow-array-ephys) for an example usage of this Array Electrophysiology Element.
135+
136+
## Citation
137+
138+
+ If your work uses DataJoint and DataJoint Elements, please cite the respective Research Resource Identifiers (RRIDs) and manuscripts.
139+
140+
+ DataJoint for Python or MATLAB
141+
+ Yatsenko D, Reimer J, Ecker AS, Walker EY, Sinz F, Berens P, Hoenselaar A, Cotton RJ, Siapas AS, Tolias AS. DataJoint: managing big scientific data using MATLAB or Python. bioRxiv. 2015 Jan 1:031658. doi: https://doi.org/10.1101/031658
142+
143+
+ DataJoint ([RRID:SCR_014543](https://scicrunch.org/resolver/SCR_014543)) - DataJoint for `<Select Python or MATLAB>` (version `<Enter version number>`)
144+
145+
+ DataJoint Elements
146+
+ Yatsenko D, Nguyen T, Shen S, Gunalan K, Turner CA, Guzman R, Sasaki M, Sitonic D, Reimer J, Walker EY, Tolias AS. DataJoint Elements: Data Workflows for Neurophysiology. bioRxiv. 2021 Jan 1. doi: https://doi.org/10.1101/2021.03.30.437358
147+
148+
+ DataJoint Elements ([RRID:SCR_021894](https://scicrunch.org/resolver/SCR_021894)) - Element Array Electrophysiology (version `<Enter version number>`)

element_array_ephys/__init__.py

Lines changed: 2 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,2 @@
1-
import datajoint as dj
2-
import pathlib
3-
import uuid
4-
import hashlib
5-
6-
7-
dj.config['enable_python_native_blobs'] = True
8-
9-
10-
def find_full_path(root_directories, relative_path):
11-
"""
12-
Given a relative path, search and return the full-path
13-
from provided potential root directories (in the given order)
14-
:param root_directories: potential root directories
15-
:param relative_path: the relative path to find the valid root directory
16-
:return: root_directory (pathlib.Path object)
17-
"""
18-
relative_path = pathlib.Path(relative_path)
19-
20-
if relative_path.exists():
21-
return relative_path
22-
23-
# turn to list if only a single root directory is provided
24-
if isinstance(root_directories, (str, pathlib.Path)):
25-
root_directories = [root_directories]
26-
27-
for root_dir in root_directories:
28-
if (pathlib.Path(root_dir) / relative_path).exists():
29-
return pathlib.Path(root_dir) / relative_path
30-
31-
raise FileNotFoundError('No valid full-path found (from {})'
32-
' for {}'.format(root_directories, relative_path))
33-
34-
35-
def find_root_directory(root_directories, full_path):
36-
"""
37-
Given multiple potential root directories and a full-path,
38-
search and return one directory that is the parent of the given path
39-
:param root_directories: potential root directories
40-
:param full_path: the relative path to search the root directory
41-
:return: full-path (pathlib.Path object)
42-
"""
43-
full_path = pathlib.Path(full_path)
44-
45-
if not full_path.exists():
46-
raise FileNotFoundError(f'{full_path} does not exist!')
47-
48-
# turn to list if only a single root directory is provided
49-
if isinstance(root_directories, (str, pathlib.Path)):
50-
root_directories = [root_directories]
51-
52-
try:
53-
return next(pathlib.Path(root_dir) for root_dir in root_directories
54-
if pathlib.Path(root_dir) in set(full_path.parents))
55-
56-
except StopIteration:
57-
raise FileNotFoundError('No valid root directory found (from {})'
58-
' for {}'.format(root_directories, full_path))
59-
60-
61-
def dict_to_uuid(key):
62-
"""
63-
Given a dictionary `key`, returns a hash string as UUID
64-
"""
65-
hashed = hashlib.md5()
66-
for k, v in sorted(key.items()):
67-
hashed.update(str(k).encode())
68-
hashed.update(str(v).encode())
69-
return uuid.UUID(hex=hashed.hexdigest())
1+
# ephys_acute as default
2+
import element_array_ephys.ephys_acute as ephys

0 commit comments

Comments
 (0)