Skip to content

Commit 26b6be9

Browse files
committed
pull upstream & resolve merge conflicts
2 parents 68fa77c + c3ad36f commit 26b6be9

30 files changed

+1973
-1011
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,6 @@ docker-compose.y*ml
123123
# vscode settings
124124
.vscode
125125
*.code-workspace
126+
127+
# exports/notes
128+
temp*

.pre-commit-config.yaml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
default_stages: [commit, push]
2+
exclude: (^.github/|^docs/|^images/)
3+
4+
repos:
5+
- repo: https://github.com/pre-commit/pre-commit-hooks
6+
rev: v4.4.0
7+
hooks:
8+
- id: trailing-whitespace
9+
- id: end-of-file-fixer
10+
- id: check-yaml
11+
- id: check-added-large-files # prevent giant files from being committed
12+
- id: requirements-txt-fixer
13+
- id: mixed-line-ending
14+
args: ["--fix=lf"]
15+
description: Forces to replace line ending by the UNIX 'lf' character.
16+
17+
# black
18+
- repo: https://github.com/psf/black
19+
rev: 22.12.0
20+
hooks:
21+
- id: black
22+
- id: black-jupyter
23+
args:
24+
- --line-length=88
25+
26+
# isort
27+
- repo: https://github.com/pycqa/isort
28+
rev: 5.11.2
29+
hooks:
30+
- id: isort
31+
args: ["--profile", "black"]
32+
description: Sorts imports in an alphabetical order
33+
34+
# flake8
35+
- repo: https://github.com/pycqa/flake8
36+
rev: 4.0.1
37+
hooks:
38+
- id: flake8
39+
args: # arguments to configure flake8
40+
# making isort line length compatible with black
41+
- "--max-line-length=88"
42+
- "--max-complexity=18"
43+
- "--select=B,C,E,F,W,T4,B9"
44+
45+
# these are errors that will be ignored by flake8
46+
# https://www.flake8rules.com/rules/{code}.html
47+
- "--ignore=E203,E501,W503,W605"
48+
# E203 - Colons should not have any space before them.
49+
# Needed for list indexing
50+
# E501 - Line lengths are recommended to be no greater than 79 characters.
51+
# Needed as we conform to 88
52+
# W503 - Line breaks should occur after the binary operator.
53+
# Needed because not compatible with black
54+
# W605 - a backslash-character pair that is not a valid escape sequence now
55+
# generates a DeprecationWarning. This will eventually become a SyntaxError.
56+
# Needed because we use \d as an escape sequence

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Observes [Semantic Versioning](https://semver.org/spec/v2.0.0.html) standard and
3434

3535
+ Update - Rename module for acute probe insertions from `ephys.py` to `ephys_acute.py`.
3636
+ Add - Module for pre-clustering steps (`ephys_precluster.py`), which is built off of `ephys_acute.py`.
37-
+ Add - Module for chronic probe insertions (`ephys_chronic.py`).
37+
+ Add - Module for chronic probe insertions (`ephys_chronic.py`).
3838
+ Bugfix - Missing `fileTimeSecs` key in SpikeGLX meta file.
3939
+ Update - Move common functions to `element-interface` package.
4040
+ Add - NWB export function
@@ -55,7 +55,7 @@ Observes [Semantic Versioning](https://semver.org/spec/v2.0.0.html) standard and
5555
+ Add - Readers for: `SpikeGLX`, `Open Ephys`, `Kilosort`
5656
+ Add - Probe table supporting: Neuropixels probes 1.0 - 3A, 1.0 - 3B, 2.0 - SS,
5757
2.0 - MS
58-
58+
5959
[0.2.1]: https://github.com/datajoint/element-array-ephys/releases/tag/0.2.1
6060
[0.2.0]: https://github.com/datajoint/element-array-ephys/releases/tag/0.2.0
6161
[0.1.4]: https://github.com/datajoint/element-array-ephys/releases/tag/0.1.4

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Contribution Guidelines
22

3-
This project follows the [DataJoint Contribution Guidelines](https://docs.datajoint.io/python/community/02-Contribute.html). Please reference the link for more full details.
3+
This project follows the [DataJoint Contribution Guidelines](https://datajoint.com/docs/community/contribute/). Please reference the link for more full details.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ fully functional pipeline.
88

99
![diagram](https://raw.githubusercontent.com/datajoint/element-array-ephys/main/images/diagram_flowchart.svg)
1010

11-
Installation and usage instructions can be found at the
11+
Installation and usage instructions can be found at the
1212
[Element documentation](https://datajoint.com/docs/elements/element-array-ephys).

docs/src/api/make_pages.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,3 @@
4141

4242
with mkdocs_gen_files.open("api/navigation.md", "w") as nav_file:
4343
nav_file.writelines(nav.build_literate_nav())
44-

docs/src/concepts.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ Tables related to information about physiological recordings and automatic inges
104104
| CuratedClusting.Unit | A part table containing single unit information after spike sorting and optional curation. |
105105
| WaveformSet | A table containing spike waveforms for single units. |
106106

107+
### `ephys_report` schema ([API docs](../api/element_array_ephys/ephys_report))
108+
Tables for storing probe or unit-level visualization results.
109+
110+
| Table | Description |
111+
| --- | --- |
112+
| ProbeLevelReport | A table to store drift map figures generated from each recording probe. |
113+
| UnitLevelReport | A table to store figures (waveforms, autocorrelogram, peak waveform + neighbors) generated for each unit. |
114+
107115
## Element Development
108116

109117
Through our interviews and direct collaboration on the precursor projects, we identified the common motifs to create the [Array Electrophysiology Element](https://github.com/datajoint/element-array-ephys).

element_array_ephys/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import datajoint as dj
21
import logging
32
import os
43

4+
import datajoint as dj
5+
6+
from . import ephys_acute as ephys
7+
8+
__all__ = ["ephys", "get_logger"]
59

610
dj.config["enable_python_native_blobs"] = True
711

@@ -10,6 +14,3 @@ def get_logger(name):
1014
log = logging.getLogger(name)
1115
log.setLevel(os.getenv("LOGLEVEL", "INFO"))
1216
return log
13-
14-
15-
from . import ephys_acute as ephys

element_array_ephys/ephys_acute.py

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import datajoint as dj
1+
import gc
2+
import importlib
3+
import inspect
24
import pathlib
35
import re
4-
import numpy as np
5-
import inspect
6-
import importlib
7-
import gc
86
from decimal import Decimal
9-
import pandas as pd
107

11-
from element_interface.utils import find_root_directory, find_full_path, dict_to_uuid
8+
import datajoint as dj
9+
import numpy as np
10+
import pandas as pd
11+
from element_interface.utils import dict_to_uuid, find_full_path, find_root_directory
1212

13-
from .readers import spikeglx, kilosort, openephys
14-
from . import probe, get_logger, ephys_report
13+
from . import ephys_report, get_logger, probe
14+
from .readers import kilosort, openephys, spikeglx
1515

1616
log = get_logger(__name__)
1717

@@ -127,7 +127,7 @@ class AcquisitionSoftware(dj.Lookup):
127127
"""
128128

129129
definition = """ # Software used for recording of neuropixels probes
130-
acq_software: varchar(24)
130+
acq_software: varchar(24)
131131
"""
132132
contents = zip(["SpikeGLX", "Open Ephys"])
133133

@@ -264,7 +264,7 @@ class EphysRecording(dj.Imported):
264264

265265
definition = """
266266
# Ephys recording from a probe insertion for a given session.
267-
-> ProbeInsertion
267+
-> ProbeInsertion
268268
---
269269
-> probe.ElectrodeConfig
270270
-> AcquisitionSoftware
@@ -465,9 +465,9 @@ class Electrode(dj.Part):
465465

466466
definition = """
467467
-> master
468-
-> probe.ElectrodeConfig.Electrode
468+
-> probe.ElectrodeConfig.Electrode
469469
---
470-
lfp: longblob # (uV) recorded lfp at this electrode
470+
lfp: longblob # (uV) recorded lfp at this electrode
471471
"""
472472

473473
# Only store LFP for every 9th channel, due to high channel density,
@@ -615,7 +615,7 @@ class ClusteringParamSet(dj.Lookup):
615615
# Parameter set to be used in a clustering procedure
616616
paramset_idx: smallint
617617
---
618-
-> ClusteringMethod
618+
-> ClusteringMethod
619619
paramset_desc: varchar(128)
620620
param_set_hash: uuid
621621
unique index (param_set_hash)
@@ -800,7 +800,7 @@ class Clustering(dj.Imported):
800800
# Clustering Procedure
801801
-> ClusteringTask
802802
---
803-
clustering_time: datetime # time of generation of this set of clustering results
803+
clustering_time: datetime # time of generation of this set of clustering results
804804
package_version='': varchar(16)
805805
"""
806806

@@ -841,6 +841,10 @@ def make(self, key):
841841
spikeglx_meta_filepath.parent
842842
)
843843
spikeglx_recording.validate_file("ap")
844+
run_CatGT = (
845+
params.pop("run_CatGT", True)
846+
and "_tcat." not in spikeglx_meta_filepath.stem
847+
)
844848

845849
if clustering_method.startswith("pykilosort"):
846850
kilosort_triggering.run_pykilosort(
@@ -861,7 +865,7 @@ def make(self, key):
861865
ks_output_dir=kilosort_dir,
862866
params=params,
863867
KS2ver=f'{Decimal(clustering_method.replace("kilosort", "")):.1f}',
864-
run_CatGT=True,
868+
run_CatGT=run_CatGT,
865869
)
866870
run_kilosort.run_modules()
867871
elif acq_software == "Open Ephys":
@@ -925,11 +929,11 @@ class Curation(dj.Manual):
925929
-> Clustering
926930
curation_id: int
927931
---
928-
curation_time: datetime # time of generation of this set of curated clustering results
932+
curation_time: datetime # time of generation of this set of curated clustering results
929933
curation_output_dir: varchar(255) # output directory of the curated results, relative to root data directory
930934
quality_control: bool # has this clustering result undergone quality control?
931935
manual_curation: bool # has manual curation been performed on this clustering result?
932-
curation_note='': varchar(2000)
936+
curation_note='': varchar(2000)
933937
"""
934938

935939
def create1_from_clustering_task(self, key, curation_note=""):
@@ -978,7 +982,7 @@ class CuratedClustering(dj.Imported):
978982

979983
definition = """
980984
# Clustering results of a curation.
981-
-> Curation
985+
-> Curation
982986
"""
983987

984988
class Unit(dj.Part):
@@ -1005,7 +1009,7 @@ class Unit(dj.Part):
10051009
spike_count: int # how many spikes in this recording for this unit
10061010
spike_times: longblob # (s) spike times of this unit, relative to the start of the EphysRecording
10071011
spike_sites : longblob # array of electrode associated with each spike
1008-
spike_depths=null : longblob # (um) array of depths associated with each spike, relative to the (0, 0) of the probe
1012+
spike_depths=null : longblob # (um) array of depths associated with each spike, relative to the (0, 0) of the probe
10091013
"""
10101014

10111015
def make(self, key):
@@ -1131,8 +1135,8 @@ class Waveform(dj.Part):
11311135
# Spike waveforms and their mean across spikes for the given unit
11321136
-> master
11331137
-> CuratedClustering.Unit
1134-
-> probe.ElectrodeConfig.Electrode
1135-
---
1138+
-> probe.ElectrodeConfig.Electrode
1139+
---
11361140
waveform_mean: longblob # (uV) mean waveform across spikes of the given unit
11371141
waveforms=null: longblob # (uV) (spike x sample) waveforms of a sampling of spikes at the given electrode for the given unit
11381142
"""
@@ -1260,7 +1264,7 @@ class QualityMetrics(dj.Imported):
12601264

12611265
definition = """
12621266
# Clusters and waveforms metrics
1263-
-> CuratedClustering
1267+
-> CuratedClustering
12641268
"""
12651269

12661270
class Cluster(dj.Part):
@@ -1285,26 +1289,26 @@ class Cluster(dj.Part):
12851289
contamination_rate (float): Frequency of spikes in the refractory period.
12861290
"""
12871291

1288-
definition = """
1292+
definition = """
12891293
# Cluster metrics for a particular unit
12901294
-> master
12911295
-> CuratedClustering.Unit
12921296
---
1293-
firing_rate=null: float # (Hz) firing rate for a unit
1297+
firing_rate=null: float # (Hz) firing rate for a unit
12941298
snr=null: float # signal-to-noise ratio for a unit
12951299
presence_ratio=null: float # fraction of time in which spikes are present
12961300
isi_violation=null: float # rate of ISI violation as a fraction of overall rate
12971301
number_violation=null: int # total number of ISI violations
12981302
amplitude_cutoff=null: float # estimate of miss rate based on amplitude histogram
12991303
isolation_distance=null: float # distance to nearest cluster in Mahalanobis space
1300-
l_ratio=null: float #
1304+
l_ratio=null: float #
13011305
d_prime=null: float # Classification accuracy based on LDA
13021306
nn_hit_rate=null: float # Fraction of neighbors for target cluster that are also in target cluster
13031307
nn_miss_rate=null: float # Fraction of neighbors outside target cluster that are in target cluster
13041308
silhouette_score=null: float # Standard metric for cluster overlap
13051309
max_drift=null: float # Maximum change in spike depth throughout recording
1306-
cumulative_drift=null: float # Cumulative change in spike depth throughout recording
1307-
contamination_rate=null: float #
1310+
cumulative_drift=null: float # Cumulative change in spike depth throughout recording
1311+
contamination_rate=null: float #
13081312
"""
13091313

13101314
class Waveform(dj.Part):
@@ -1324,7 +1328,7 @@ class Waveform(dj.Part):
13241328
velocity_below (float) inverse velocity of waveform propagation from soma toward the bottom of the probe.
13251329
"""
13261330

1327-
definition = """
1331+
definition = """
13281332
# Waveform metrics for a particular unit
13291333
-> master
13301334
-> CuratedClustering.Unit
@@ -1476,20 +1480,20 @@ def get_neuropixels_channel2electrode_map(
14761480
return channel2electrode_map
14771481

14781482

1479-
def generate_electrode_config(probe_type: str, electrodes: list) -> dict:
1483+
def generate_electrode_config(probe_type: str, electrode_keys: list) -> dict:
14801484
"""Generate and insert new ElectrodeConfig
14811485
14821486
Args:
14831487
probe_type (str): probe type (e.g. neuropixels 2.0 - SS)
1484-
electrodes (list): Electrode dict (keys of the probe.ProbeType.Electrode table)
1488+
electrode_keys (list): list of keys of the probe.ProbeType.Electrode table
14851489
14861490
Returns:
14871491
dict: representing a key of the probe.ElectrodeConfig table
14881492
"""
14891493
# compute hash for the electrode config (hash of dict of all ElectrodeConfig.Electrode)
1490-
electrode_config_hash = dict_to_uuid({k["electrode"]: k for k in electrodes})
1494+
electrode_config_hash = dict_to_uuid({k["electrode"]: k for k in electrode_keys})
14911495

1492-
electrode_list = sorted([k["electrode"] for k in electrodes])
1496+
electrode_list = sorted([k["electrode"] for k in electrode_keys])
14931497
electrode_gaps = (
14941498
[-1]
14951499
+ np.where(np.diff(electrode_list) > 1)[0].tolist()
@@ -1514,7 +1518,7 @@ def generate_electrode_config(probe_type: str, electrodes: list) -> dict:
15141518
}
15151519
)
15161520
probe.ElectrodeConfig.Electrode.insert(
1517-
{**electrode_config_key, **electrode} for electrode in electrodes
1521+
{**electrode_config_key, **electrode} for electrode in electrode_keys
15181522
)
15191523

15201524
return electrode_config_key

0 commit comments

Comments
 (0)