NeuroM 1.0.0

NeuroM is a Python-based toolkit for the analysis and processing of neuron morphologies.


Contents

NeuroM Quick-Start

Install

Install the latest release:

$ pip install neurom

Install a specific version:

$ pip install neurom==1.2.3

Note

It is recommended that you install NeuroM into a virtualenv. See virtualenv setup for details on how to set that up.

See also

The installation instructions for more details and alternative installation methods.

Analyze, visualize, and check

The neurom module has various helper functions and command line applications to simplify loading neuron morphologies from files into neurom data structures and obtaining morphometrics, either from single or multiple neurons. The functionality described here is limited, but it is hoped that it will suffice for most analyses.

Extract morphometrics with neurom.get()

These are some of the properties can be obtained for a single neurite type or for all neurites regardless of type via the neurom.get() function:

  • Segment lengths
  • Section lengths
  • Segment radii
  • Number of sections
  • Number of sections per neurite
  • Number of neurites
  • Number of segments
  • Local and remote bifurcation angles
  • Section path distances
  • Section radial distances
  • Section branch orders
  • Total neurite length

The usage is simple:

import neurom as nm
nrn = nm.load_neuron('some/data/path/morph_file0.swc')
nrn_ap_seg_len = nm.get('segment_lengths', nrn, neurite_type=nm.APICAL_DENDRITE)
pop = nm.load_neurons('some/data/path')
pop_ap_seg_len = nm.get('segment_lengths', pop, neurite_type=nm.APICAL_DENDRITE)

This function also allows obtaining the soma radius and surface area.

Iterate over neurites with neurom.iter_neurites()

The neurom.iter_neurites() function allows to iterate over the neurites of a sungle neuron or a neuron population. It can also be applied to a single neurite or a list of neurites. It allows to optionally pass a function to be mapped onto each neurite, as well as a neurite filter function. In this example, we apply a simple user defined function to the apical dendrites in a population:

import neurom as nm

def user_func(neurite):
    print 'Analysinz neurite', neurite
    return len(neurite.points)

stuff = [x for x in nm.iter_neurites(pop, user_func, lambda n : n.type == nm.APICAL_DENDRITE)]

See also

The neurom documentation for more details and examples.

View neurons with neurom.viewer

There are also helper functions to plot a neuron in 2 and 3 dimensions.

The neurom.viewer.draw() function allows the user to make two and three-dimensional plots of neurites, somata and neurons. It also has a dendrogram neurom plotting mode.

See also

The neurom.viewer documentation for more details and examples.

Extract morphometrics into JSON files

The morph_stats application lets you obtain various morphometrics quantities from a set of morphology files. It is highly configurable, and gives access to all the features avaulable via the neurom.get() function.

For example,

$ morph_stats some/path/morph.swc # single file
{
  "some/path/morph.swc":{
    "axon":{
      "total_section_length":207.87975220908129,
      "max_section_length":11.018460736176685,
      "max_section_branch_order":10,
      "total_section_volume":276.73857657289523
    },
    "all":{
      "total_section_length":840.68521442251949,
      "max_section_length":11.758281556059444,
      "max_section_branch_order":10,
      "total_section_volume":1104.9077419665782
    },
    "mean_soma_radius":0.17071067811865476,
    "apical_dendrite":{
      "total_section_length":214.37304577550353,
      "max_section_length":11.758281556059444,
      "max_section_branch_order":10,
      "total_section_volume":271.9412385728449
    },
    "basal_dendrite":{
      "total_section_length":418.43241643793476,
      "max_section_length":11.652508126101711,
      "max_section_branch_order":10,
      "total_section_volume":556.22792682083821
    }
  }
}

$ morph_stats some/path # all files in directory
Check data validity

The morph_check application applies some structural and semantic checks to morphology data files in order to determine whether it is suitable to construct a neuron structure and whether certain defects within the structure are detected. It can be invoked from the command line, and takes as main argument the path to either a single file or a directory of morphology files.

