diff --git a/README.md b/README.md index b59fda94..85277136 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,9 @@ environment and notebooks to learn the pipeline. ## Getting Started + Please fork this repository. + + Clone the repository to your computer. + ```bash git clone https://github.com//element-array-ephys.git ``` @@ -38,6 +40,7 @@ environment and notebooks to learn the pipeline. ```bash pip install -e . ``` + + [Interactive tutorial on GitHub Codespaces](https://github.com/datajoint/element-array-ephys#interactive-tutorial) diff --git a/element_array_ephys/__init__.py b/element_array_ephys/__init__.py index 99acf32a..1c0c7285 100644 --- a/element_array_ephys/__init__.py +++ b/element_array_ephys/__init__.py @@ -1,19 +1 @@ -import os -import datajoint as dj - -if "custom" not in dj.config: - dj.config["custom"] = {} - -# overwrite dj.config['custom'] values with environment variables if available - -dj.config["custom"]["database.prefix"] = os.getenv( - "DATABASE_PREFIX", dj.config["custom"].get("database.prefix", "") -) - -dj.config["custom"]["ephys_root_data_dir"] = os.getenv( - "EPHYS_ROOT_DATA_DIR", dj.config["custom"].get("ephys_root_data_dir", "") -) - -db_prefix = dj.config["custom"].get("database.prefix", "") - from . import ephys_acute as ephys diff --git a/images/diagram_flowchart.drawio b/images/diagram_flowchart.drawio index b259ce3e..998e0220 100644 --- a/images/diagram_flowchart.drawio +++ b/images/diagram_flowchart.drawio @@ -1,6 +1,6 @@ - + - + diff --git a/images/diagram_flowchart.svg b/images/diagram_flowchart.svg index e8b1df4b..eed92b1c 100644 --- a/images/diagram_flowchart.svg +++ b/images/diagram_flowchart.svg @@ -1,4 +1,4 @@ -
Generate quality
control metrics
Generate quality...
Optionally
curate units
Optionally...
Acquire Neuropixels data with OpenEphys
 or SpikeGLX
Acquire Neuropixels...
Enter metadata
into pipeline
Enter metadata...
Process with
Kilosort
Process with...
Visualize



 
Visualize...

 Export & publish

 
 
Export & publish...
Synchronize data modalities
& exploratory
analysis
Synchronize data mo...
Text is not SVG - cannot display
\ No newline at end of file +
Generate quality
control metrics
Generate quality...
Optionally
curate units
Optionally...
Acquire Neuropixels data with OpenEphys
 or SpikeGLX
Acquire Neuropixels...
Enter metadata
into pipeline
Enter metadata...
Process with
Kilosort
Process with...
Visualize



 
Visualize...

 Export & publish

 
 
