-
Notifications
You must be signed in to change notification settings - Fork 52
Add AGENTS.md for LLM guidance on Spyglass standards and conventions #1407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Co-authored-by: edeno <[email protected]>
edeno
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Integrate the following information using prompting best practices:
Table-Joining Protocol
When connecting two tables:
- Use
.describe()or.headingto view primary keys (PK) and foreign keys (FK). - Look for direct FK. If none, check for linkers via
.parents()/.children(). - Chain joins, confirming keys at each step.
- Smoke-test:
.fetch(limit=1, as_dict=True). - If stuck, check for overlapping PK/FKs among all tables; explain attempts; suggest checking docs.
Knowledge Base
CORE API - use these commands to access data in Spyglass
| Command / Method | Origin | 1-line purpose | Tutorial-style example* |
|---|---|---|---|
& (restriction) |
DataJoint | Filter rows by key-dict or SQL. | (Session & {'nwb_file_name': 'j1620210710_.nwb'}).fetch1() |
.proj() |
DataJoint | Rename / drop attrs before join. | (Session * Subject).proj(session_date='session_start_time').fetch(limit=3) |
.fetch() / .fetch1() |
DataJoint | Materialise query (arrays / dicts / DataFrames). | (IntervalList & key).fetch('valid_times', limit=2) |
.describe() |
DataJoint | Show schema, PKs, docstring. | PositionOutput.describe() |
.aggr() |
DataJoint | On-the-fly aggregation. | Spikes.aggr(IntervalList, n='count(*)').fetch(limit=1) |
dj.U() |
DataJoint | Union of two (or more) relations. | task_or_sleep = dj.U((IntervalList & 'interval_list_name="task"'), (IntervalList & 'interval_list_name="sleep"')) |
dj.AndList() |
DataJoint | OR-restrict using list of dicts. | files = Session & dj.AndList([{'nwb_file_name': 'fileA.nwb'}, {'nwb_file_name': 'fileB.nwb'}]) |
.heading |
DataJoint | Python attr: dict of all columns. | Session.heading |
<< (up-stream) |
Spyglass | Restrict by ancestor attribute (shorthand for restrict_by(direction="up")). |
PositionOutput() << "nwb_file_name = 'j1620210710_.nwb'" |
>> (down-stream) |
Spyglass | Restrict by descendant attribute (shorthand for restrict_by(direction="down")). |
Session() >> 'trodes_pos_params_name="default"' |
.restrict_by() |
Spyglass | Explicit long-distance restrict; choose "up"/"down". |
PositionOutput().restrict_by("nwb_file_name = 'j1620210710_.nwb'", direction="up") |
.merge_restrict() |
Spyglass | Union of master + parts. | PositionOutput.merge_restrict() |
.merge_fetch() |
Spyglass | Fast cross-part fetch. | PositionOutput.merge_fetch({'nwb_file_name': 'j1620210710_.nwb'}) |
.fetch_nwb() |
Spyglass | Load raw/analysis NWB as h5py.File. |
(LFPOutput & part_key).fetch_nwb() |
.fetch1_dataframe() |
Spyglass | First matching row → tidy pandas.DataFrame. |
(PositionOutput & part_key).fetch1_dataframe() |
.fetch_pose_dataframe() |
Spyglass | Pose key-points DF. | (PositionOutput & part_key).fetch_pose_dataframe(bodypart='nose') |
fetch_results |
Spyglass | Return decoder results dict/array. | results = (DecodingOutput & part_key).fetch_results() |
get_restricted_merge_ids |
Spyglass | Map friendly keys → merge_ids (spikes). | ids = SpikeSortingOutput.get_restricted_merge_ids(key) |
Spyglass — Common-schema “must-know” tables & key fields
| Schema.Table | Primary key(s) | Why a beginner needs it |
|---|---|---|
| common_nwbfile.Nwbfile | nwb_file_name |
Registry of every raw NWB file — all pipelines anchor here. |
| common_nwbfile.AnalysisNwbfile | analysis_file_abs_path |
Tracks derived NWB files (filtered LFP, decoding, …). |
| common_session.Session | nwb_file_name |
One row per recording; first thing you restrict on. |
| └─ Session.Experimenter | nwb_file_name, lab_member_name |
Maps each session to its LabMember experimenters |
| └─ Session.DataAcquisitionDevice | nwb_file_name, data_acquisition_device_name |
Lists headstages / DAQs used in that session |
| common_interval.IntervalList | nwb_file_name, interval_list_name |
Time-windows (task, sleep, artefact) that gate every analysis. |
| common_subject.Subject | subject_id |
Animal metadata; auto-added from NWB. |
| common_lab.LabMember | lab_member_name |
People registry; used in Session.Experimenter and permissions |
| common_lab.LabTeam (+ LabTeamMember) | team_name |
Group members so collaborators can curate/delete their own data. |
| common_lab.Institution | institution_name |
Lookup referenced in Session.institution_name. |
| common_lab.Lab | lab_name |
Lookup referenced in Session.lab_name. |
| common_device.DataAcquisitionDevice | data_acquisition_device_name |
Amplifier / digitiser catalogue. |
| common_device.CameraDevice | camera_name |
Camera hardware; referenced by TaskEpoch. |
| common_device.ProbeType | probe_type |
Defines shank count, site spacing, manufacturer. |
| common_device.Probe | probe_id |
Physical probe instances linked to sessions. |
| common_region.BrainRegion | region_id |
Standardised anatomical labels |
| common_ephys.ElectrodeGroup | nwb_file_name, electrode_group_name |
Groups channels on a probe |
| common_ephys.Electrode | nwb_file_name, electrode_id |
Channel-level metadata (coords, region) |
| common_ephys.Raw | nwb_file_name, interval_list_name, raw_object_id |
Entry point for raw ElectricalSeries upstream of LFP & spikes |
| common_filter.FirFilterParameters | filter_name, filter_sampling_rate |
Library of standard FIR kernels (θ, γ, ripple) |
| common_position.IntervalPositionInfo | nwb_file_name, interval_list_name |
Links raw pose series to analysis epochs. |
| common_sensors.SensorData | nwb_file_name, sensor_data_object_id |
Generic analog/IMU channels. |
| common_dio.DIOEvents | dio_event_name |
TTL pulses & sync lines for behavior timestamping. |
| common_task.Task | task_name |
Lookup of behavioral task definitions. |
| common_task.TaskEpoch | nwb_file_name, epoch |
Maps each epoch to a Task, CameraDevice, and IntervalList |
| Table (module path) | Primary key(s) you always need | Description |
|---|---|---|
| position.PositionOutput (merge master) | merge_id |
Final XY/θ trajectories; part tables TrodesPosV1, DLCPosV1. |
| lfp.LFPOutput (merge master) | merge_id |
Band-limited LFP; main part LFPV1. |
| spikesorting.spikesorting_merge.SpikeSortingOutput (merge master) | merge_id |
Curated spike times; part CurationV1. |
| spikesorting.analysis.v1.group.SortedSpikesGroup | nwb_file_name, sorted_spikes_group_name, unit_filter_params_name |
Bundles curated units for ensemble analyses or decoding. |
| ripple.v1.ripple.RippleTimesV1 | lfp_merge_id,filter_name,filter_sampling_rate,nwb_file_name,target_interval_list_name,lfp_band_sampling_rate,group_name,ripple_param_name,pos_merge_id |
Start/stop of hippocampal sharp-wave ripples (needs LFP ripple-band + speed). |
| mua.v1.mua.MuaEventsV1 | mua_param_name, nwb_file_name,unit_filter_params_name,sorted_spikes_group_name, pos_merge_id, detection_interval |
Multi-unit burst events (+ helper to fetch firing-rate & speed). |
| decoding.decoding_merge.DecodingOutput (merge master) | merge_id |
Decoding posteriors; parts ClusterlessDecodingV1, SortedSpikesDecodingV1. |
| behavior.v1.core.PoseGroup | nwb_file_name, pose_group_name |
Key-point cohorts that drive MoSeq or other pose analyses. |
| sharing.AnalysisNwbfileKachery | kachery_zone_name, analysis_file_name |
Analysis NWB files stored in Kachery; used for fetching NWB data. |
Mini Glossary (symbols tutor should recognize)
- Output table – merge table ending in
Output; single, versioned endpoint for downstream analysis. A ‘master’ table with a DataJoint ‘part’ table connected to the endpoint of each available pipeline e.g.LFPOutput - Group table – table ending in
Groupthat groups rows for another table for easy usage e.g.SortedSpikesGroupgroups a set of spike sorting analyses. - Long-distance restriction –
<<(up-stream),>>(down-stream) operators that filter based on attributes several joins away. fetch_nwb– returns anh5py.File-like NWBFile; auto-detects raw vs analysis files.fetch1_dataframe– returns apandas.DataFramefor the first matching row.
Database Exploration (for tutor use)
For tables outside the knowledge base, you can internally use:
table.children(as_objects=bool): returns a list of all tables (or table names) with a foreign key reference totabletable.parents(as_objects=bool): returns a list of all upstream tables (or table names) on whichtabledepends on through a foreign key referencetable.heading: return the list of keys defining the entries of a table.dj.FreeTable(dj.conn(), full_table_name): returns a table object corresponding to the database tablefull_table_name. Allows access to table operations without requiring access to the python class.
Common Linkers (memorize!)
- Session ↔ ProbeType: via ElectrodeGroup, Probe
- Session ↔ BrainRegion: via ElectrodeGroup, Electrode
- Session ↔ Task: via TaskEpoch
- Session ↔ CameraDevice: via TaskEpoch
- Session ↔ LabMember: via Session.Experimenter (part table)
(“via” = join through these)
Schema pre-fixes
The Spyglass pipeline is organized into schemas, each with a specific focus. Here are the main schemas and their purposes:
common_*– contains common data structures and utilities used across the pipeline, such as raw electrophysiology data.lfp_*– contains tables related to local field potentials (LFP) analysisposition_*– contains tables related to position data analysis, including raw and processed position data.spikesorting_*– contains tables related to spike sorting, including raw spike datadecoding_*– contains tables related to decoding analyses, such as decoding neural activityposition_linearization_*– contains tables related to linearizing position data for analysis along a trackripple_*– contains tables related to ripple analysis, which is often used in conjunction with LFP data.
Merge tables
Analogy: PositionOutput (any *Output) is a Table-of-Contents; each part table is a chapter, and merge_id is the bookmark.
Discover chapters: dir(PositionOutput) → pick one, then PositionOutput.TrodesPosV1.describe() to see required keys.
Build your search: key = {"nwb_file_name": "...", ...}.
Get the bookmark: merge_key = PositionOutput.merge_get_part(key).fetch1("KEY"); fetch data with (PositionOutput & merge_key).fetch1_dataframe().
Never type merge_id by hand—lookup with merge_get_part (or get_restricted_merge_ids) and preview everything with merge_view().
merge_view(): "To quickly peek at the combined data from all pipelines and see what columns are available, usemerge_view()."get_restricted_merge_ids(): "For some tables likeSpikeSortingOutput, there are powerful shortcuts that do the lookup for you.get_restricted_merge_ids(key)can often replace steps 3 and 4."
Quick examples for grabbing data (for tutor use)
from spyglass.common import Session, IntervalList
from spyglass.position import PositionOutput
from spyglass.lfp import LFPOutput
from spyglass.spikesorting.spikesorting_merge import SpikeSortingOutput
from spyglass.spikesorting.analysis.v1.group import SortedSpikesGroup
nwb_file_name = "j1620210710_.nwb"
Session & {"nwb_file_name": nwb_file_name}
(IntervalList & {"nwb_file_name": nwb_file_name, "interval_list_name": "02_r1"}).fetch(
"valid_times"
)
key = {
"nwb_file_name": nwb_file_name,
"interval_list_name": "pos 1 valid times",
"trodes_pos_params_name": "default",
}
merge_key = (PositionOutput.merge_get_part(key)).fetch1("KEY")
# use this to restrict PositionOutput and fetch the data
position_info = (
(PositionOutput & merge_key).fetch1_dataframe().loc[:, ["position_x", "position_y"]]
)
key = {
"nwb_file_name": nwb_file_name,
"lfp_electrode_group_name": "lfp_tets_j16",
"target_interval_list_name": "02_r1 noPrePostTrialTimes",
"filter_name": "LFP 0-400 Hz",
"filter_sampling_rate": 30000,
}
merge_key = (LFPOutput.merge_get_part(key)).fetch1("KEY")
lfp_data = (LFPOutput & merge_key).fetch1_dataframe()
SpikeSortingOutput().get_spike_times(
{"merge_id": "0164f4ef-8f78-c9a7-d50e-72c699bbbffc"}
)[0]
spike_times, unit_ids = SortedSpikesGroup.fetch_spike_data(
{
"nwb_file_name": nwb_file_name,
"unit_filter_params_name": "all_units",
"sorted_spikes_group_name": "HPC_02_r1_clusterless",
},
return_unit_ids=True,
)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces comprehensive documentation specifically designed to guide Large Language Models and AI agents in working with the Spyglass neuroscience data analysis framework. The documentation ensures consistent assistance by providing detailed standards, patterns, and conventions for Spyglass development.
Key Changes:
- Complete AGENTS.md documentation covering DataJoint foundations, table types, and development standards
- Practical code examples for all major table patterns (Parameters, Selection, Computed, NWB Ingestion, Merge)
- LLM-specific best practices and common workflow guidance
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1407 +/- ##
=======================================
Coverage 70.54% 70.54%
=======================================
Files 104 104
Lines 12650 12650
=======================================
Hits 8924 8924
Misses 3726 3726 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Possibly should wait to merge until #1377 is merged |
| - [Contributing Guide](docs/src/ForDevelopers/Contribute.md) | ||
|
|
||
| This document should be referenced when providing assistance with Spyglass | ||
| development to ensure consistency with established patterns and standards. No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Integrate the following information using prompting best practices:
Table-Joining Protocol
When connecting two tables:
- Use
.describe()or.headingto view primary keys (PK) and foreign keys (FK). - Look for direct FK. If none, check for linkers via
.parents()/.children(). - Chain joins, confirming keys at each step.
- Smoke-test:
.fetch(limit=1, as_dict=True). - If stuck, check for overlapping PK/FKs among all tables; explain attempts; suggest checking docs.
Knowledge Base
CORE API - use these commands to access data in Spyglass
| Command / Method | Origin | 1-line purpose | Tutorial-style example* |
|---|---|---|---|
& (restriction) |
DataJoint | Filter rows by key-dict or SQL. | (Session & {'nwb_file_name': 'j1620210710_.nwb'}).fetch1() |
.proj() |
DataJoint | Rename / drop attrs before join. | (Session * Subject).proj(session_date='session_start_time').fetch(limit=3) |
.fetch() / .fetch1() |
DataJoint | Materialise query (arrays / dicts / DataFrames). | (IntervalList & key).fetch('valid_times', limit=2) |
.describe() |
DataJoint | Show schema, PKs, docstring. | PositionOutput.describe() |
.aggr() |
DataJoint | On-the-fly aggregation. | Spikes.aggr(IntervalList, n='count(*)').fetch(limit=1) |
dj.U() |
DataJoint | Union of two (or more) relations. | task_or_sleep = dj.U((IntervalList & 'interval_list_name="task"'), (IntervalList & 'interval_list_name="sleep"')) |
dj.AndList() |
DataJoint | OR-restrict using list of dicts. | files = Session & dj.AndList([{'nwb_file_name': 'fileA.nwb'}, {'nwb_file_name': 'fileB.nwb'}]) |
.heading |
DataJoint | Python attr: dict of all columns. | Session.heading |
<< (up-stream) |
Spyglass | Restrict by ancestor attribute (shorthand for restrict_by(direction="up")). |
PositionOutput() << "nwb_file_name = 'j1620210710_.nwb'" |
>> (down-stream) |
Spyglass | Restrict by descendant attribute (shorthand for restrict_by(direction="down")). |
Session() >> 'trodes_pos_params_name="default"' |
.restrict_by() |
Spyglass | Explicit long-distance restrict; choose "up"/"down". |
PositionOutput().restrict_by("nwb_file_name = 'j1620210710_.nwb'", direction="up") |
.merge_restrict() |
Spyglass | Union of master + parts. | PositionOutput.merge_restrict() |
.merge_fetch() |
Spyglass | Fast cross-part fetch. | PositionOutput.merge_fetch({'nwb_file_name': 'j1620210710_.nwb'}) |
.fetch_nwb() |
Spyglass | Load raw/analysis NWB as h5py.File. |
(LFPOutput & part_key).fetch_nwb() |
.fetch1_dataframe() |
Spyglass | First matching row → tidy pandas.DataFrame. |
(PositionOutput & part_key).fetch1_dataframe() |
.fetch_pose_dataframe() |
Spyglass | Pose key-points DF. | (PositionOutput & part_key).fetch_pose_dataframe(bodypart='nose') |
fetch_results |
Spyglass | Return decoder results dict/array. | results = (DecodingOutput & part_key).fetch_results() |
get_restricted_merge_ids |
Spyglass | Map friendly keys → merge_ids (spikes). | ids = SpikeSortingOutput.get_restricted_merge_ids(key) |
Spyglass — Common-schema “must-know” tables & key fields
| Schema.Table | Primary key(s) | Why a beginner needs it |
|---|---|---|
| common_nwbfile.Nwbfile | nwb_file_name |
Registry of every raw NWB file — all pipelines anchor here. |
| common_nwbfile.AnalysisNwbfile | analysis_file_abs_path |
Tracks derived NWB files (filtered LFP, decoding, …). |
| common_session.Session | nwb_file_name |
One row per recording; first thing you restrict on. |
| └─ Session.Experimenter | nwb_file_name, lab_member_name |
Maps each session to its LabMember experimenters |
| └─ Session.DataAcquisitionDevice | nwb_file_name, data_acquisition_device_name |
Lists headstages / DAQs used in that session |
| common_interval.IntervalList | nwb_file_name, interval_list_name |
Time-windows (task, sleep, artefact) that gate every analysis. |
| common_subject.Subject | subject_id |
Animal metadata; auto-added from NWB. |
| common_lab.LabMember | lab_member_name |
People registry; used in Session.Experimenter and permissions |
| common_lab.LabTeam (+ LabTeamMember) | team_name |
Group members so collaborators can curate/delete their own data. |
| common_lab.Institution | institution_name |
Lookup referenced in Session.institution_name. |
| common_lab.Lab | lab_name |
Lookup referenced in Session.lab_name. |
| common_device.DataAcquisitionDevice | data_acquisition_device_name |
Amplifier / digitiser catalogue. |
| common_device.CameraDevice | camera_name |
Camera hardware; referenced by TaskEpoch. |
| common_device.ProbeType | probe_type |
Defines shank count, site spacing, manufacturer. |
| common_device.Probe | probe_id |
Physical probe instances linked to sessions. |
| common_region.BrainRegion | region_id |
Standardised anatomical labels |
| common_ephys.ElectrodeGroup | nwb_file_name, electrode_group_name |
Groups channels on a probe |
| common_ephys.Electrode | nwb_file_name, electrode_id |
Channel-level metadata (coords, region) |
| common_ephys.Raw | nwb_file_name, interval_list_name, raw_object_id |
Entry point for raw ElectricalSeries upstream of LFP & spikes |
| common_filter.FirFilterParameters | filter_name, filter_sampling_rate |
Library of standard FIR kernels (θ, γ, ripple) |
| common_position.IntervalPositionInfo | nwb_file_name, interval_list_name |
Links raw pose series to analysis epochs. |
| common_sensors.SensorData | nwb_file_name, sensor_data_object_id |
Generic analog/IMU channels. |
| common_dio.DIOEvents | dio_event_name |
TTL pulses & sync lines for behavior timestamping. |
| common_task.Task | task_name |
Lookup of behavioral task definitions. |
| common_task.TaskEpoch | nwb_file_name, epoch |
Maps each epoch to a Task, CameraDevice, and IntervalList |
| Table (module path) | Primary key(s) you always need | Description |
|---|---|---|
| position.PositionOutput (merge master) | merge_id |
Final XY/θ trajectories; part tables TrodesPosV1, DLCPosV1. |
| lfp.LFPOutput (merge master) | merge_id |
Band-limited LFP; main part LFPV1. |
| spikesorting.spikesorting_merge.SpikeSortingOutput (merge master) | merge_id |
Curated spike times; part CurationV1. |
| spikesorting.analysis.v1.group.SortedSpikesGroup | nwb_file_name, sorted_spikes_group_name, unit_filter_params_name |
Bundles curated units for ensemble analyses or decoding. |
| ripple.v1.ripple.RippleTimesV1 | lfp_merge_id,filter_name,filter_sampling_rate,nwb_file_name,target_interval_list_name,lfp_band_sampling_rate,group_name,ripple_param_name,pos_merge_id |
Start/stop of hippocampal sharp-wave ripples (needs LFP ripple-band + speed). |
| mua.v1.mua.MuaEventsV1 | mua_param_name, nwb_file_name,unit_filter_params_name,sorted_spikes_group_name, pos_merge_id, detection_interval |
Multi-unit burst events (+ helper to fetch firing-rate & speed). |
| decoding.decoding_merge.DecodingOutput (merge master) | merge_id |
Decoding posteriors; parts ClusterlessDecodingV1, SortedSpikesDecodingV1. |
| behavior.v1.core.PoseGroup | nwb_file_name, pose_group_name |
Key-point cohorts that drive MoSeq or other pose analyses. |
| sharing.AnalysisNwbfileKachery | kachery_zone_name, analysis_file_name |
Analysis NWB files stored in Kachery; used for fetching NWB data. |
Mini Glossary (symbols tutor should recognize)
- Output table – merge table ending in
Output; single, versioned endpoint for downstream analysis. A ‘master’ table with a DataJoint ‘part’ table connected to the endpoint of each available pipeline e.g.LFPOutput - Group table – table ending in
Groupthat groups rows for another table for easy usage e.g.SortedSpikesGroupgroups a set of spike sorting analyses. - Long-distance restriction –
<<(up-stream),>>(down-stream) operators that filter based on attributes several joins away. fetch_nwb– returns anh5py.File-like NWBFile; auto-detects raw vs analysis files.fetch1_dataframe– returns apandas.DataFramefor the first matching row.
Database Exploration (for tutor use)
For tables outside the knowledge base, you can internally use:
table.children(as_objects=bool): returns a list of all tables (or table names) with a foreign key reference totabletable.parents(as_objects=bool): returns a list of all upstream tables (or table names) on whichtabledepends on through a foreign key referencetable.heading: return the list of keys defining the entries of a table.dj.FreeTable(dj.conn(), full_table_name): returns a table object corresponding to the database tablefull_table_name. Allows access to table operations without requiring access to the python class.
Common Linkers (memorize!)
- Session ↔ ProbeType: via ElectrodeGroup, Probe
- Session ↔ BrainRegion: via ElectrodeGroup, Electrode
- Session ↔ Task: via TaskEpoch
- Session ↔ CameraDevice: via TaskEpoch
- Session ↔ LabMember: via Session.Experimenter (part table)
(“via” = join through these)
Schema pre-fixes
The Spyglass pipeline is organized into schemas, each with a specific focus. Here are the main schemas and their purposes:
common_*– contains common data structures and utilities used across the pipeline, such as raw electrophysiology data.lfp_*– contains tables related to local field potentials (LFP) analysisposition_*– contains tables related to position data analysis, including raw and processed position data.spikesorting_*– contains tables related to spike sorting, including raw spike datadecoding_*– contains tables related to decoding analyses, such as decoding neural activityposition_linearization_*– contains tables related to linearizing position data for analysis along a trackripple_*– contains tables related to ripple analysis, which is often used in conjunction with LFP data.
Merge tables
Analogy: PositionOutput (any *Output) is a Table-of-Contents; each part table is a chapter, and merge_id is the bookmark.
Discover chapters: dir(PositionOutput) → pick one, then PositionOutput.TrodesPosV1.describe() to see required keys.
Build your search: key = {"nwb_file_name": "...", ...}.
Get the bookmark: merge_key = PositionOutput.merge_get_part(key).fetch1("KEY"); fetch data with (PositionOutput & merge_key).fetch1_dataframe().
Never type merge_id by hand—lookup with merge_get_part (or get_restricted_merge_ids) and preview everything with merge_view().
merge_view(): "To quickly peek at the combined data from all pipelines and see what columns are available, usemerge_view()."get_restricted_merge_ids(): "For some tables likeSpikeSortingOutput, there are powerful shortcuts that do the lookup for you.get_restricted_merge_ids(key)can often replace steps 3 and 4."
Quick examples for grabbing data (for tutor use)
from spyglass.common import Session, IntervalList
from spyglass.position import PositionOutput
from spyglass.lfp import LFPOutput
from spyglass.spikesorting.spikesorting_merge import SpikeSortingOutput
from spyglass.spikesorting.analysis.v1.group import SortedSpikesGroup
nwb_file_name = "j1620210710_.nwb"
Session & {"nwb_file_name": nwb_file_name}
(IntervalList & {"nwb_file_name": nwb_file_name, "interval_list_name": "02_r1"}).fetch(
"valid_times"
)
key = {
"nwb_file_name": nwb_file_name,
"interval_list_name": "pos 1 valid times",
"trodes_pos_params_name": "default",
}
merge_key = (PositionOutput.merge_get_part(key)).fetch1("KEY")
# use this to restrict PositionOutput and fetch the data
position_info = (
(PositionOutput & merge_key).fetch1_dataframe().loc[:, ["position_x", "position_y"]]
)
key = {
"nwb_file_name": nwb_file_name,
"lfp_electrode_group_name": "lfp_tets_j16",
"target_interval_list_name": "02_r1 noPrePostTrialTimes",
"filter_name": "LFP 0-400 Hz",
"filter_sampling_rate": 30000,
}
merge_key = (LFPOutput.merge_get_part(key)).fetch1("KEY")
lfp_data = (LFPOutput & merge_key).fetch1_dataframe()
SpikeSortingOutput().get_spike_times(
{"merge_id": "0164f4ef-8f78-c9a7-d50e-72c699bbbffc"}
)[0]
spike_times, unit_ids = SortedSpikesGroup.fetch_spike_data(
{
"nwb_file_name": nwb_file_name,
"unit_filter_params_name": "all_units",
"sorted_spikes_group_name": "HPC_02_r1_clusterless",
},
return_unit_ids=True,
)
This PR adds a comprehensive AGENTS.md file to provide Large Language Models (LLMs) and AI agents with essential guidance for working with the Spyglass neuroscience data analysis framework. The file serves as a definitive reference to ensure consistent and correct assistance when helping developers create new Spyglass tables, pipelines, and analyses.
What's included
The AGENTS.md file provides:
Key benefits
This documentation will help LLMs:
SpyglassMixininheritance pattern:class MyTable(SpyglassMixin, dj.TableType)make()andinsert_default()Example usage guidance
The file includes practical examples like this Parameters table pattern:
The documentation ensures LLMs will provide assistance that maintains consistency with Spyglass standards while helping developers create robust, reproducible neuroscience analysis pipelines.
Fixes #1406.
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.