For example,

$ morph_check some/path/morph.swc # single file
INFO: ========================================
INFO: File: test_data/swc/Neuron.swc
INFO:                      Is single tree PASS
INFO:                     Has soma points PASS
INFO:                  No missing parents PASS
INFO:                  Has sequential ids PASS
INFO:                  Has increasing ids PASS
INFO:                      Has valid soma PASS
INFO:                  Has valid neurites PASS
INFO:                  Has basal dendrite PASS
INFO:                            Has axon PASS
INFO:                 Has apical dendrite PASS
INFO:     Has all nonzero segment lengths PASS
INFO:     Has all nonzero section lengths PASS
INFO:       Has all nonzero neurite radii PASS
INFO:             Has nonzero soma radius PASS
INFO:                                 ALL PASS
INFO: ========================================

$ morph_check test_data/swc # all files in directory
# loops over all morphology files found in test_data/swc

Applications

NeuroM ships with configurable command line applications for commonly needed functionality. These are convenience tools which leverage NeuroM library funtionality without users having to concern themselves with writing any code beyond simple and optional configuration scripts. These commanline tools are installed as executable scripts with NeuroM. The tools are designed to be used in batch mode, i.e. they do not require any user interactivity upon launch, and do not require access to a display.

morph_check: the morphology checker

The morph_check application performs checks on reconstructed morphologies from data contained in morphology files, and so may be used as a morphology validaiton of sorts.

The tests are grouped in two categories:

  1. Structural tests. These apply to the structure of the data and are a good indicator as to whether a neuron object or any of its sub-components can actually be reconstructed. Failure in some of these may make further tests fail.
  2. Neuron tests. These are applied to properties of reconstructed neurons and their constituent soma and neurites, and can be thought of as “quality” checks.

It is very likely that a failure in the structural tests will make the neuron tests fail. Furthermore, inability to build a soma typically results in an inability to build neurites. Failure to build a soma or neurites results in an early faulure for a given morphology file.

The application may be invoked with a YAML configuration file specifying which checks to perform. The structure of the configuration file reflects the test categories mentioned above. Here is an example configuration:

checks:
    structural_checks:
        - is_single_tree
        - has_soma_points
        - has_valid_soma
        - has_valid_neurites
    neuron_checks:
        - has_basal_dendrite
        - has_axon
        - has_all_nonzero_segment_lengths
        - has_all_nonzero_section_lengths
        - has_all_nonzero_neurite_radii
        - has_nonzero_soma_radius

options :
    has_nonzero_soma_radius         : 0.0
    has_all_nonzero_neurite_radii   : 0.007
    has_all_nonzero_segment_lengths : 0.01
    has_all_nonzero_section_lengths : 0.01

As can be seen, the configuration file is split into two sections checks, and options. Each of the checks sub-items corresponds to a sub-module of neurom.check, namely structural_checks and neuron_checks. And each of their sub-items corresponds to a function in that sub-module. This illustrates the possible checks that may be applied by morph_check.

The application also produces a summary json file, which can be useful when processing more than one file:

{
    "files": {
        "test_data/swc/Neuron.swc": {
            "Is single tree": true,
            "Has soma points": true,
            "No missing parents": true,
            "Has sequential ids": true,
            "Has increasing ids": true,
            "Has valid soma": true,
            "Has valid neurites": true,
            "Has basal dendrite": true,
            "Has axon": true,
            "Has apical dendrite": true,
            "Has all nonzero segment lengths": true,
            "Has all nonzero section lengths": true,
            "Has all nonzero neurite radii": true,
            "Has nonzero soma radius": true,
            "ALL": true
        }
    },
    "STATUS": "PASS"
}

For more information on the application and available options, invoke it with the --help or -h option.

morph_check --help

morph_stats: morphometric statistics extraction

The morph_stats application extracts morphometrics from a set of neuron morpholigy files and produces a summary JSON output. It may obtain any of the morphometrics available in the neurom.get() function, and is highly configurable, allowing the user to get raw or summary statistics from a large set of neurite and neuron features.