Export & publish...
Synchronize data modalities
& exploratory
analysis
Synchronize data mo...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/notebooks/tutorial.ipynb b/notebooks/tutorial.ipynb index 9cbec92c..954766ca 100644 --- a/notebooks/tutorial.ipynb +++ b/notebooks/tutorial.ipynb @@ -5,100 +5,56 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# DataJoint Elements for Array Electrophysiology with NeuroPixels" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Open-source Data Pipeline for Processing and Analyzing Extracellular Electrophysiology Datasets**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This tutorial aims to provide a comprehensive understanding of the open-source data pipeline by `element-array-ephys`. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![flowchart](../images/diagram_flowchart.svg)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The package is designed to **process NeuroPixels ephys data** with **OpenEphys** and spike sorted with **Kilosort**. The following Diagram corresponds to the `ephys_acute` module:" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![pipeline](../images/attached_array_ephys_element_acute.svg)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By the end of this tutorial, you will have a clear grasp of how to set up and integrate the `element-array-ephys` into your specific research projects and your lab." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### **Key Components and Objectives**\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**- Setup**\n", + "# DataJoint Elements for Array Electrophysiology with NeuroPixels\n", "\n", - "**- Designing the DataJoint Pipeline**\n", + "#### Open-source data pipeline for processing and analyzing extracellular electrophysiology datasets.\n", "\n", - "**- Step 1: Insert Example Data into Subject and Session tables**\n", + "Welcome to the tutorial for the DataJoint Element for extracellular array electrophysiology. This\n", + "tutorial aims to provide a comprehensive understanding of the open-source data pipeline\n", + "created using `element-array-ephys`.\n", "\n", - "**- Step 2: Register the Electrophysiology Recording information for each Probe**\n", + "This package is designed to seamlessly process, ingest, and track extracellular electrophysiology\n", + "data, along with its associated probe and recording metadata. By the end of this\n", + "tutorial you will have a clear grasp on setting up and integrating `element-array-ephys`\n", + "into your specific research projects and lab. \n", "\n", - "**- Step 3: Run the Clustering Task**\n", + "![flowchart](../images/diagram_flowchart.svg)\n", "\n", - "**- Step 4: Curate the Clustering Results (Optional)**\n", + "### Prerequisites\n", "\n", - "**- Step 5: Visualize the Results**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Setup**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This tutorial examines the `ephys_acute` module applied to physiological recordings and automatic ingestion of spike sorting results.\n", + "Please see the [datajoint tutorials GitHub\n", + "repository](https://github.com/datajoint/datajoint-tutorials/tree/main) before\n", + "proceeding.\n", "\n", - "The goal is to store, track and manage different curations of the spike sorting results and unit-level visualization results.\n", + "A basic understanding of the following DataJoint concepts will be beneficial to your\n", + "understanding of this tutorial: \n", + "1. The `Imported` and `Computed` tables types in `datajoint-python`.\n", + "2. The functionality of the `.populate()` method. \n", "\n", - "The results of this Element example can be combined with other modalities to create a complete customizable data pipeline for your specific lab or study. For instance, you can combine `element-array-ephys` with `element-calcium-imaging` and `element-deeplabcut` to characterize the neural activity." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's start this tutorial by importing the packages necessary to run the data pipeline." + "#### **Tutorial Overview**\n", + "\n", + "+ Setup\n", + "+ *Activate* the DataJoint pipeline.\n", + "+ *Insert* subject, session, and probe metadata.\n", + "+ *Populate* electrophysiology recording metadata.\n", + "+ Run the clustering task.\n", + "+ Curate the results (optional).\n", + "+ Visualize the results.\n", + "\n", + "### **Setup**\n", + "\n", + "This tutorial examines extracellular electrophysiology data acquired with `OpenEphys`\n", + "and spike-sorted using Kilosort 2.5. The goal is to store, track\n", + "and manage sessions of array electrophysiology data, including spike sorting results and\n", + "unit-level visualizations. \n", + "\n", + "The results of this Element can be combined with **other modalities** to create\n", + "a complete, customizable data pipeline for your specific lab or study. For instance, you\n", + "can combine `element-array-ephys` with `element-calcium-imaging` and\n", + "`element-deeplabcut` to characterize the neural activity along with markless\n", + "pose-estimation during behavior.\n", + "\n", + "Let's start this tutorial by importing the packages necessary to run the notebook." ] }, { @@ -117,7 +73,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This codespace provides a local database private to you for experimentation. Let's connect to the database server:" + "If the tutorial is run in Codespaces, a private, local database server is created and\n", + "made available for you. This is where we will insert and store our processed results.\n", + "Let's connect to the database server." ] }, { @@ -129,8 +87,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2023-11-27 15:06:43,279][INFO]: Connecting root@fakeservices.datajoint.io:3306\n", - "[2023-11-27 15:06:43,287][INFO]: Connected root@fakeservices.datajoint.io:3306\n" + "[2023-11-28 19:33:47,134][INFO]: Connecting root@fakeservices.datajoint.io:3306\n", + "[2023-11-28 19:33:47,142][INFO]: Connected root@fakeservices.datajoint.io:3306\n" ] }, { @@ -152,16 +110,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Design the DataJoint Pipeline**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This tutorial presumes that the `element-array-ephys` has been pre-configured and instantiated, with the database linked downstream to pre-existing `subject` and `session` tables. \n", + "### **Activate the DataJoint Pipeline**\n", "\n", - "Now, we will proceed to import the essential schemas required to construct this data pipeline, with particular attention to the primary components: `probe` and `ephys`." + "This tutorial activates the `ephys_acute.py` module from `element-array-ephys`, along\n", + "with upstream dependencies from `element-animal` and `element-session`. Please refer to the\n", + "[`tutorial_pipeline.py`](./tutorial_pipeline.py) for the source code." ] }, { @@ -173,7 +126,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2023-11-27 15:06:47,930][WARNING]: lab.Project and related tables will be removed in a future version of Element Lab. Please use the project schema.\n" + "[2023-11-28 19:33:49,428][WARNING]: lab.Project and related tables will be removed in a future version of Element Lab. Please use the project schema.\n" ] } ], @@ -185,7 +138,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We can represent a diagram of some of the upstream and downstream dependencies connected to these `probe` and `ephys` schemas:" + "We can represent the tables in the `probe` and `ephys` schemas as well as some of the\n", + "upstream dependencies to `session` and `subject` schemas as a diagram." ] }, { @@ -196,931 +150,484 @@ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "%3\n", - "\n", - "\n", + "\n", + "\n", "\n", - "ephys.LFP.Electrode\n", - "\n", - "\n", - "ephys.LFP.Electrode\n", + "ephys.LFP\n", + "\n", + "\n", + "ephys.LFP\n", "\n", "\n", "\n", - "\n", - "\n", - "ephys.WaveformSet.PeakWaveform\n", - "\n", - "\n", - "ephys.WaveformSet.PeakWaveform\n", + "\n", + "\n", + "ephys.LFP.Electrode\n", + "\n", + "\n", + "ephys.LFP.Electrode\n", "\n", "\n", "\n", - "\n", - "\n", - "ephys.ClusteringTask\n", - "\n", - "\n", - "ephys.ClusteringTask\n", + "\n", + "\n", + "ephys.LFP->ephys.LFP.Electrode\n", + "\n", + "\n", + "\n", + "\n", + "ephys.EphysRecording.EphysFile\n", + "\n", + "\n", + "ephys.EphysRecording.EphysFile\n", "\n", "\n", "\n", - "\n", - "\n", - "ephys.Clustering\n", - "\n", - "\n", - "ephys.Clustering\n", + "\n", + "\n", + "ephys.QualityMetrics.Cluster\n", + "\n", + "\n", + "ephys.QualityMetrics.Cluster\n", "\n", "\n", "\n", - "\n", - "\n", - "ephys.ClusteringTask->ephys.Clustering\n", - "\n", - "\n", - "\n", + "\n", "\n", - "ephys.QualityMetrics\n", - "\n", - "\n", - "ephys.QualityMetrics\n", + "probe.ProbeType.Electrode\n", + "\n", + "\n", + "probe.ProbeType.Electrode\n", "\n", "\n", "\n", - "\n", - "\n", - "ephys.QualityMetrics.Waveform\n", - "\n", - "\n", - "ephys.QualityMetrics.Waveform\n", + "\n", + "\n", + "probe.ElectrodeConfig.Electrode\n", + "\n", + "\n", + "probe.ElectrodeConfig.Electrode\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "ephys.QualityMetrics->ephys.QualityMetrics.Waveform\n", - "\n", + "probe.ProbeType.Electrode->probe.ElectrodeConfig.Electrode\n", + "\n", "\n", - "\n", - "\n", - "ephys.QualityMetrics.Cluster\n", - "\n", - "\n", - "ephys.QualityMetrics.Cluster\n", + "\n", + "\n", + "ephys.Curation\n", + "\n", + "\n", + "ephys.Curation\n", "\n", "\n", "\n", - "\n", + "\n", + "\n", + "ephys.CuratedClustering\n", + "\n", + "\n", + "ephys.CuratedClustering\n", + "\n", + "\n", + "\n", + "\n", "\n", - "ephys.QualityMetrics->ephys.QualityMetrics.Cluster\n", - "\n", + "ephys.Curation->ephys.CuratedClustering\n", + "\n", "\n", - "\n", - "\n", - "ephys.CuratedClustering.Unit\n", - "\n", - "\n", - "ephys.CuratedClustering.Unit\n", + "\n", + "\n", + "ephys.ProbeInsertion\n", + "\n", + "\n", + "ephys.ProbeInsertion\n", "\n", "\n", "\n", - "\n", + "\n", + "\n", + "ephys.InsertionLocation\n", + "\n", + "\n", + "ephys.InsertionLocation\n", + "\n", + "\n", + "\n", + "\n", "\n", - "ephys.CuratedClustering.Unit->ephys.WaveformSet.PeakWaveform\n", - "\n", + "ephys.ProbeInsertion->ephys.InsertionLocation\n", + "\n", "\n", - "\n", + "\n", + "\n", + "ephys.EphysRecording\n", + "\n", + "\n", + "ephys.EphysRecording\n", + "\n", + "\n", + "\n", + "\n", "\n", - "ephys.CuratedClustering.Unit->ephys.QualityMetrics.Waveform\n", - "\n", + "ephys.ProbeInsertion->ephys.EphysRecording\n", + "\n", "\n", - "\n", - "\n", - "ephys.WaveformSet.Waveform\n", - "\n", - "\n", - "ephys.WaveformSet.Waveform\n", + "\n", + "\n", + "probe.ElectrodeConfig\n", + "\n", + "\n", + "probe.ElectrodeConfig\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "ephys.CuratedClustering.Unit->ephys.WaveformSet.Waveform\n", - "\n", + "probe.ElectrodeConfig->probe.ElectrodeConfig.Electrode\n", + "\n", "\n", - "\n", + "\n", "\n", - "ephys.CuratedClustering.Unit->ephys.QualityMetrics.Cluster\n", - "\n", + "probe.ElectrodeConfig->ephys.EphysRecording\n", + "\n", "\n", - "\n", - "\n", - "session.Session\n", - "\n", - "\n", - "session.Session\n", + "\n", + "\n", + "ephys.WaveformSet.PeakWaveform\n", + "\n", + "\n", + "ephys.WaveformSet.PeakWaveform\n", "\n", "\n", "\n", - "\n", - "\n", - "ephys.ProbeInsertion\n", - "\n", - "\n", - "ephys.ProbeInsertion\n", + "\n", + "\n", + "ephys.CuratedClustering.Unit\n", + "\n", + "\n", + "ephys.CuratedClustering.Unit\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "session.Session->ephys.ProbeInsertion\n", - "\n", - "\n", - "\n", - "\n", - "ephys.LFP\n", - "\n", - "\n", - "ephys.LFP\n", - "\n", - "\n", + "ephys.CuratedClustering.Unit->ephys.QualityMetrics.Cluster\n", + "\n", "\n", - "\n", + "\n", "\n", - "ephys.LFP->ephys.LFP.Electrode\n", - "\n", - "\n", - "\n", - "\n", - "ephys.Curation\n", - "\n", - "\n", - "ephys.Curation\n", - "\n", - "\n", + "ephys.CuratedClustering.Unit->ephys.WaveformSet.PeakWaveform\n", + "\n", "\n", - "\n", - "\n", - "ephys.CuratedClustering\n", - "\n", - "\n", - "ephys.CuratedClustering\n", + "\n", + "\n", + "ephys.WaveformSet.Waveform\n", + "\n", + "\n", + "ephys.WaveformSet.Waveform\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "ephys.Curation->ephys.CuratedClustering\n", - "\n", - "\n", - "\n", - "\n", - "ephys.Clustering->ephys.Curation\n", - "\n", + "ephys.CuratedClustering.Unit->ephys.WaveformSet.Waveform\n", + "\n", "\n", - "\n", - "\n", - "ephys.AcquisitionSoftware\n", - "\n", - "\n", - "ephys.AcquisitionSoftware\n", + "\n", + "\n", + "ephys.QualityMetrics.Waveform\n", + "\n", + "\n", + "ephys.QualityMetrics.Waveform\n", "\n", "\n", "\n", - "\n", - "\n", - "ephys.EphysRecording\n", - "\n", - "\n", - "ephys.EphysRecording\n", + "\n", + "\n", + "ephys.CuratedClustering.Unit->ephys.QualityMetrics.Waveform\n", + "\n", + "\n", + "\n", + "\n", + "ephys.WaveformSet\n", + "\n", + "\n", + "ephys.WaveformSet\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "ephys.AcquisitionSoftware->ephys.EphysRecording\n", - "\n", + "ephys.WaveformSet->ephys.WaveformSet.PeakWaveform\n", + "\n", "\n", - "\n", + "\n", "\n", - "ephys.ProbeInsertion->ephys.EphysRecording\n", - "\n", + "ephys.WaveformSet->ephys.WaveformSet.Waveform\n", + "\n", "\n", - "\n", - "\n", - "ephys.InsertionLocation\n", - "\n", - "\n", - "ephys.InsertionLocation\n", + "\n", + "\n", + "probe.ProbeType\n", + "\n", + "\n", + "probe.ProbeType\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "ephys.ProbeInsertion->ephys.InsertionLocation\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig.Electrode\n", - "\n", - "\n", - "probe.ElectrodeConfig.Electrode\n", - "\n", - "\n", + "probe.ProbeType->probe.ProbeType.Electrode\n", + "\n", "\n", - "\n", + "\n", "\n", - "probe.ElectrodeConfig.Electrode->ephys.LFP.Electrode\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig.Electrode->ephys.CuratedClustering.Unit\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig.Electrode->ephys.WaveformSet.Waveform\n", - "\n", - "\n", - "\n", - "\n", - "ephys.EphysRecording->ephys.ClusteringTask\n", - "\n", - "\n", - "\n", - "\n", - "ephys.EphysRecording->ephys.LFP\n", - "\n", - "\n", - "\n", - "\n", - "ephys.EphysRecording.EphysFile\n", - "\n", - "\n", - "ephys.EphysRecording.EphysFile\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.EphysRecording->ephys.EphysRecording.EphysFile\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusteringMethod\n", - "\n", - "\n", - "ephys.ClusteringMethod\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusteringParamSet\n", - "\n", - "\n", - "ephys.ClusteringParamSet\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusteringMethod->ephys.ClusteringParamSet\n", - "\n", - "\n", - "\n", - "\n", - "ephys.CuratedClustering->ephys.QualityMetrics\n", - "\n", - "\n", - "\n", - "\n", - "ephys.CuratedClustering->ephys.CuratedClustering.Unit\n", - "\n", - "\n", - "\n", - "\n", - "ephys.WaveformSet\n", - "\n", - "\n", - "ephys.WaveformSet\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.CuratedClustering->ephys.WaveformSet\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusteringParamSet->ephys.ClusteringTask\n", - "\n", - "\n", - "\n", - "\n", - "probe.ProbeType.Electrode\n", - "\n", - "\n", - "probe.ProbeType.Electrode\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "probe.ProbeType.Electrode->probe.ElectrodeConfig.Electrode\n", - "\n", - "\n", - "\n", - "\n", - "ephys.WaveformSet->ephys.WaveformSet.PeakWaveform\n", - "\n", - "\n", - "\n", - "\n", - "ephys.WaveformSet->ephys.WaveformSet.Waveform\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject\n", - "\n", - "\n", - "subject.Subject\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject->session.Session\n", - "\n", + "probe.ProbeType->probe.ElectrodeConfig\n", + "\n", "\n", "\n", - "\n", + "\n", "probe.Probe\n", - "\n", - "\n", - "probe.Probe\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "probe.Probe->ephys.ProbeInsertion\n", - "\n", - "\n", - "\n", - "\n", - "probe.ProbeType\n", - "\n", - "\n", - "probe.ProbeType\n", + "\n", + "\n", + "probe.Probe\n", "\n", "\n", "\n", - "\n", - "\n", - "probe.ProbeType->probe.ProbeType.Electrode\n", - "\n", - "\n", "\n", - "\n", + "\n", "probe.ProbeType->probe.Probe\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig\n", - "\n", - "\n", - "probe.ElectrodeConfig\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "probe.ProbeType->probe.ElectrodeConfig\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusterQualityLabel\n", - "\n", - "\n", - "ephys.ClusterQualityLabel\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusterQualityLabel->ephys.CuratedClustering.Unit\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig->probe.ElectrodeConfig.Electrode\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig->ephys.EphysRecording\n", - "\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "(\n", - " dj.Diagram(subject.Subject)\n", - " + dj.Diagram(session.Session)\n", - " + dj.Diagram(probe)\n", - " + dj.Diagram(ephys)\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As evident, this data pipeline is fairly comprehensive, encompassing several tables associated with different Array Electrophysiology components like ephys recording, probe, and clustering. A few tables, such as `Subject` or `Session`, while integral to the pipeline, fall outside the scope of `element-array-ephys` tutorial as they are upstream. \n", - "\n", - "Our focus in this tutorial will be primarily on the two core schemas:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "%3\n", - "\n", - "\n", - "\n", - "ephys.LFP.Electrode\n", - "\n", - "\n", - "ephys.LFP.Electrode\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.WaveformSet.PeakWaveform\n", - "\n", - "\n", - "ephys.WaveformSet.PeakWaveform\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusteringTask\n", - "\n", - "\n", - "ephys.ClusteringTask\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.Clustering\n", - "\n", - "\n", - "ephys.Clustering\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusteringTask->ephys.Clustering\n", - "\n", - "\n", - "\n", - "\n", - "ephys.QualityMetrics\n", - "\n", - "\n", - "ephys.QualityMetrics\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.QualityMetrics.Waveform\n", - "\n", - "\n", - "ephys.QualityMetrics.Waveform\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.QualityMetrics->ephys.QualityMetrics.Waveform\n", - "\n", - "\n", - "\n", - "\n", - "ephys.QualityMetrics.Cluster\n", - "\n", - "\n", - "ephys.QualityMetrics.Cluster\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.QualityMetrics->ephys.QualityMetrics.Cluster\n", - "\n", - "\n", - "\n", - "\n", - "ephys.CuratedClustering.Unit\n", - "\n", - "\n", - "ephys.CuratedClustering.Unit\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.CuratedClustering.Unit->ephys.WaveformSet.PeakWaveform\n", - "\n", - "\n", - "\n", - "\n", - "ephys.CuratedClustering.Unit->ephys.QualityMetrics.Waveform\n", - "\n", - "\n", - "\n", - "\n", - "ephys.WaveformSet.Waveform\n", - "\n", - "\n", - "ephys.WaveformSet.Waveform\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.CuratedClustering.Unit->ephys.WaveformSet.Waveform\n", - "\n", - "\n", - "\n", - "\n", - "ephys.CuratedClustering.Unit->ephys.QualityMetrics.Cluster\n", - "\n", - "\n", - "\n", - "\n", - "ephys.LFP\n", - "\n", - "\n", - "ephys.LFP\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.LFP->ephys.LFP.Electrode\n", - "\n", - "\n", - "\n", - "\n", - "ephys.Curation\n", - "\n", - "\n", - "ephys.Curation\n", - "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "ephys.CuratedClustering\n", - "\n", - "\n", - "ephys.CuratedClustering\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.Curation->ephys.CuratedClustering\n", - "\n", - "\n", - "\n", - "\n", - "ephys.Clustering->ephys.Curation\n", - "\n", + "\n", + "\n", + "probe.Probe->ephys.ProbeInsertion\n", + "\n", "\n", "\n", - "\n", + "\n", "ephys.AcquisitionSoftware\n", - "\n", - "\n", - "ephys.AcquisitionSoftware\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.EphysRecording\n", - "\n", - "\n", - "ephys.EphysRecording\n", + "\n", + "\n", + "ephys.AcquisitionSoftware\n", "\n", "\n", "\n", "\n", - "\n", - "ephys.AcquisitionSoftware->ephys.EphysRecording\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ProbeInsertion\n", - "\n", - "\n", - "ephys.ProbeInsertion\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ProbeInsertion->ephys.EphysRecording\n", - "\n", - "\n", - "\n", - "\n", - "ephys.InsertionLocation\n", - "\n", - "\n", - "ephys.InsertionLocation\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ProbeInsertion->ephys.InsertionLocation\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig.Electrode\n", - "\n", - "\n", - "probe.ElectrodeConfig.Electrode\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig.Electrode->ephys.LFP.Electrode\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig.Electrode->ephys.CuratedClustering.Unit\n", - "\n", - "\n", - "\n", - "\n", - "probe.ElectrodeConfig.Electrode->ephys.WaveformSet.Waveform\n", - "\n", - "\n", - "\n", - "\n", - "ephys.EphysRecording->ephys.ClusteringTask\n", - "\n", - "\n", - "\n", "\n", - "ephys.EphysRecording->ephys.LFP\n", - "\n", + "ephys.AcquisitionSoftware->ephys.EphysRecording\n", + "\n", "\n", - "\n", - "\n", - "ephys.EphysRecording.EphysFile\n", - "\n", - "\n", - "ephys.EphysRecording.EphysFile\n", + "\n", + "\n", + "ephys.QualityMetrics\n", + "\n", + "\n", + "ephys.QualityMetrics\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "ephys.EphysRecording->ephys.EphysRecording.EphysFile\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusteringMethod\n", - "\n", - "\n", - "ephys.ClusteringMethod\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "ephys.ClusteringParamSet\n", - "\n", - "\n", - "ephys.ClusteringParamSet\n", - "\n", - "\n", + "ephys.QualityMetrics->ephys.QualityMetrics.Cluster\n", + "\n", "\n", - "\n", + "\n", "\n", - "ephys.ClusteringMethod->ephys.ClusteringParamSet\n", - "\n", - "\n", - "\n", - "\n", - "ephys.CuratedClustering->ephys.QualityMetrics\n", - "\n", + "ephys.QualityMetrics->ephys.QualityMetrics.Waveform\n", + "\n", "\n", "\n", - "\n", + "\n", "ephys.CuratedClustering->ephys.CuratedClustering.Unit\n", - "\n", - "\n", - "\n", - "\n", - "ephys.WaveformSet\n", - "\n", - "\n", - "ephys.WaveformSet\n", - "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "ephys.CuratedClustering->ephys.WaveformSet\n", - "\n", + "\n", "\n", - "\n", - "\n", - "ephys.ClusteringParamSet->ephys.ClusteringTask\n", - "\n", + "\n", + "\n", + "ephys.CuratedClustering->ephys.QualityMetrics\n", + "\n", "\n", - "\n", - "\n", - "probe.ProbeType.Electrode\n", - "\n", - "\n", - "probe.ProbeType.Electrode\n", + "\n", + "\n", + "subject.Subject\n", + "\n", + "\n", + "subject.Subject\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "session.Session\n", + "\n", + "\n", + "session.Session\n", "\n", "\n", "\n", - "\n", + "\n", + "\n", + "subject.Subject->session.Session\n", + "\n", + "\n", + "\n", "\n", - "probe.ProbeType.Electrode->probe.ElectrodeConfig.Electrode\n", - "\n", + "probe.ElectrodeConfig.Electrode->ephys.CuratedClustering.Unit\n", + "\n", "\n", - "\n", + "\n", "\n", - "ephys.WaveformSet->ephys.WaveformSet.PeakWaveform\n", - "\n", + "probe.ElectrodeConfig.Electrode->ephys.WaveformSet.Waveform\n", + "\n", "\n", - "\n", + "\n", "\n", - "ephys.WaveformSet->ephys.WaveformSet.Waveform\n", - "\n", + "probe.ElectrodeConfig.Electrode->ephys.LFP.Electrode\n", + "\n", "\n", - "\n", - "\n", - "probe.Probe\n", - "\n", - "\n", - "probe.Probe\n", + "\n", + "\n", + "ephys.ClusteringMethod\n", + "\n", + "\n", + "ephys.ClusteringMethod\n", "\n", "\n", "\n", - "\n", - "\n", - "probe.Probe->ephys.ProbeInsertion\n", - "\n", - "\n", - "\n", + "\n", "\n", - "probe.ProbeType\n", - "\n", - "\n", - "probe.ProbeType\n", + "ephys.ClusteringParamSet\n", + "\n", + "\n", + "ephys.ClusteringParamSet\n", "\n", "\n", "\n", - "\n", + "\n", + "\n", + "ephys.ClusteringMethod->ephys.ClusteringParamSet\n", + "\n", + "\n", + "\n", "\n", - "probe.ProbeType->probe.ProbeType.Electrode\n", - "\n", + "ephys.EphysRecording->ephys.LFP\n", + "\n", "\n", - "\n", + "\n", "\n", - "probe.ProbeType->probe.Probe\n", - "\n", + "ephys.EphysRecording->ephys.EphysRecording.EphysFile\n", + "\n", "\n", - "\n", - "\n", - "probe.ElectrodeConfig\n", - "\n", - "\n", - "probe.ElectrodeConfig\n", + "\n", + "\n", + "ephys.ClusteringTask\n", + "\n", + "\n", + "ephys.ClusteringTask\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "probe.ProbeType->probe.ElectrodeConfig\n", - "\n", + "ephys.EphysRecording->ephys.ClusteringTask\n", + "\n", + "\n", + "\n", + "\n", + "session.Session->ephys.ProbeInsertion\n", + "\n", + "\n", + "\n", + "\n", + "ephys.ClusteringParamSet->ephys.ClusteringTask\n", + "\n", "\n", "\n", - "\n", + "\n", "ephys.ClusterQualityLabel\n", - "\n", - "\n", - "ephys.ClusterQualityLabel\n", + "\n", + "\n", + "ephys.ClusterQualityLabel\n", "\n", "\n", "\n", "\n", - "\n", + "\n", "ephys.ClusterQualityLabel->ephys.CuratedClustering.Unit\n", - "\n", + "\n", "\n", - "\n", - "\n", - "probe.ElectrodeConfig->probe.ElectrodeConfig.Electrode\n", - "\n", + "\n", + "\n", + "ephys.Clustering\n", + "\n", + "\n", + "ephys.Clustering\n", + "\n", "\n", - "\n", - "\n", - "probe.ElectrodeConfig->ephys.EphysRecording\n", - "\n", + "\n", + "\n", + "\n", + "ephys.Clustering->ephys.Curation\n", + "\n", + "\n", + "\n", + "\n", + "ephys.ClusteringTask->ephys.Clustering\n", + "\n", "\n", "\n", "" ], "text/plain": [ - "" + "" ] }, - "execution_count": 5, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dj.Diagram(probe) + dj.Diagram(ephys)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This diagram represents an example of the `element-array-ephys` pipeline." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Step 1 - Insert Example Data into Subject and Session tables**" + "(\n", + " dj.Diagram(subject.Subject)\n", + " + dj.Diagram(session.Session)\n", + " + dj.Diagram(probe)\n", + " + dj.Diagram(ephys)\n", + ")" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ + "As evident from the diagram, this data pipeline encompasses tables associated with\n", + "recording and probe metadata, results of clustering, and optional curation of clustering\n", + "results. A few tables, such as `subject.Subject` or `session.Session`,\n", + "while important for a complete pipeline, fall outside the scope of the `element-array-ephys`\n", + "tutorial, and will therefore, not be explored extensively here. The primary focus of\n", + "this tutorial will be on the `probe` and `ephys` schemas.\n", + "\n", + "### **Insert subject, session, and probe metadata**\n", + "\n", "Let's start with the first table in the schema diagram (i.e. `subject.Subject` table).\n", "\n", - "To know what data to insert into the table, we can view its dependencies and attributes using the `.describe()` and `.heading` functions." + "To know what data to insert into the table, we can view its dependencies and attributes using the `.describe()` and `.heading` methods." ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -1210,7 +717,7 @@ " (Total: 0)" ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -1221,7 +728,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -1244,7 +751,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -1259,7 +766,7 @@ "subject_description=\"\" : varchar(1024) # " ] }, - "execution_count": 8, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -1280,7 +787,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -1374,7 +881,7 @@ " (Total: 1)" ] }, - "execution_count": 9, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -1396,7 +903,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -1415,7 +922,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -1426,7 +933,7 @@ "session_datetime : datetime # " ] }, - "execution_count": 11, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -1453,7 +960,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -1462,7 +969,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -1544,7 +1051,7 @@ " (Total: 1)" ] }, - "execution_count": 13, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -1558,19 +1065,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Step 2: Register the Electrophysiology Recording information for each Probe**\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Every experimental session produces a set of data files. The purpose of the `SessionDirectory` table is to locate these files. It references a directory path relative to a root directory, defined in `dj.config[\\\"custom\\\"]`. More information about `dj.config` is provided in the [Documentation](https://datajoint.com/docs/elements/user-guide/)." + "Every experimental session produces a set of data files. The purpose of the `SessionDirectory` table is to locate these files. It references a directory path relative to a root directory, defined in `dj.config[\"custom\"]`. More information about `dj.config` is provided in the [documentation](https://datajoint.com/docs/elements/user-guide/)." ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -1656,7 +1156,7 @@ " (Total: 1)" ] }, - "execution_count": 14, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -1681,7 +1181,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -1767,7 +1267,7 @@ " (Total: 1)" ] }, - "execution_count": 15, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -1790,7 +1290,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -1812,7 +1312,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -1826,7 +1326,7 @@ "probe : varchar(32) # unique identifier for this model of probe (e.g. serial number)" ] }, - "execution_count": 17, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -1837,7 +1337,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -1927,7 +1427,7 @@ " (Total: 1)" ] }, - "execution_count": 18, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -1952,7 +1452,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -2042,7 +1542,7 @@ " (Total: 1)" ] }, - "execution_count": 19, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -2055,12 +1555,15 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In the upcoming cells, populate the `ephys.EphysRecording` table and its part table `ephys.EphysRecording.EphysFile` will extract and store the recording information from a given experimental session.\n" + "### **Populate electrophysiology recording metadata**\n", + "\n", + "In the upcoming cells, the `.populate()` method will automatically extract and store the\n", + "recording metadata for each experimental session in the `ephys.EphysRecording` table and its part table `ephys.EphysRecording.EphysFile`." ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -2159,7 +1662,7 @@ " (Total: 0)" ] }, - "execution_count": 20, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -2170,7 +1673,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -2257,7 +1760,7 @@ " (Total: 0)" ] }, - "execution_count": 21, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -2268,14 +1771,14 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "EphysRecording: 100%|██████████| 1/1 [00:01<00:00, 1.51s/it]\n" + "EphysRecording: 100%|██████████| 1/1 [00:01<00:00, 1.25s/it]\n" ] } ], @@ -2293,7 +1796,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -2399,7 +1902,7 @@ " (Total: 1)" ] }, - "execution_count": 23, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -2410,7 +1913,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -2500,7 +2003,7 @@ " (Total: 1)" ] }, - "execution_count": 24, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -2509,18 +2012,13 @@ "ephys.EphysRecording.EphysFile()" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Step 3: Run the Clustering Task**" - ] - }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ + "### **Run the Clustering Task**\n", + "\n", "We're almost ready to spike sort the data with `kilosort`. An important step before\n", "processing is managing the parameters which will be used in that step. To do so, we will\n", "define the kilosort parameters in a dictionary and insert them into a DataJoint table\n", @@ -2532,7 +2030,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -2547,7 +2045,7 @@ "params : longblob # dictionary of all applicable parameters" ] }, - "execution_count": 25, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -2558,7 +2056,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 25, "metadata": {}, "outputs": [ { @@ -2652,7 +2150,7 @@ " (Total: 1)" ] }, - "execution_count": 26, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -2697,8 +2195,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now that we've inserted kilosort parameters into the `ClusteringParamSet` table,\n", - "we're almost ready to sort our data. DataJoint uses a `ClusteringTask` table to\n", + "DataJoint uses a `ClusteringTask` table to\n", "manage which `EphysRecording` and `ClusteringParamSet` should be used during processing. \n", "\n", "This table is important for defining several important aspects of\n", @@ -2707,7 +2204,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -2723,7 +2220,7 @@ "task_mode=\"load\" : enum('load','trigger') # 'load': load computed analysis results, 'trigger': trigger computation" ] }, - "execution_count": 27, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -2738,23 +2235,17 @@ "metadata": {}, "source": [ "The `ClusteringTask` table contains two important attributes: \n", - "+ `paramset_idx` \n", - "+ `task_mode` \n", - "\n", - "The `paramset_idx` attribute tracks\n", - "your kilosort parameter sets. You can choose the parameter set using which \n", - "you want spike sort ephys data. For example, `paramset_idx=0` may contain\n", - "default parameters for kilosort processing whereas `paramset_idx=1` contains your custom parameters for sorting. This\n", - "attribute tells the `Processing` table which set of parameters you are processing in a given `populate()`.\n", - "\n", - "The `task_mode` attribute can be set to either `load` or `trigger`. When set to `load`,\n", - "running the processing step initiates a search for exisiting kilosort output files. When set to `trigger`, the\n", - "processing step will run kilosort on the raw data. " + "+ `paramset_idx` - Allows the user to choose the parameter set with which you want to\n", + " run spike sorting.\n", + "+ `task_mode` - Can be set to `load` or `trigger`. When set to `load`, running the\n", + " Clustering step initiates a search for existing output files of the spike sorting\n", + " algorithm defined in `ClusteringParamSet`. When set to `trigger`, the processing step\n", + " will run spike sorting on the raw data." ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ @@ -2769,16 +2260,23 @@ ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's call populate on the `Clustering` table which checks for kilosort results since `task_mode=load`." + ] + }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Clustering: 100%|██████████| 1/1 [00:00<00:00, 2.71it/s]\n" + "Clustering: 100%|██████████| 1/1 [00:00<00:00, 3.27it/s]\n" ] } ], @@ -2790,14 +2288,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Step 4: Curate the Clustering Results (Optional)**" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ + "### **Curate the results (Optional)**\n", + "\n", "While spike sorting is completed in the above step, you can optionally curate\n", "the output of image processing using the `Curation` table. For this demo, we\n", "will simply use the results of the spike sorting output from the `Clustering` task." @@ -2805,7 +2297,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -2825,7 +2317,7 @@ "curation_note=\"\" : varchar(2000) # " ] }, - "execution_count": 30, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -2836,7 +2328,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 30, "metadata": {}, "outputs": [], "source": [ @@ -2855,7 +2347,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 31, "metadata": {}, "outputs": [ { @@ -2864,9 +2356,9 @@ "text": [ "CuratedClustering: 0%| | 0/1 [00:00=0.1.8", - "element-event>=0.2.3", - "element-interface>=0.4.0", - "element-lab>=0.3.0", - "element-session>=0.1.5", + "element-animal @ git+https://github.com/datajoint/element-animal.git", + "element-event @ git+https://github.com/datajoint/element-event.git", + "element-interface @ git+https://github.com/datajoint/element-interface.git", + "element-lab @ git+https://github.com/datajoint/element-lab.git", + "element-session @ git+https://github.com/datajoint/element-session.git", ], "nwb": ["dandi", "neuroconv[ecephys]", "pynwb"], "tests": ["pre-commit", "pytest", "pytest-cov"],