Background
I work with anatomically relevant data and often do analyses that involve recoding variables manually based on some anatomical structure. Some convenient defaults for referencing these structures by relation and traits while incorporating them into other julia structures would be extremely helpful. The structure of this post is:
- Desired syntax
- Current ideas concerning design
- !Goals (Not goals) and Goals
- Type of feedback most needed
I’ll be sticking with a couple of anatomical terms so that those who are less anatomically inclined can follow.
- Temporal lobe: part of brain
- Mesial temporal lobe: part of the temporal lobe
- Amygdala: part of mesial temporal lobe
- Hippocampus: part of mesial temporal lobe
So as a tree structure it may look like
-Temporal Lobe
|- Mesial temporal lobe
|- Amygdala
|- Hippocampus
I also mention a couple other things but you don’t actually have to understand them to understand what I’m getting at.
Desired Syntax
Relation Trees
I’d like to have the default be similar to what is offered by something like AbstractTrees.jl
parent(Hippocampus)
#> Mesial temporal lobe
children(Hippocampus)
#> DentateGyrus, etc.
But I want to have context for situations where a single anatomical region has multiple “parents”/children depending on what you want to think about. So if I want to iterate through a list of anatomical structures and know what their neural circuitry/network is I can do:
parent(Network, Hippocampus)
#> PapezCircuit
But if I want to know it’s context in the Destrieux atlas (brain atlas used for magnetic resonance imaging segmentation) I can do:
parent(DestrieuxAtlas, Hippocampus)
#> TemporalLobe
For the sake of simplicity I will just mention by reference (and not example) that some structures such as the cingulum are highly interconnected by network and anatomy. In such cases the “parent” would be different based on how you divide up the structure. So although I listed examples that were different parents based on obvious differences in the context of function and atlas, other structures have ambiguity in tree structure even when defined solely on anatomical location. So even if the syntax were different based on the desired context you’d still have ambiguity.
network_parent(Hippocampus)
#> PapezCircuit
destrieux_atlas_parent(Hippocampus)
#> TemporalLobe
anatomical_parent(Cingulum)
#> Frontal lobe or maybe temporal lobe
The essential difference between this and what I’ve seen in phylogenetic/ontological trees is that the nodes/vertices are fairly static but the tree itself is dynamic. So it makes sense to define a set of trees based on phylogentic typing and then dynamically add species to this because there are many. Anatomy doesn’t really change but how we understand it does. In other words I want to have many trees but a fixed set of nodes that I don’t have to recode over again when investigating a new paradigm.
Interacting With Julia Types
My intuition is to just use enumeration for the actual indexing:
@enum Atlas Hippocampus=1 Amygdala=2
which would then give the indice of hippocampus in a vector doing Int(Hippocampus)
.
I’d like to associate values with specific instances of types sometimes too. For example, if I’m using a certain MRI segmentation atlas it often has a set of associated colors for each region of interest.
color(DestrieuxAtlas, Hippocampus) -> RGBA
Other Potential Ideas
It would be really neat to see how far this could be taken (if it’s even feasible).
For example, there are labs that spend all their time categorizing neurons within a region of the brain. So being able to have a flexible tree structure to relate it to would be a really cool way to bridge different research interests. So to a wet lab doing cell typing they could keep have:
celltypes(Hippocampus)
#> BasketCells, etc.
cellpercentage(Hippocampus)
#> Dictionary of cell types and percentage contributing to neuronal composition of hippocampus
Then I could provide an previously defined atlas that would search the tree structure for the values.
cellpercentage(DestrieuxAtlas, TemporalLobe)
#> Average of cell type percentages within children of TemporalLobe as described by the Destrieux atlas
Current Ideas Concerning Design
I’ll probably implement a package with a core design API and then build other packages around it mainly related to neuroanatomy. The following proposes a way to define the raw structures and the default tree related to them. Most of the implementation of traits and syntax would have to be worked around this.
Look Up Table
A look up table could easily be used to store many of the traits and I could probably use columns named by context do derive children/parents. But that would be pretty inefficient memory wise because if I wanted to just study the hippocampus then I’d need to store default traits for all other regions in this table.
- Pros
- Could use sort and find functions implemented elsewhere
- Tables are universal enough that it would be easy for others to adopt
- Cons
- Would be inefficient memory wise (every row would need a trait defined)
- Working on a subset of the tree would require splitting off a copy of the table first (seems like a sloppy implementation).
Nested Dictionaries
A nested dictionary structure could be used as a pseudo-type hierarchy.
struct AnatomicalDict <: AbstractDict
context
children
end
TemporalLobe = AnatomicalDict(:temporal_lobe, (AnatomicalDict(:hippocampus), AnatomicalDict(:amygdala)))
- Pros
- Easy to implement in a core package
- Cons
- Would have to do some to tricky/obnoxious stuff to reference a structure (
anatomicaldict["hippocampus"]
would search the tree structure for hippocampus). - Traits would probably need to be restricted to a dictionary for each node
- Would have to do some to tricky/obnoxious stuff to reference a structure (
Type Hierarchy
I could create the default hierarchy in the type system
abstract type TemporalLobe end
abstract type MesialTemporalLobe <: TemporalLobe end
struct Hippocampus <: MesialTemporalLobe end
struct Amygdala <: MesialTemporalLobe end
- Pros
- Easy to implement type hierarchy with minimal script length
- Could use built introspection to identify relations between types for default tree.
- Can use trait based dispatch.
- Cons
- Treating parents as individuals nodes is more complicated. For example, what if I just want to store an index that is suppose to relate to the temporal lobe? I’d have to define an
AbstractTemporalLobe
for parent heritage and then define an absolute structure forTemporalLobe <: AbstractTemporalLobe
.
- Treating parents as individuals nodes is more complicated. For example, what if I just want to store an index that is suppose to relate to the temporal lobe? I’d have to define an
Parametric Context Type
struct AnatomicalContex{C} end
TemporalLobe = AnatomicalContext{:temporal_lobe}()
Hippocampus = AnatomicalContext{:hippocampus}()
parent(::AnatomicalContext{:hippocampus}) = TemporalLobe
- Pros
- Probably be the most flexible and solves the efficiency problems with a look up table and the type hierarchy.
- Synonyms would be easy to managae (
const InsularCortex = InsularLobe
)
- Cons
- In terms of typing it would be a lot of work upfront. I just typed hippocampus three times.
- Initial type explosion would be hard on compiler. A basic neuroanatomical package would likely need a couple hundred terms. However, until CRISPR is mastered the number of anatomical regions isn’t really changing.
!Goals (Not goals) and Goals
!Goals
- Creating a formal ontology of anatomical structures or comprehensive subdivision of an anatomical region
- A comprehensive list of anatomical structures
Goals
- Create an interface that could be used to interact with or complement:
- A formal ontology
- Brain atlases
- Flexible to additional traits from other packages if desired.
Type of Feedback Most Needed
While you can provide any feedback you feel is helpful I’m specifically concerned with the following:
Syntax
It’s possible I’m limiting myself by the kind of syntax I’ve been thinking about so I’m open to rethinking the syntax provided it doesn’t limit the functionality provided by what I’ve proposed. Additional syntax that would be helpful/interesting would also be welcome.
Design
I don’t have any formal computer science training and it feels like I’m missing some sort of design paradigm that already exists somewhere. On the other hand, I’ve never seen this sort of thing implemented so it might only be possible through Julia’s ability to handle trait like dispatch. So if you have a better idea of how to implement this then by all means share.