The functionality can be best explained by looking at a sample configuration file:

neurite:
    section_lengths:
        - max
        - total
    section_volumes:
        - total
    section_branch_orders:
        - max

neurite_type:
    - AXON
    - APICAL_DENDRITE
    - BASAL_DENDRITE
    - ALL

neuron:
    soma_radii:
        - mean

Here, there are two feature categories,

  1. neurite: these are morphometrics obtained from neurites, e.g. branch orders, section lengths, bifurcation angles, path lengths.
  2. neuron: these are morphometrics that can be applied to a whole neuron, e.g. the soma radius, the trunk radii, etc.

Each category sub-item (section_lehgths, soma_radii, etc) corresponds to a neurom.get() feature, and each one of its sub-items corresponds to a statistic, 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. This is a sample output using the above configuration:

{
  "some/path/morph.swc":{
    "mean_soma_radius":0.17071067811865476,
    "axon":{
      "total_section_length":207.87975220908129,
      "max_section_length":11.018460736176685,
      "max_section_branch_order":10,
      "total_section_volume":276.73857657289523
    },
    "all":{
      "total_section_length":840.68521442251949,
      "max_section_length":11.758281556059444,
      "max_section_branch_order":10,
      "total_section_volume":1104.9077419665782
    },
    "apical_dendrite":{
      "total_section_length":214.37304577550353,
      "max_section_length":11.758281556059444,
      "max_section_branch_order":10,
      "total_section_volume":271.9412385728449
    },
    "basal_dendrite":{
      "total_section_length":418.43241643793476,
      "max_section_length":11.652508126101711,
      "max_section_branch_order":10,
      "total_section_volume":556.22792682083821
    }
  }
}

For more information on the application and available options, invoke it with the --help or -h option.

morph_stats --help

NeuroM morphology definitions

These are NeuroM specific working definitions of various components of neuron morpholigies.

Point

A point is a vector of numbers [X, Y, Z, R, TYPE, ID, PID] where the components are

  • X, Y, Z: Cartesian coordinates of position
  • R: Radius
  • TYPE: One of the NeuroM valid point types
  • ID: Unique identifier of the point.
  • PID: ID of the parent of the point.

Typically only the first four or five components are of interest to morphology analysis. The rest are used to construct the soma and hierarchical tree structures of the neuron, and to check its semantic validity.

In NeuroM a point is represented as an iterable of floating point numbers, usually a numpy array.

Note

For most of what follows, it suffices to consider a point as a vector of [X, Y, Z, R, TYPE]. The remaining components ID and PID can be considered book-keeping.

Todo

Point types may need to be restricted to align SWC with H5. This is dependent on future H5 specs.

Segment

A segment consists of two consecutive points belonging to the same neurite and section.

In NeuroM a segment is represented as a length 2 tuple or numpy array of points<point-label>.

Section

A section is a tree node containing a series of two or more points whose first and last element are any of the following combinations:

  • root node, forking point
  • forking point, forking point
  • forking point, end point
  • root node, end point

The first point of a section is a duplicate of the last point of its parent section, unless the latter is a soma section.

In NeuroM, a section is represented by class Section. This pseudocode shows the relevant parts of the section class:

section = {
    section_id,
    points,
    parent,
    children
}

Soma

A soma can be represented by one, three or more points. The soma is classified solely based on the number of points it contains thus:

  • Type A: 1 point defining the center and radius.
  • Type B: 3 points. Only the centers of the points are considered. The first point defines the center. The radius is estimated from the mean distance between the center and the two remaining points.
  • Type C: More than three points. The center is defined as the mean position of all points. The radius is defined as the mean distance of all points to the center.

Todo

Expand list if and when specifications require new types of soma.

The soma is represented by classes derived from Soma. The interface exports a center and radius. These can be calculated in different ways, but the default is to use the center and radius for type A and the mean center and radius for types B and C.

