-
Notifications
You must be signed in to change notification settings - Fork 52
WIP: Add Histology, MicroCT, and Electrode Localization Pipelines #1294
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?
Changes from 14 commits
45a2f1f
e7093bd
575fadd
9ea5599
13d5dea
95fbe79
dca9f89
35715dc
17fc6e6
35f24bf
bf78853
58efe81
f7ba99c
feab74e
5fc4e06
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| import datajoint as dj | ||
|
|
||
| from spyglass.utils.dj_mixin import SpyglassMixin | ||
| from spyglass.utils.dj_mixin import SpyglassMixin, logger | ||
|
|
||
| schema = dj.schema("common_region") | ||
|
|
||
|
|
@@ -10,9 +10,13 @@ class BrainRegion(SpyglassMixin, dj.Lookup): | |
| definition = """ | ||
| region_id: smallint auto_increment | ||
| --- | ||
| region_name: varchar(200) # the name of the brain region | ||
| subregion_name=NULL: varchar(200) # subregion name | ||
| subsubregion_name=NULL: varchar(200) # subregion within subregion | ||
| region_name: varchar(200) # Name of the region (e.g., 'Hippocampal formation') | ||
| region_abbr=NULL: varchar(64) # Standard abbreviation (e.g., 'HPF') | ||
| subregion_name=NULL: varchar(200) # Subregion name (e.g., 'Cornu Ammonis 1') | ||
| subregion_abbr=NULL: varchar(64) # Subregion abbreviation (e.g., 'CA1') | ||
| subsubregion_name=NULL: varchar(200) # Sub-subregion name (e.g., 'stratum pyramidale') | ||
| subsubregion_abbr=NULL: varchar(64) # Sub-subregion abbreviation (e.g., 'sp') | ||
| atlas_source=NULL: varchar(128) # Source atlas (e.g., 'Allen CCF v3', 'Paxinos Rat 6th Ed') | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I would make this a nullable foreign key reference to an imported table that handles fetching atlases |
||
| """ | ||
|
|
||
| @classmethod | ||
|
|
@@ -48,6 +52,49 @@ def fetch_add( | |
| ) | ||
| query = BrainRegion & key | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider removing this function or only allowing brain regions from a specific atlas. |
||
| if not query: | ||
| logger.info( | ||
| f"Brain region '{region_name}' not found. Adding to BrainRegion. " | ||
| "Please make sure to check the spelling and format." | ||
| "Remove any extra spaces or special characters." | ||
| ) | ||
| cls.insert1(key) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In a meeting we discussed limiting this operation to admin |
||
| query = BrainRegion & key | ||
| return query.fetch1("region_id") | ||
|
|
||
|
|
||
| @schema | ||
| class BrainCoordinateSystem(dj.Lookup): | ||
| definition = """ | ||
| # Defines standard coordinate systems used for brain spatial data. | ||
| coordinate_system_id: varchar(64) # Primary key (e.g., 'Allen_CCFv3_RAS_um') | ||
| --- | ||
| description: varchar(255) # Description of the coordinate system | ||
| atlas_source=NULL: varchar(128) # Source if based on an atlas (e.g., 'Allen CCF v3', 'WHS Rat v4') | ||
| """ | ||
| contents = [ | ||
| [ | ||
| "Allen_CCFv3_RAS_um", | ||
| "Allen CCF v3 Mouse Atlas, RAS orientation, micrometers", | ||
| "Allen CCF v3", | ||
| ], | ||
| [ | ||
| "Paxinos_Rat_6th_PIR_um", | ||
| "Paxinos & Watson Rat Atlas 6th Ed, PIR orientation, micrometers", | ||
| "Paxinos Rat 6th Ed", | ||
| ], | ||
| [ | ||
| "WHS_Rat_v4_RAS_um", | ||
| "Waxholm Space Sprague Dawley Rat Atlas v4, RAS orientation, micrometers", | ||
| "WHS Rat v4", | ||
| ], | ||
| [ | ||
| "Histology_Image_Pixels", | ||
| "2D Pixels from processed histology image (Origin/Orientation Varies)", | ||
| None, | ||
| ], | ||
| [ | ||
| "MicroCT_Voxel_Scan", | ||
| "3D Voxel space from raw microCT scan (Orientation relative to scanner)", | ||
| None, | ||
| ], | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| from spyglass.electrode_localization.localization_merge import ( | ||
| ChannelBrainLocation, | ||
| ChannelBrainLocationHistologyV1, | ||
| ChannelBrainLocationMicroCTV1, | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| """Merge of electrode channel locations from histology and microCT pipelines.""" | ||
|
|
||
| import datajoint as dj | ||
|
|
||
| from spyglass.electrode_localization.v1.histology import ( # noqa: F401 | ||
| ChannelBrainLocationHistologyV1, | ||
| ) | ||
| from spyglass.electrode_localization.v1.micro_ct import ( # noqa: F401 | ||
| ChannelBrainLocationMicroCTV1, | ||
| ) | ||
| from spyglass.utils import SpyglassMixin | ||
| from spyglass.utils.dj_merge_tables import _Merge | ||
|
|
||
| schema = dj.schema("electrode_localization_v1") | ||
|
|
||
|
|
||
| @schema | ||
| class ChannelBrainLocation(_Merge, SpyglassMixin): | ||
| """Merge of electrode channel locations from histology and microCT pipelines. | ||
|
|
||
| The master table lists each (subject, probe, channel), with parts: | ||
| - HistologyV1: ground‐truth coordinates from manual histology alignment. | ||
| - MicroCTV1: coregistered coordinates from the microCT volume. | ||
| """ | ||
|
|
||
| class HistologyV1(SpyglassMixin, dj.Part): | ||
| definition = """ | ||
| -> master | ||
| -> ChannelBrainLocationHistologyV1 | ||
| """ | ||
|
|
||
| class MicroCTV1(SpyglassMixin, dj.Part): | ||
| definition = """ | ||
| -> master | ||
| -> ChannelBrainLocationMicroCTV1 | ||
| """ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| """Histology-derived coordinates and region assignment for an electrode""" | ||
|
|
||
| import datajoint as dj | ||
|
|
||
| from spyglass.common import ( | ||
| BrainCoordinateSystem, | ||
| BrainRegion, | ||
| Electrode, | ||
| ) # noqa: F401 | ||
| from spyglass.histology.v1.histology import ( # noqa: F401 | ||
| HistologyImages, | ||
| HistologyRegistration, | ||
| ) | ||
| from spyglass.utils import SpyglassMixin | ||
|
|
||
| schema = dj.schema("electrode_localization_v1") | ||
|
|
||
|
|
||
| @schema | ||
| class ChannelBrainLocationHistologyV1(SpyglassMixin, dj.Manual): | ||
| definition = """ | ||
| # Histology-derived coordinates and region assignment for an electrode | ||
| -> Electrode # Electrode being localized | ||
| -> HistologyImages # Source NWB file link for histology images | ||
| -> HistologyRegistration # Alignment parameters used | ||
| --- | ||
| -> BrainCoordinateSystem # Defines the space for pos_x,y,z (e.g., Allen CCF RAS um) | ||
| pos_x: float # (um) coordinate in the specified space | ||
| pos_y: float # (um) coordinate in the specified space | ||
| pos_z: float # (um) coordinate in the specified space | ||
| -> BrainRegion # Assigned brain region | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nullable? Is there ever a case where this is not known, or the value retrieved doesn't make sense in this case - either a grey area or individual differences for the animal vs averaged atlas? Is this an imported table? Is |
||
| """ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| """MicroCT-derived coordinates and region assignment for an electrode""" | ||
|
|
||
| import datajoint as dj | ||
|
|
||
| from spyglass.common import ( | ||
| BrainCoordinateSystem, | ||
| BrainRegion, | ||
| Electrode, | ||
| ) # noqa: F401 | ||
| from spyglass.micro_ct.v1.micro_ct import ( # noqa: F401 | ||
| MicroCTImages, | ||
| MicroCTRegistration, | ||
| ) | ||
| from spyglass.utils import SpyglassMixin | ||
|
|
||
| schema = dj.schema("electrode_localization_v1") | ||
|
|
||
|
|
||
| @schema | ||
| class ChannelBrainLocationMicroCTV1(SpyglassMixin, dj.Manual): | ||
| definition = """ | ||
| # MicroCT-derived coordinates and region assignment for an electrode | ||
| -> Electrode # Electrode being localized | ||
| -> MicroCTImages # Source NWB file link for microCT data | ||
| -> MicroCTRegistration # Alignment parameters used | ||
| --- | ||
| -> BrainCoordinateSystem # Defines the space for pos_x,y,z | ||
| pos_x: float # (um) coordinate in the specified space | ||
| pos_y: float # (um) coordinate in the specified space | ||
| pos_z: float # (um) coordinate in the specified space | ||
| -> BrainRegion # Assigned brain region | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same questions as histology table above |
||
| """ | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,141 @@ | ||||||||
| import datajoint as dj | ||||||||
|
|
||||||||
| from spyglass.common import ( # noqa: F401 | ||||||||
| AnalysisNwbfile, | ||||||||
| BrainCoordinateSystem, | ||||||||
| LabMember, | ||||||||
| Subject, | ||||||||
| ) | ||||||||
| from spyglass.utils import SpyglassMixin, logger | ||||||||
|
|
||||||||
| schema = dj.schema("histology_v1") | ||||||||
|
|
||||||||
|
|
||||||||
| @schema | ||||||||
| class Histology(SpyglassMixin, dj.Manual): | ||||||||
| definition = """ | ||||||||
| # Represents a single histology preparation for a subject | ||||||||
|
Comment on lines
+16
to
+17
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| -> Subject | ||||||||
| histology_id: varchar(32) # User-defined ID (e.g., 'probe_track_run1') | ||||||||
| --- | ||||||||
| prep_date=NULL: date # Optional: Date of tissue preparation | ||||||||
| slice_orientation: enum( # Orientation of sections | ||||||||
| "coronal", | ||||||||
| "sagittal", | ||||||||
| "horizontal", | ||||||||
| "other" | ||||||||
| ) | ||||||||
| slice_thickness: float # (um) Thickness of sections | ||||||||
| mounting_medium=NULL: varchar(128) # e.g., 'DPX', 'Fluoromount-G' | ||||||||
| experiment_purpose: varchar(1024) # e.g., 'Probe track recovery', 'Anatomical ref' | ||||||||
| notes="": varchar(2048) # Optional general notes about the preparation | ||||||||
| -> [nullable] LabMember.proj(histology_experimenter='user_name') # Optional: who did the prep? | ||||||||
| # --- Data Source --- | ||||||||
| output_format='TIFF stack': varchar(64) # Format of raw image data from scanner | ||||||||
| raw_scan_path: varchar(512) # Path to the raw output (e.g., folder containing TIFF stack) | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are user's intended to access the images from this path or the AnalysisNwbfile? If the latter, we might not need to store it in the table, but rather pass it to an insertion method |
||||||||
| """ | ||||||||
|
|
||||||||
| class HistologyStain(SpyglassMixin, dj.Part): | ||||||||
| definition = """ | ||||||||
| # Details of specific stains used in a histology preparation | ||||||||
| -> Histology | ||||||||
| stain_index: tinyint unsigned # Use index for multiple stains (0, 1, 2...) | ||||||||
| --- | ||||||||
| identified_feature: varchar(128) # Biological target/marker (e.g., 'Nissl Bodies', 'ChR2-tdTomato+', 'ProbeTrack_DiI') | ||||||||
| visualization_agent: varchar(128)# Method/molecule making feature visible (e.g., 'Cresyl Violet', 'Native tdTomato', 'DiI', 'Alexa 488') | ||||||||
| stain_type: enum( # Type of staining method used | ||||||||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this list exhaustive? Would we want to make this a varchar for flexibility?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you're not sure, then yes, I'd convert |
||||||||
| "immunohistochemistry", | ||||||||
| "genetic_marker", | ||||||||
| "tracer", | ||||||||
| "anatomical", | ||||||||
| "histochemical", | ||||||||
| "in_situ_hybridization", | ||||||||
| "other" | ||||||||
| ) = "anatomical" | ||||||||
| stain_protocol_name=NULL: varchar(128) # Optional: name of the protocol used | ||||||||
| antibody_details=NULL: varchar(255) # Optional: specific antibody info (e.g. company, cat#, lot#) | ||||||||
| stain_notes="": varchar(1024) # Optional notes about this specific stain (e.g., concentration) | ||||||||
| """ | ||||||||
|
|
||||||||
|
|
||||||||
| @schema | ||||||||
| class HistologyImages(SpyglassMixin, dj.Computed): | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there are multiple
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @CBroz1 do you have an opinion on this?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes? It would be helpful for me to talk through a use case, but yes, moving to a part table seems right What happens to these images downstream? Is some analysis just going to look at the brain region or electrode coordinates and ignore image-specific info? If so, if no downstream table cares about specific images, then we might be better off just including image-specific info in blobs/nwbs that we're unlikely to fetch - for the sake of streamlining primary keys and cutting down on the table count The current approach seems low table count but high information. I could either see us increasing the table count to better accommodate the same info, or reducing the info for the v1 version of this pipeline and conceding that the info can be dumped in less-accessible places for the sake of pipeline streamlining
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently these images aren't used for electrode localization, but they could be in the future. I guess it depends on how much we want to worry about this in v1. |
||||||||
| definition = """ | ||||||||
| # Links Histology info to the Analysis NWB file containing the image data | ||||||||
| -> Histology | ||||||||
| images_id: varchar(32) # User-defined ID for these images (e.g., histology_id) | ||||||||
| --- | ||||||||
| -> AnalysisNwbfile # Link to the NWB file storing image data | ||||||||
| processing_time=CURRENT_TIMESTAMP: timestamp # Timestamp of NWB file creation | ||||||||
| # --- Image Acquisition/Processing Details --- | ||||||||
| color_to_stain=NULL: blob # Mapping channel colors to stain features (e.g., {'DAPI': 'blue', 'GFAP': 'green'}) | ||||||||
| pixel_size_x: float # (um) Pixel size in X dimension after processing/scaling | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible that the post-processing pixel size will differ across images in a stack? |
||||||||
| pixel_size_y: float # (um) Pixel size in Y dimension after processing/scaling | ||||||||
| pixel_size_z: float # (um) Pixel size in Z dimension (often slice_thickness or scan step) | ||||||||
| objective_magnification: float # Magnification of the objective lens (e.g., 20 for 20x) | ||||||||
| image_modality: enum( # Modality of the microscopy | ||||||||
| "fluorescence", | ||||||||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this list exhaustive? Would we want to make this a varchar for flexibility?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above: if unsure, then convert |
||||||||
| "brightfield", | ||||||||
| "other" | ||||||||
| ) | ||||||||
| processing_notes="": varchar(1024) # Notes on image processing applied before/during NWB creation | ||||||||
| """ | ||||||||
|
|
||||||||
| # Ensure this key is unique for HistologyImages entries | ||||||||
| # key_source = Histology | ||||||||
|
||||||||
| # key_source = Histology | |
| key_source = Histology |
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.
key_source will change the make. To make unique in the table, we can add to the table definition:
unique index (subject_id, histology_id)
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.
How should the analysisNWB file be made? We usually have this correspond to subject + date but this would be per subject.
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.
I'd consider either ...
- making these part tables with only
-> masteras the primary key. At the cost of violating the one-to-many assumption of master-parts, you get fewer fields and the ability to shorten names (HistologyRegistration.registration_X->HistologyRegistration.Params.X) - making the params a lookup table
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.
Is having a abbreviation helpful? We already only use the region name.