Skip to content
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

Mixed subtree processing #981

Merged
merged 87 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
b6c3beb
Use soma center in sholl_frequency distance calculation (#989)
eleftherioszisis Feb 25, 2022
d120263
Fix the trunk_origin_radii feature (#986)
adrien-berchet Feb 28, 2022
d896651
Fix `sholl_frequency` for NA neurite_type (#990)
eleftherioszisis Feb 28, 2022
e071ba5
Add py39 and py310 for tests (#984)
eleftherioszisis Mar 3, 2022
0b7b5ea
Make output file in morph_check required (#992)
eleftherioszisis Mar 4, 2022
8c3efc8
Minor housekeeping (#993)
eleftherioszisis Mar 7, 2022
c570a2f
Fix doc of neurom.core.morphology.Neurite.iter_sections method (#994)
adrien-berchet Mar 8, 2022
cfc7012
Add volume density at the morphology level (#996)
eleftherioszisis Mar 10, 2022
127d6fd
Remove duplicate points in principal_direction_extents (#999)
eleftherioszisis Mar 10, 2022
f57feb2
Fix parition_asymmetry Uylings to not throw for bifurcations with lea…
eleftherioszisis Mar 14, 2022
79c62e3
Make deprecation warnings respect pre-existing warnings configuration…
eleftherioszisis Mar 15, 2022
a9e3020
introduce flatten (#1003)
eleftherioszisis Mar 16, 2022
1b64091
Refactor features (#1005)
eleftherioszisis Mar 18, 2022
fdf9f78
Generalize partition asymmetry (#1006)
eleftherioszisis Mar 18, 2022
ba29611
Fix principal direction extent (#1008)
eleftherioszisis Mar 21, 2022
cef7800
Shape related features (#1013)
eleftherioszisis Mar 28, 2022
dc54aa8
Update `neurom.features.get` docstring with available builtin feature…
eleftherioszisis Apr 1, 2022
ed518c4
Sort principal direction extents (#1017)
eleftherioszisis Apr 1, 2022
623cbd9
Return nan if no points in shape features (#1018)
eleftherioszisis Apr 4, 2022
f4cb039
Fix: kwargs are unnecessarily updated in extract_stats (#1020)
adrien-berchet Apr 8, 2022
1ecce98
Allow using lists of kwargs in morph_stats features (#1021)
eleftherioszisis Apr 13, 2022
dd28360
Implement new feature of length above soma (#1023)
eleftherioszisis Apr 14, 2022
c6d187a
Exit early if not points, to avoid hull warning (#1024)
eleftherioszisis Apr 14, 2022
b99aa71
Subtree processing example
eleftherioszisis Feb 14, 2022
7338d45
test original path
mgeplf Feb 16, 2022
ca46861
Make use_subtrees explicit argument.
eleftherioszisis Feb 16, 2022
096485f
Use a regular dict
eleftherioszisis Feb 16, 2022
5a558ab
Make explicit use_subtrees in get
eleftherioszisis Feb 16, 2022
325c235
Make mixed morphology more complex
eleftherioszisis Feb 16, 2022
a6f881e
Add is_heterogeneous to Neurite
eleftherioszisis Feb 20, 2022
6ef838d
Add section_type to radial distance features
eleftherioszisis Feb 20, 2022
aa9d6e9
Check feature signature and propagate use_subtrees
eleftherioszisis Feb 20, 2022
0e8dc1c
Add tests
eleftherioszisis Feb 20, 2022
49cbf8a
Add origin to morphology max_radial_distance & cleanup
eleftherioszisis Feb 20, 2022
73312ad
Add morphology total_length_per_neurite
eleftherioszisis Feb 20, 2022
8d1d172
Add total_area_per_neurite morphology feature
eleftherioszisis Feb 20, 2022
ebcdf02
Add soma features to tests
eleftherioszisis Feb 20, 2022
a15a511
Convert total_volume_per_neurite feature
eleftherioszisis Feb 21, 2022
188bc91
Trunk origin azimuths, elevations & angles are not valid for distal s…
eleftherioszisis Feb 21, 2022
f3d589a
Add section_filter in iter_sections
eleftherioszisis Feb 24, 2022
31d9332
Convert more features
eleftherioszisis Feb 24, 2022
ff21783
Add section filter in iter_segments
eleftherioszisis Feb 24, 2022
926ddf1
More features
eleftherioszisis Feb 24, 2022
11fa604
Add neurite volume density
eleftherioszisis Feb 24, 2022
aaaf4d1
Use kwargs only in tests
eleftherioszisis Feb 24, 2022
40fe4ed
Simplify subneurite iterators
eleftherioszisis Feb 25, 2022
6b0f7f8
Remove print
eleftherioszisis Feb 25, 2022
8b8f9a9
Convert some of the neurite features
eleftherioszisis Feb 26, 2022
f1f3478
Handle forking points with mixed subtrees
eleftherioszisis Feb 26, 2022
5f1e142
Convert more neurite features
eleftherioszisis Feb 27, 2022
640fd70
Handle section path lengths
eleftherioszisis Mar 3, 2022
3261c0f
Remove check
eleftherioszisis Mar 3, 2022
7d66075
Add test for section_path_length
eleftherioszisis Mar 3, 2022
8112a7a
Simplify volume density
eleftherioszisis Mar 3, 2022
d80e42f
Adapt principal_direction_extents
eleftherioszisis Mar 4, 2022
f8666be
Converted to more complex morph and converted branch-order partition_…
eleftherioszisis Mar 9, 2022
c3b3ca6
Add more complex test morph, update features
eleftherioszisis Mar 10, 2022
ca90515
Convert all variants of partition asymmetry
eleftherioszisis Mar 13, 2022
3171c30
Convert segment_path_lengths
eleftherioszisis Mar 14, 2022
f1a0679
Uncomment test
eleftherioszisis Mar 14, 2022
ef87613
Convert population sholl_frequency
eleftherioszisis Mar 14, 2022
7a53411
Increase coverage
eleftherioszisis Mar 14, 2022
dc41ad9
Use iter_segments in segment features
eleftherioszisis Mar 15, 2022
916bf0e
Use section_length from section.py
eleftherioszisis Mar 15, 2022
067152e
Fix lint
eleftherioszisis Mar 16, 2022
26eccb7
Fixes from rebase
eleftherioszisis Mar 18, 2022
81fb647
Convert shape related features
eleftherioszisis Apr 3, 2022
68328f5
Fix _homogeneous_subtrees docstring
eleftherioszisis Apr 5, 2022
3dbc9aa
Add section_filter to docstring
eleftherioszisis Apr 5, 2022
607d572
Fix year and pylint spacing
eleftherioszisis Apr 5, 2022
dff7540
Move extract_subneurites where it is used
eleftherioszisis Apr 6, 2022
f3df2c3
Factor out signature checking using inspect
eleftherioszisis Apr 6, 2022
5bf8076
Use **kwargs in _get_neurite_feature_value
eleftherioszisis Apr 6, 2022
8732868
Add morphology heterogeneous tests
eleftherioszisis Apr 13, 2022
2357027
Cleanup neurite features
eleftherioszisis Apr 14, 2022
8bba54f
Add new feature, refactor, and more tests
eleftherioszisis Apr 16, 2022
a3791b2
Refactor morphology.py
eleftherioszisis Apr 18, 2022
44938b5
Add documentation
eleftherioszisis Apr 19, 2022
c3b1ddc
Generalize iupstream to also stop at node
eleftherioszisis Apr 19, 2022
cbe287a
some doc reflow
mgeplf Apr 21, 2022
94a6a8c
Simplify iupstream
eleftherioszisis Apr 21, 2022
1848f1d
Add brief description for total_volume for default mode
eleftherioszisis Apr 21, 2022
baded71
Make neurites iterable readable
eleftherioszisis Apr 21, 2022
15aecdb
Drop extra line
eleftherioszisis Apr 21, 2022
cd21427
Use full path of section features
eleftherioszisis Apr 21, 2022
cd70e90
Add warning for non AcD neurites
eleftherioszisis Apr 22, 2022
d427225
Do not use a set for subtrees to allow finding many of same type.
eleftherioszisis Apr 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/publish-sdist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Set up Python 3.6
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.6
python-version: 3.9
- name: Build a source tarball
run:
python setup.py sdist
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run-tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8]
python-version: ['3.7', '3.8', '3.9', '3.10']

steps:
- uses: actions/checkout@v2
Expand Down
25 changes: 25 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,35 @@ Changelog

Version 3.2.0
-------------

- Add ``neurom.features.morphology.length_fraction_above_soma`` feature.
- List of multiple kwargs configurations are now allowed in``neurom.apps.morph_stats``.
- ``neurom.features.neurite.principal_direction_extents`` directions correspond to extents
ordered in a descending order.
- Add features ``neurom.features.morphology.(aspect_ration, circularity, shape_factor)```
- Fix ``neurom.morphmath.principal_direction_extent`` to calculate correctly the pca extent.
- Fix ``neurom.features.neurite.segment_taper_rates`` to return signed taper rates.
- Fix warning system so that it doesn't change the pre-existing warnings configuration
- Fix ``neurom.features.bifurcation.partition_asymmetry`` Uylings variant to not throw
for bifurcations with leaves.
- Fix ``neurom.features.neurite.principal_direction_extents`` to remove duplicate points
when calculated.
- Add ``neurom.features.morphology.volume_density`` feature so that it is calculated
correctly when the entire morphology is taken into account instead of summing the per
neurite volume densities.
- Add support for py39 and py310 testing.
- Fix ``neurom.features.morphology.sholl_frequency`` to return an empty list when a
neurite_type that is not present in the morphology is specified.
- Fix ``neurom.features.morphology.trunk_origin_radii`` to warn and use only the root
section for the calculation of the path distances. Edge cases from the combination
of ``min_length_filter`` and ``max_length_filter`` are addressed.
- Fix ``neurom.features.morphology.sholl_frequency`` to use soma center in distance
calculation, instead of using the origin.
- Add ``neurom.features.morphology.trunk_angles_inter_types`` and
``neurom.features.morphology.trunk_angles_from_vector`` features, make
``neurom.features.morphology.trunk_angles`` more generic and add length filter to
``neurom.features.morphology.trunk_origin_radii``.
- Deprecate python3.6
- Add doc on spherical coordinates.

Version 3.1.0
Expand Down
226 changes: 226 additions & 0 deletions doc/source/heterogeneous.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
.. Copyright (c) 2022, Ecole Polytechnique Federale de Lausanne, Blue Brain Project
All rights reserved.

This file is part of NeuroM <https://github.com/BlueBrain/NeuroM>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of
its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

.. _heterogeneous:

Heterogeneous Morphologies
**************************

.. image:: images/heterogeneous_neuron.png

Definition
----------

A heterogeneous morphology consists of zero or more homogeneous and at least one heterogeneous neurite trees extending from the soma.
A heterogeneous neurite tree consists of multiple sub-neurites with different types (ie: basal and axon).

A typical example of a heterogeneous neurite is the axon-carrying dendrite, in which the axon sprouts from the basal dendrite.


Identification
--------------

Heterogeneous neurites can be identified using the ``Neurite::is_heterogeneous`` method:

.. code:: python

from neurom import load_morphology
from neurom.core.morphology import iter_neurites

m = load_morphology('tests/data/swc/heterogeneous_morphology.swc')

print([neurite.is_heterogeneous() for neurite in m])

which would return ``[False, True, False]``, meaning the 2nd neurite extending from the soma contains multiple neurite types.


Sub-neurite views of heterogeneous neurites
--------------------------------------------

Default mode
~~~~~~~~~~~~

NeuroM does not take into account heterogeneous sub-neurites by default.
A heterogeneous neurite is treated as a homogeneous one, the type of which is determined by the first section of the tree.
For example:

.. code-block:: python

from neurom import load_morphology
from neurom.core.morphology import iter_neurites

m = load_morphology('tests/data/swc/heterogeneous_morphology.swc')

basal, axon_carrying_dendrite, apical = list(iter_neurites(m))

print(basal.type, axon_carrying_dendrite.type, apical.type)

Prints::

NeuriteType.basal_dendrite NeuriteType.basal_dendrite NeuriteType.apical_dendrite

I.E. the axon-carrying dendrite would be treated as a basal dendrite.
For feature extraction and checks, the axon-carrying dendrite is treated as a basal dendrite.
Features, for which an axon neurite type is passed, do not have access to the axonal part of the neurite.
For instance, the number of basal and axon neurites will be two and zero respectively.
mgeplf marked this conversation as resolved.
Show resolved Hide resolved
A features such as ``total_volume`` would include the entire axon-carrying dendrite, without separating between basal and axon types.

Sub-neurite mode
~~~~~~~~~~~~~~~~

NeuroM provides an immutable approach (without modifying the morphology) to access the homogeneous sub-neurites of a neurite.
Using ``iter_neurites`` with the flag ``use_subtrees`` returns a neurite view for each homogeneous sub-neurite.

.. code-block:: python

basal1, basal2, axon, apical = list(iter_neurites(m, use_subtrees=True))

print(basal1.type, basal2.type, axon.type, apical.type)

In the example above, two views of the axon-carrying dendrite have been created: the basal and axon dendrite views.

.. image:: images/heterogeneous_neurite.png

Given that the morphology is not modified, the sub-neurites specify as their ``root_node`` the section of the homogeneous sub-neurite.
They are just references to where the sub-neurites start.

.. note::
Creating neurite instances for the homogeneous sub-neurites breaks the assumption of root nodes not having a parent.


.. warning::
Be careful while using sub-neurites.
Because they just point to the start sections of the sub-neurite, they may include other sub-neurites as well.
In the figure example above, the basal sub-neurite includes the entire tree, including the axon sub-neurite.
An additional filtering of the sections is needed to leave out the axonal part.
However, for the axon sub-neurite this filtering is not needed because it is downstream homogeneous.


Extract features from heterogeneous morphologies
------------------------------------------------

Neurite
~~~~~~~

Neurite features have been extended to include a ``section_type`` argument, which can be used to apply a feature on a heterogeneous neurite.

.. code-block:: python

from neurom import NeuriteType
from neurom import load_morphology
from neurom.features.neurite import number_of_sections

m = load_morphology('tests/data/swc/heterogeneous_morphology.swc')

axon_carrying_dendrite = m.neurites[1]

total_sections = number_of_sections(axon_carrying_dendrite)
basal_sections = number_of_sections(axon_carrying_dendrite, section_type=NeuriteType.basal_dendrite)
axon_sections = number_of_sections(axon_carrying_dendrite, section_type=NeuriteType.axon)

print(total_sections, basal_sections, axon_sections)

Not specifying a ``section_type`` is equivalent to passing ``NeuriteType.all`` and it will use all sections as done historically.

Morphology
~~~~~~~~~~

Morphology features have been extended to include the ``use_subtrees`` flag, which allows to use the sub-neurites.

.. code-block:: python

from neurom import NeuriteType
from neurom import load_morphology
from neurom.features.morphology import number_of_neurites

m = load_morphology('tests/data/swc/heterogeneous_morphology.swc')

total_neurites_wout_subneurites = number_of_neurites(m)
total_neurites_with_subneurites = number_of_neurites(m, use_subtrees=True)

print("A:", total_neurites_wout_subneurites, total_neurites_with_subneurites)

number_of_axon_neurites_wout = number_of_neurites(m, neurite_type=NeuriteType.axon)
number_of_axon_neurites_with = number_of_neurites(m, neurite_type=NeuriteType.axon, use_subtrees=True)

print("B:", number_of_axon_neurites_wout, number_of_axon_neurites_with)

number_of_basal_neurites_wout = number_of_neurites(m, neurite_type=NeuriteType.basal_dendrite)
number_of_basal_neurites_with = number_of_neurites(m, neurite_type=NeuriteType.basal_dendrite, use_subtrees=True)

print("C:", number_of_basal_neurites_wout, number_of_basal_neurites_with)

Prints::

A: 3 4
B: 0 1
C: 2 2

In the example above, the total number of neurites increases from 3 to 4 when the subtrees are enabled (see ``A`` in the print out.)
This is because the axonal and basal parts of the axon-carrying dendrite are counted separately in the second case.

Specifying a ``neurite_type``, allows to count sub-neurites.
Therefore, the number of axons without subtrees is 0, whereas it is 1 when subtrees are enabled (see ``B`` in the print out.)
However, for basal dendrites the number does not change (2) because the axon-carrying dendrite is perceived as basal dendrite in the default case (see ``C``.)

features.get
~~~~~~~~~~~~

``features.get`` can be used with respect to what has been mentioned above for neurite and morphology features.

.. code-block:: python

from neurom import features
from neurom import load_morphology

m = load_morphology('tests/data/swc/heterogeneous_morphology.swc')

features.get("number_of_neurites", m, use_subtrees=True)
features.get("number_of_sections", m, section_type=NeuriteType.axon)

Conventions & Incompatibilities
-------------------------------

Heterogeneous Forks
~~~~~~~~~~~~~~~~~~~

A heterogeneous bifurcation/fork, i.e. a section with children of different types, is ignored when features on bifurcations are calculated.
It is not meaningful to calculate features, such as bifurcation angles, on transitional forks where the downstream subtrees have different types.

Incompatible features with subtrees
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The following features are not compatible with subtrees:

* trunk_origin_azimuths
* trunk_origin_elevations
* trunk_angles

Because they require the neurites to be rooted at the soma.
This is not true for sub-neurites.
Therefore, passing a ``use_subtrees`` flag will result in an error.
Binary file added doc/source/images/heterogeneous_neurite.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/source/images/heterogeneous_neuron.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ NeuroM is a Python-based toolkit for the analysis and processing of morphologies
features
spherical_coordinates
examples
heterogeneous
cli
definitions
api
Expand Down
67 changes: 63 additions & 4 deletions doc/source/morph_stats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Short format (prior version 3.0.0)
An example config:

.. code-block:: yaml

neurite:
section_lengths:
- max
Expand All @@ -67,13 +67,13 @@ An example config:
- total
section_branch_orders:
- max

neurite_type:
- AXON
- APICAL_DENDRITE
- BASAL_DENDRITE
- ALL

neuron:
soma_radius:
- mean
Expand All @@ -93,7 +93,7 @@ function, e.g.
* ``raw``: array of raw values
* ``max``, ``min``, ``mean``, ``median``, ``std``: self-explanatory.
* ``total``: sum of the raw values

An additional field ``neurite_type`` specifies the neurite types into which the morphometrics
are to be split. It applies only to ``neurite`` features. A sample output using the above
configuration:
Expand Down Expand Up @@ -198,6 +198,65 @@ So the example config from `Short format (prior version 3.0.0)`_ looks:
- mean


List of features format (starting version 3.2.0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The kwargs entry was converted into a list to allow running the same feature with different arguments. The ``partition_asymmetry`` feature in the example above can be specified multiple times with different arguments as follows:

.. code-block:: yaml

neurite:
partition_asymmetry:
kwargs:
- method: petilla
variant: length
- method: uylings
variant: branch-order
modes:
- max
- sum

To allow differentiation between the feature multiples, the keys and values of the kwargs are appended at the end of the feature name:

.. code-block::

partition_asymmetry__variant:length__method:petilla
partition_asymmetry__variant:branch-order__method:uylings

The example config from `Short format (prior version 3.0.0)`_ becomes:

.. code-block:: yaml

neurite:
section_branch_orders:
kwargs:
- {}
modes:
- max
section_lengths:
kwargs:
- {}
modes:
- max
- sum
section_volumes:
kwargs:
- {}
modes:
- sum
morphology:
soma_radius:
kwargs:
- {}
modes:
- mean
neurite_type:
- AXON
- APICAL_DENDRITE
- BASAL_DENDRITE
- ALL


Features
--------

Expand Down
Loading