Todo

In the future, type B may be interpreted as 3 points on an ellipse. In this case, the points would have to be non-collinear. Currently there is no such restriction.

See also

Neurite tree

A neurite is essentially a tree of sections. The tree structure implies the following:

  • A node can only have one parent.
  • A node can have an arbitrary number of children.
  • No loops are present in the structure.

Neurites are represented by the class Neurite, which contains the root node of the aforementioned tree as well as some helper functions to aid iteration over sections and collection of points.

In NeuroM neurite trees are implemented using the recursive structure neurom.fst.Section, described above.

Neuron

A neuron structure consists of a single soma and a collection of neurites.

The trees that are expected to be present depend on the type of cell:

  • Interneuron (IN): basal dendrite, axon
  • Pyramidal cell (PC): basal dendrite, apical dendrite, axon

Neurons are represented by the class Neuron. This is more or less what it looks like:

neuron = {
    soma,
    neurites,
    points,
    name
}

Code Documentation

Public API

The public API is the stable, minimal set of entry points for end-users and developers who build code on top of NeuroM.

neurom NeuroM neurom morphology analysis package
neurom.viewer Tools to visualize neuron morphological objects
neurom.core Core functionality and data types of NeuroM
neurom.io IO operations module for NeuroM
neurom.check Basic tools to check neuronal morphologies.
neurom.stats Statistical analysis helper functions
neurom.exceptions Module containing NeuroM specific exceptions

Developer API

The developer API consists of implementation code supporting the public API, as well as rough experimental code that is not stable enough to be made public. This is intended for developers of NeuroM itself.

neurom.fst NeuroM, lightweight and fast
neurom.fst.sectionfunc Section functions and functional tools
neurom.check.structural_checks Module with consistency/validity checks for raw data blocks
neurom.check.neuron_checks NeuroM neuron checking functions.
neurom.core.types Type enumerations
neurom.core.tree Generic tree class and iteration functions
neurom.core._neuron Neuron classes and functions
neurom.core._soma Soma classes and functions
neurom.core.point Point classes and functions
neurom.core.dataformat Data format definitions
neurom.io.utils Utility functions and for loading neurons
neurom.io.swc Module for morphology SWC data loading
neurom.io.hdf5 Module for morphology HDF5 data loading
neurom.view View tools to visualize morphologies
neurom.view.common Module containing the common functionality to be used by view-plot modules.
neurom.view.view Python module of NeuroM to visualize morphologies
neurom.analysis Morphometrics of neurons
neurom.analysis.morphmath Mathematical and geometrical functions used to compute morphometrics

Supported file formats

NeuroM currently supports the SWC format, the BBP HDF5 formats, and offers experimental support for NeuroLucida .asc files.

See also

The morphology definitions page for definitions of concepts such as point, section, soma and neurite in NeuroM.

Todo

Complete this section with additional NeuroM specific restrictions on the formats below.

SWC

The SWC format represents a neuron as a tree of 3D points with additional information. More information can be found here.

Todo

Add reference to SWC paper and more semantic constraints.

Todo

Add semantic constraints on different soma types once these have been determined. For more info on what is to be considered, see neuromorpho.org’s.

HDF5

The HDF5 morphology formats developed by the BBP represent the neuron as a tree of sections. The specifications for the two versions of the format cn be found in the HBP morphology format documentation page.

NeuroLucida (experimental)

The NeuroLucida .asc file format is commonly used but lacking in an open format specification. NeuroM provides a best-effort experimental reader that parses information equivalent to the two formats above, that is to say, it does not deal with annotations or other meta-data, and is restricted purely to the topological and geometrical features of a neuron, as well as the neurite type information.

Warning

The NeuroLucida parser is experimental. Use at own risk when extracting numerical information. We make no statement as to the correctness of numerical output.

Todo

References and more information?

Installation

It is recommended that you use pip to install into NeuroM into a virtualenv. For details on how to set it up, see Virtualenv setup

