From 3fb761ad45054c5c183861603ef800315b2f4379 Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Fri, 20 Oct 2023 15:00:38 +0200 Subject: [PATCH] Explain spherical soma and connectedness. (#2214) Extend docs to cover two topics I recently interact with. These seemed confusing to me, so I expect more people will feel this way. - Spherical soma in SWC and its consequence for attaching dendrites. - Connectedness of components. Closes #2161 --- doc/concepts/labels.rst | 14 +++++++------- doc/concepts/morphology.rst | 37 ++++++++++++++++++++++++++++++++++++- doc/fileformat/swc.rst | 28 ++++++++++++++++++++-------- doc/scripts/gen-labels.py | 2 ++ doc/scripts/inputs.py | 2 ++ doc/scripts/make_images.py | 9 +++++++++ 6 files changed, 76 insertions(+), 16 deletions(-) diff --git a/doc/concepts/labels.rst b/doc/concepts/labels.rst index 5b7a0e2a16..b50f041093 100644 --- a/doc/concepts/labels.rst +++ b/doc/concepts/labels.rst @@ -201,6 +201,13 @@ dendritic tree where the radius first is less than or equal to 0.2 μm. thing could be achieved using hoc in NEURON, and whether it would be free of bugs and applicable to arbitrary morphologies. +.. figure:: ../gen-images/label_branch.svg + :width: 800 + :align: center + + The input morphology with branch numbers for reference in the examples below. + + .. _labels-locset-expr: Locset expressions @@ -210,13 +217,6 @@ Locset expressions The empty locset. -.. figure:: ../gen-images/label_branch.svg - :width: 800 - :align: center - - The input morphology with branch numbers for reference in the examples below. - - .. label:: (root) The location of the root. diff --git a/doc/concepts/morphology.rst b/doc/concepts/morphology.rst index b2f1035747..32226ed2e1 100644 --- a/doc/concepts/morphology.rst +++ b/doc/concepts/morphology.rst @@ -393,8 +393,43 @@ multiple soma and dendrite segments in branch 0. are no longer of much use for the user and it is better to think of the cell structure as Arbor does: in terms of branches. +Connectivity of Components +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When building regions, Arbor considers two points in a region of the morphology +as *connected* if they are + +1. located on the same branch, +2. located on adjacent branches, where one is distal to the other, +3. or separated by fully connected branches. + +Two components are connected -- and thus one component -- if there are points in +both that are connected. In short, a component is defined as the maximal set of +connected points. + +.. figure:: ../gen-images/label_branch.svg + :width: 800 + :align: center + +This means a simple fork -- as that between branches 2, 3, and 4 in the image +above gives rise to the following scenarios + +- ``(join (segment 2) (segment 3))`` is connected as 3 is distal to 2. +- ``(join (segment 2) (segment 4))`` is connected as 4 is distal to 2. +- ``(join (segment 3) (segment 4))`` is **not** connected as 3 and 4 are at equivalent depth. + +One can observe the difference when using the ``on-components`` expression, see below. + +.. figure:: ../gen-images/connected_components.svg + :width: 800 + :align: center + + **Left**: ``(on-components 0.5 (join (branch 2) (branch 3)))`` + + **Right**: ``(on-components 0.5 (join (branch 3) (branch 4)))`` + Examples -~~~~~~~~~~~~~~~ +~~~~~~~~ Here we present a series of morphology examples of increasing complexity. The examples use the Python API are two-dimensional, with the z-dimension set to zero. diff --git a/doc/fileformat/swc.rst b/doc/fileformat/swc.rst index cf799324da..682791786d 100644 --- a/doc/fileformat/swc.rst +++ b/doc/fileformat/swc.rst @@ -114,16 +114,28 @@ joined at the soma center. It differs in two ways: * The soma is extended along the x-axis, not the y-axis. * The soma is constructed from three points, the first at ``x=x0-r``, the second with - ``x=x0`` and the third at ``x=x0+r``, to form a single section, with all dendrites, axons - and apical dendrites attached to the center of the soma with "zero resistance wires". + ``x=x0`` and the third at ``x=x0+r``, to form a single section. +* All dendrites, axons, and apical dendrites are attached to the center of the soma with "zero resistance wires". -**The axon, dendrite and apical sub-trees follow special rules for attachment to the soma**: -By default, the sub-tree starts at the first sample with the dendrite, axon or apical tag, and not -at the parent location on the soma, and the sub-tree is connected to its parent with a "zero resistance wire". -**Except** when the sub tree is defined by a single child sample. In which case the sub-tree is -composed of a single a segment from the parent location on the soma to the child sample, -with constant radius of the child. +**The axon, dendrite and apical sub-trees follow special rules for attachment to +the soma**: By default, the sub-tree starts at the first sample with the +dendrite, axon or apical tag, and not at the parent location on the soma, and +the sub-tree is connected to its parent with a "zero resistance wire". +**Except** when the sub tree is defined by a single child sample. In which case +the sub-tree is composed of a single a segment from the parent location on the +soma to the child sample, with constant radius of the child. +Note that these special properties can lead to unintuitive behviour in some cases. Example + +.. code-block:: + + # id, tag, x, y, z, radius, parent + 1 1 0 0 0 6 -1 + 2 3 2 0 0 3 1 + +As we have one sample tagged ``1`` (soma), the soma is build by two cylinders +approximating a sphere. The dendrite is attached to the center, thus the +morphology has *three* branches arranged in a 'T'-shape. API """ diff --git a/doc/scripts/gen-labels.py b/doc/scripts/gen-labels.py index 1cd706745a..9ccf3e032a 100644 --- a/doc/scripts/gen-labels.py +++ b/doc/scripts/gen-labels.py @@ -224,6 +224,8 @@ def write_morphology(name, morph): "proximal_translate": "(proximal-translate (terminal) 10)", "distal_translate_single": "(distal-translate (location 0 0.5) 5)", "distal_translate_multi": "(distal-translate (location 0 0.5) 15)", + "comp_23": "(on-components 0.5 (join (branch 2) (branch 3)))", + "comp_c34": "(on-components 0.5 (join (branch 3) (branch 4)))", } labels = {**regions, **locsets} diff --git a/doc/scripts/inputs.py b/doc/scripts/inputs.py index f4f19c4b86..5da33d7701 100644 --- a/doc/scripts/inputs.py +++ b/doc/scripts/inputs.py @@ -136,6 +136,8 @@ ls_proximal_translate = {'type': 'locset', 'value': [(1, 0.35497750169352515), (2, 0.5160959062272675), (2, 0.6817468794150789), (5, 0.0)]} ls_distal_translate_single = {'type': 'locset', 'value': [(0, 0.915588599565521)]} ls_distal_translate_multi = {'type': 'locset', 'value': [(1, 0.5795163072671657), (3, 0.24228815992614555), (4, 0.20321157163712014)]} +ls_comp_23 = {'type': 'locset', 'value': [(2, 0.9307207471099461)]} +ls_comp_c34 = {'type': 'locset', 'value': [(3, 0.5), (4, 0.5)]} ############# regions (label_morph) diff --git a/doc/scripts/make_images.py b/doc/scripts/make_images.py index 6d7f4bb8b7..595534e0ee 100644 --- a/doc/scripts/make_images.py +++ b/doc/scripts/make_images.py @@ -458,6 +458,15 @@ def generate(path=""): path + "/distal_translate_label.svg", ) + label_image( + inputs.label_morph, + [ + inputs.ls_comp_23, + inputs.ls_comp_c34, + ], + path + "/connected_components.svg", + ) + ####################### regions label_image(