Once the virtualenv is set up is set up and the pre-installed dependencies are taken care of, there are three ways to install NeuroM

  1. From the official Python Package Index server (PyPI)
  2. From the git repository
  3. From source (for NeuroM developers)

Install from the official PyPI server

Install the latest release:

(nrm)$ pip install neurom

Install a specific version:

(nrm)$ pip install neurom==1.2.3

Install from git

Install a particular release:

(nrm)$ pip install git+https://github.com/BlueBrain/NeuroM.git@v0.1.0

Install the latest version:

(nrm)$ pip install git+https://github.com/BlueBrain/NeuroM.git

Install from source

Clone the repository and install it:

(nrm)$ git clone https://github.com/BlueBrain/NeuroM.git
(nrm)$ pip install -e ./NeuroM

This installs NeuroM into your virtualenv in “editable” mode. That means that changes made to the source code after the installation procedure are seen by the installed package. To install in read-only mode, omit the -e.

Virtualenv setup

$ virtualenv --system-site-packages nrm   # creates a virtualenv called "nrm" in nrm directory
$ source nrm/bin/activate                 # activates virtualenv
(nrm)$                                    # now we are in the nrm virtualenv

Here, the --system-site-packages option has been used. This is because dependencies such as matplotlib aren’t trivial to build in a virtualenv. This setting allows python packages installed in the system to be used inside the virtualenv.

The prompt indicates that the virtualenv has been activated. To de-activate it,

(nrm)$ deactivate

Note that you do not have to work in the nrm directory. This is where python packages will get installed, but you can work anywhere on your file system, as long as you have activated the virtualenv.

Note

In following code samples, the prompts (nrm)$ and $ are used to indicate that the user virtualenv is activated or deactivated respectively.

Note

In following code samples, the prompt >>> indicates a python interpreter session started with the virtualenv activated. That gives access to the neurom installation.

Examples

Fast analysis with neurom

Here we load a neuron and obtain some information from it:

>>> import neurom as nm
>>> nrn = nm.load_neuron('some/data/path/morph_file.swc')
>>> ap_seg_len = nm.get('segment_lengths', nrn, neurite_type=nm.APICAL_DENDRITE)
>>> ax_sec_len = nm.get('section_lengths', nrn, neurite_type=nm.AXON)

Morphology visualization with the neurom.viewer module

Here we visualize a neuronal morphology:

>>> # Initialize nrn as above
>>> from neurom import viewer
>>> fig, ax = viewer.draw(nrn)
>>> fig.show()
>>> fig, ax = viewer.draw(nrn, mode='3d') # valid modes '2d', '3d', 'dendrogram'
>>> fig.show()

Basic feature extraction example

These basic examples illustrate the type of morphometrics that can be easily obtained directly from the neurom module, without the need for any other neurom sub-modules or tools.

The idea here is to pre-package the most common analyses so that users can obtain the morphometrics with a very minimal knowledge of python and neurom.

'''Easy analysis examples

These examples highlight most of the pre-packaged neurom.nm.get
morphometrics functionality.

'''

from __future__ import print_function
from pprint import pprint
import numpy as np
import neurom as nm


def stats(data):
    '''Dictionary with summary stats for data

    Returns:
        dicitonary with length, mean, sum, standard deviation,\
            min and max of data
    '''
    return {'len': len(data),
            'mean': np.mean(data),
            'sum': np.sum(data),
            'std': np.std(data),
            'min': np.min(data),
            'max': np.max(data)}


def pprint_stats(data):
    '''Pretty print summary stats for data'''
    pprint(stats(data))


if __name__ == '__main__':

    filename = 'test_data/swc/Neuron.swc'

    #  load a neuron from an SWC file
    nrn = nm.load_neuron(filename)

    # Get some soma information
    # Soma radius and surface area
    print("Soma radius", nm.get('soma_radii', nrn)[0])
    print("Soma surface area", nm.get('soma_surface_areas', nrn)[0])

    # Get information about neurites
    # Most neurite data can be queried for a particular type of neurite.
    # The allowed types are members of the NeuriteType enumeration.
    # NEURITE_TYPES is a list of valid neurite types.

    # We start by calling methods for different neurite types separately
    # to warm up...

    # number of neurites
    print('Number of neurites (all):', nm.get('number_of_neurites', nrn)[0])
    print('Number of neurites (axons):',
          nm.get('number_of_neurites', nrn, neurite_type=nm.NeuriteType.axon)[0])
    print('Number of neurites (apical dendrites):',
          nm.get('number_of_neurites', nrn, neurite_type=nm.NeuriteType.apical_dendrite)[0])
    print('Number of neurites (basal dendrites):',
          nm.get('number_of_neurites', nrn, neurite_type=nm.NeuriteType.basal_dendrite)[0])

    # number of sections
    print('Number of sections:',
          nm.get('number_of_sections', nrn)[0])
    print('Number of sections (axons):',
          nm.get('number_of_sections', nrn, neurite_type=nm.NeuriteType.axon)[0])
    print('Number of sections (apical dendrites):',
          nm.get('number_of_sections', nrn, neurite_type=nm.NeuriteType.apical_dendrite)[0])
    print('Number of sections (basal dendrites):',
          nm.get('number_of_sections', nrn, neurite_type=nm.NeuriteType.basal_dendrite)[0])

    # number of sections per neurite
    print('Number of sections per neurite:',
          nm.get('number_of_sections_per_neurite', nrn))
    print('Number of sections per neurite (axons):',
          nm.get('number_of_sections_per_neurite', nrn, neurite_type=nm.NeuriteType.axon))
    print('Number of sections per neurite (apical dendrites):',
          nm.get('number_of_sections_per_neurite',
                 nrn, neurite_type=nm.NeuriteType.apical_dendrite))
    print('Number of sections per neurite (basal dendrites):',
          nm.get('number_of_sections_per_neurite',
                 nrn, neurite_type=nm.NeuriteType.apical_dendrite))

    # OK, this is getting repetitive, so lets loop over valid neurite types.
    # The following methods return arrays of measurements. We will gather some
    # summary statistics for each and print them.

    # Section lengths for all and different types of neurite
    for ttype in nm.NEURITE_TYPES:
        sec_len = nm.get('section_lengths', nrn, neurite_type=ttype)
        print('Section lengths (', ttype, '):', sep='')
        pprint_stats(sec_len)

    # Segment lengths for all and different types of neurite
    for ttype in nm.NEURITE_TYPES:
        seg_len = nm.get('segment_lengths', nrn, neurite_type=ttype)
        print('Segment lengths (', ttype, '):', sep='')
        pprint_stats(seg_len)

    # Section radial distances for all and different types of neurite
    # Careful! Here we need to pass tree type as a named argument
    for ttype in nm.NEURITE_TYPES:
        sec_rad_dist = nm.get('section_radial_distances', nrn, neurite_type=ttype)
        print('Section radial distance (', ttype, '):', sep='')
        pprint_stats(sec_rad_dist)

    # Section path distances for all and different types of neurite
    # Careful! Here we need to pass tree type as a named argument
    for ttype in nm.NEURITE_TYPES:
        sec_path_dist = nm.get('section_path_distances', nrn, neurite_type=ttype)
        print('Section path distance (', ttype, '):', sep='')
        pprint_stats(sec_path_dist)

    # Local bifurcation angles for all and different types of neurite
    for ttype in nm.NEURITE_TYPES:
        local_bifangles = nm.get('local_bifurcation_angles', nrn, neurite_type=ttype)
        print('Local bifurcation angles (', ttype, '):', sep='')
        pprint_stats(local_bifangles)

    # Remote bifurcation angles for all and different types of neurite
    for ttype in nm.NEURITE_TYPES:
        rem_bifangles = nm.get('remote_bifurcation_angles', nrn, neurite_type=ttype)
        print('Local bifurcation angles (', ttype, '):', sep='')
        pprint_stats(rem_bifangles)

Advanced iterator-based feature extraction example

These slightly more complex examples illustrate what can be done with the neurom module’s various generic iterators and simple morphometric functions.

The idea here is that there is a great deal of flexibility to build new analyses based on some limited number of orthogonal iterator and morphometric components that can be combined in many ways. Users with some knowledge of python and neurom can easily implement code to obtain new morphometrics.

All of the examples in the previous sections can be implemented in a similar way to those presented here.

'''Advanced analysis examples

These examples highlight more advanced neurom
morphometrics functionality using iterators.

'''

from __future__ import print_function
from neurom.core.dataformat import COLS
import neurom as nm
from neurom import geom
from neurom.fst import iter_sections, iter_segments, sectionfunc
from neurom.core import Tree
from neurom.core.types import tree_type_checker, NEURITES
from neurom.analysis import morphmath as mm
import numpy as np


if __name__ == '__main__':

    filename = 'test_data/swc/Neuron.swc'

    #  load a neuron from an SWC file
    nrn = nm.load_neuron(filename)

    # Some examples of what can be done using iteration
    # instead of pre-packaged functions that return lists.
    # The iterations give us a lot of flexibility: we can map
    # any function that takes a segment or section.

    # Get of all neurites in cell by iterating over sections,
    # and summing the section lengths
    def sec_len(sec):
        '''Return the length of a section'''
        return mm.section_length(sec.points)

    print('Total neurite length (sections):',
          sum(sec_len(s) for s in iter_sections(nrn)))

    # Get length of all neurites in cell by iterating over segments,
    # and summing the segment lengths.
    # This should yield the same result as iterating over sections.
    print('Total neurite length (segments):',
          sum(mm.segment_length(s) for s in iter_segments(nrn)))

    # get volume of all neurites in cell by summing over segment
    # volumes
    print('Total neurite volume:',
          sum(mm.segment_volume(s) for s in iter_segments(nrn)))

    # get area of all neurites in cell by summing over segment
    # areas
    print('Total neurite surface area:',
          sum(mm.segment_area(s) for s in iter_segments(nrn)))

    # get total number of neurite points in cell.
    def n_points(sec):
        '''number of points in a section'''
        n = len(sec.points)
        # Non-root sections have duplicate first point
        return n if sec.parent is None else n - 1

    print('Total number of points:',
          sum(n_points(s) for s in iter_sections(nrn)))

    # get mean radius of neurite points in cell.
    # p[COLS.R] yields the radius for point p.
    # Note: this includes duplicated points at beginning of
    # non-trunk sections
    print('Mean radius of points:',
          np.mean([s.points[:, COLS.R] for s in iter_sections(nrn)]))

    # get mean radius of neurite points in cell.
    # p[COLS.R] yields the radius for point p.
    # Note: this includes duplicated points at beginning of
    # non-trunk sections
    pts = [p[COLS.R] for s in nrn.sections[1:] for p in s.points]
    print('Mean radius of points:',
          np.mean(pts))

    # get mean radius of segments
    print('Mean radius of segments:',
          np.mean(list(mm.segment_radius(s) for s in iter_segments(nrn))))

    # get stats for the segment taper rate, for different types of neurite
    for ttype in NEURITES:
        ttt = ttype
        seg_taper_rate = [mm.segment_taper_rate(s)
                          for s in iter_segments(nrn, neurite_filter=tree_type_checker(ttt))]

        print('Segment taper rate (', ttype,
              '):\n  mean=', np.mean(seg_taper_rate),
              ', std=', np.std(seg_taper_rate),
              ', min=', np.min(seg_taper_rate),
              ', max=', np.max(seg_taper_rate),
              sep='')

    # Number of bifurcation points.
    print('Number of bifurcation points:',
          sum(1 for _ in iter_sections(nrn,
                                       iterator_type=Tree.ibifurcation_point)))

    # Number of bifurcation points for apical dendrites
    print('Number of bifurcation points (apical dendrites):',
          sum(1 for _ in iter_sections(nrn,
                                       iterator_type=Tree.ibifurcation_point,
                                       neurite_filter=tree_type_checker(nm.APICAL_DENDRITE))))

    # Maximum branch order
    print('Maximum branch order:',
          max(sectionfunc.branch_order(s) for s in iter_sections(nrn)))

    # Neuron's bounding box
    # Note: does not account for soma radius
    print('Bounding box ((min x, y, z), (max x, y, z))', geom.bounding_box(nrn))

Reporting issues

Issues should be reported to the NeuroM github repository issue tracker. The ability and speed with which issues can be resolved depends on how complete and succinct the report is. For this reason, it is recommended that reports be accompanied with

  • A minimal but self-contained code sample that reproduces the issue. Minimal means no code that is irrelevant to the issue should be included. Self-contained means it should be possible to run the code without modifications and reproduce the problem.
  • The observed and expected output and/or behaviour. If the issue is an error, the python error stack trace is extremely useful.
  • The commit ID of the version used. This is particularly important if reporting an error from an older version of NeuroM.
  • If reporting a regression, the commit ID of the change that introduced the problem
  • If the issue depends on data, a data sample which reproduces the problem should be up-loaded. But check first whether the error can be reproduced with any of the data samples available in the test_data directory.

Developer Documentation

Development Workflow

  • Fork from github
  • Develop on your fork
  • Test locally
  • Make a pull request

Before making a pull request, make sure that your fork is up to date and that all the tests pass locally. This will make it less likely that your pull request will get rejected by making breaking chages or by failing the test requirements.

Running the tests

The tests require that you have cloned the repository, since the test code is not distributed in the package. It is recommended to use nosetests for this. There are two options:

Use the provided Makefile to run the tests using make:

$ git clone https://github.com/BlueBrain/NeuroM.git
$ cd NeuroM
$ make test

This runs pep8, pylint and the unit tests in sequence.

This method takes care of installing all extra dependencies needed for running the tests, diagnosing the results, performing linting on the source code. These dependencies are installed into a virtuanelv named neurom_test_venv:

The Makefile also has targets for running only pylint and pep8 individually:

$ make lint       # runs pep8 and pylint if that succeeds
$ make run_pep8   # run only pep8
$ make run_pylint # run only pep8

Note that you can also install the test dependencies and run the tests inside of your own virtualenv:

(nrm)$ pip install -r requirements_dev.txt

This installs the following packages into your virtualenv unless they are already installed:

mock>=1.3.0
pep8>=1.6.0
astroid>=1.3,<1.4
pylint>=1.4.0,<1.5
nose>=1.3.0
coverage==3.7
nosexcover>=1.0.8
sphinx>=1.3.0

Then, run the tests manually in the virtualenv. For example,

(nrm)$ nosetests -v --with-coverage --cover-min-percentage=100 --cover-package neurom

Warning

To ensure that the test requirements are the same as those run in continuous integration, you should run the tests using the make test command. This is the same command used in continuous integration. Failure to pass means will result in a pull request being rejected.

Building the Documentation

The documentation requires that you clone the repository. Once you have done that, there’s a make target to build the HTML version of the documentation:

$ git clone https://github.com/BlueBrain/NeuroM.git
....
$ cd NeuroM # repository location
$ make doc

This builds the documentation in doc/build. To view it, point a browser at doc/build/html/index.html

Dependencies

Build and runtime

Pre-installed dependencies

It is recommended that these be installed into your system before attempting to install NeuroM. These are not installed automatically.

Automatically installed dependencies

These dependencies are installed automatically when installing with pip:

Installing and building

Testing and documentation

These dependencies are not needed for installing and running NeuroM, but are useful for those who want to contribute to its development.

License

Copyright © 2015, 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.


Indices and tables