Exemple #1
0
def get_common_bounding_box(neurons):
    '''Returns the bounding box that wraps all neurons'''
    common_bbox = geom.bounding_box(neurons[0])
    for neuron in neurons[1:]:
        bbox = geom.bounding_box(neuron)
        common_bbox[0] = np.min(np.vstack([common_bbox[0], bbox[0]]), axis=0)
        common_bbox[1] = np.max(np.vstack([common_bbox[1], bbox[1]]), axis=0)

    return common_bbox
Exemple #2
0
def sholl_frequency(nrn, neurite_type=NeuriteType.all, bins=10):
    """Perform Sholl frequency calculations on a population of neurites.

    Args:
        nrn(morph): nrn or population
        neurite_type(NeuriteType): which neurites to operate on
        bins(iterable of floats|int): binning to use for the Sholl radii. If ``int`` is used then \
            it sets the number of bins in the interval between min and max radii of ``nrn``.

    Note:
        Given a neuron, the soma center is used for the concentric circles,
        which range from the soma radii, and the maximum radial distance
        in steps of `step_size`.  When a population is given, the concentric
        circles range from the smallest soma radius to the largest radial neurite
        distance.  Finally, each segment of the neuron is tested, so a neurite that
        bends back on itself, and crosses the same Sholl radius will get counted as
        having crossed multiple times.
    """
    nrns = neuron_population(nrn)
    if isinstance(bins, int):
        min_soma_edge = min(neuron.soma.radius for neuron in nrns)
        max_radii = np.max([np.abs(bounding_box(neuron)) for neuron in nrns])
        bins = np.linspace(min_soma_edge, max_radii, bins)

    return sum(
        sholl_crossings(neuron, neuron.soma.center, bins, is_type(
            neurite_type)) for neuron in nrns)
Exemple #3
0
def plot(neuron, result, inline=False):
    '''Plot the neuron, the cut plane and the cut leaves.

    Args:
        neuron (Neuron): the neuron to be plotted
        result (dict): the cut plane object in dictionary form
        inline (bool): if True, plot as an interactive plot (for example in a Jupyter notebook)
    '''
    try:
        from plotly_helper.neuron_viewer import NeuronBuilder
        from plotly_helper.object_creator import scatter
        from plotly_helper.shapes import line
    except ImportError as e:
        raise ImportError(
            'neuror[plotly] is not installed.'
            ' Please install it by doing: pip install neuror[plotly]') from e

    bbox = geom.bounding_box(neuron)

    plane = result['cut-plane']

    for display_plane, idx in [('xz', 0), ('yz', 1), ('3d', None)]:
        builder = NeuronBuilder(neuron, display_plane, inline=inline,
                                line_width=4, title='{}'.format(neuron.name))
        if idx is not None:
            if plane['a'] == 0 and plane['b'] == 0:
                builder.helper.add_shapes([
                    line(bbox[0][idx], -plane['d'], bbox[1][idx], -plane['d'], width=4)
                ])
            builder.helper.add_data({'a': scatter(result['cut-leaves'][:, [idx, 2]],
                                                  showlegend=False, width=5)})
        else:
            builder.helper.add_data({'a': scatter(result['cut-leaves'], width=2)})
        builder.plot()
Exemple #4
0
def neuron3d(nrn, new_fig=True, new_axes=True, subplot=False, **kwargs):
    '''
    Generates a figure of the neuron,
    that contains a soma and a list of trees.

    Parameters:
        neuron: Neuron \
        neurom.Neuron object
        diameter: boolean
            If True the diameter, scaled with diameter_scale factor, \
            will define the width of the tree lines. \
            If False use linewidth to select the width of the tree lines. \
            Default value is True.
        diameter_scale: float \
            Defines the scale factor that will be multiplied \
            with the diameter to define the width of the tree line. \
            Default value is 1.
    '''
    # Initialization of matplotlib figure and axes.
    fig, ax = common.get_figure(new_fig=new_fig, new_axes=new_axes,
                                subplot=subplot, params={'projection': '3d'})

    white_space = get_default('white_space', **kwargs)

    kwargs['new_fig'] = False
    kwargs['subplot'] = subplot
    kwargs['new_axes'] = False
    kwargs['title'] = kwargs.get('title', nrn.name)

    kwargs['final'] = False

    soma3d(nrn.soma, **kwargs)

    boundaries = [[], [], []]

    for temp_tree in nrn.neurites:

        bounding_box = geom.bounding_box(temp_tree)

        boundaries[0].append([bounding_box[0][getattr(COLS, 'X')],
                              bounding_box[1][getattr(COLS, 'X')]])
        boundaries[1].append([bounding_box[0][getattr(COLS, 'Y')],
                              bounding_box[1][getattr(COLS, 'Y')]])
        boundaries[2].append([bounding_box[0][getattr(COLS, 'Z')],
                              bounding_box[1][getattr(COLS, 'Z')]])

        tree3d(temp_tree, **kwargs)

    if len(boundaries[0]) > 0:
        kwargs['xlim'] = kwargs.get('xlim', [np.min(boundaries[0]) - white_space,
                                             np.max(boundaries[0]) + white_space])
    if len(boundaries[1]) > 0:
        kwargs['ylim'] = kwargs.get('ylim', [np.min(boundaries[1]) - white_space,
                                             np.max(boundaries[1]) + white_space])
    if len(boundaries[2]) > 0:
        kwargs['zlim'] = kwargs.get('zlim', [np.min(boundaries[2]) - white_space,
                                             np.max(boundaries[2]) + white_space])

    return common.plot_style(fig=fig, ax=ax, **kwargs)
Exemple #5
0
def bounding_box(neurite):
    '''Get a neurite's X,Y,Z bounding box'''
    if is_new_style(neurite):
        if isinstance(neurite, Section):
            neurite = Neurite(neurite)
        return geom.bounding_box(neurite)
    else:
        return get_bounding_box(neurite)
Exemple #6
0
def _update_3d_datalim(ax, obj):
    '''unlike w/ 2d Axes, the dataLim isn't set by collections, so it has to be updated manually'''
    min_bounding_box, max_bounding_box = geom.bounding_box(obj)
    xy_bounds = np.vstack((min_bounding_box[:COLS.Z],
                           max_bounding_box[:COLS.Z]))
    ax.xy_dataLim.update_from_data_xy(xy_bounds, ignore=False)

    z_bounds = np.vstack(((min_bounding_box[COLS.Z], min_bounding_box[COLS.Z]),
                          (max_bounding_box[COLS.Z], max_bounding_box[COLS.Z])))
    ax.zz_dataLim.update_from_data_xy(z_bounds, ignore=False)
Exemple #7
0
def test_bounding_box():

    pts = np.array([[-1, -2, -3, -999], [1, 2, 3, 1000], [-100, 5, 33, 42],
                    [42, 55, 12, -3]])

    obj = PointObj()
    obj.points = pts

    nt.assert_true(
        np.alltrue(geom.bounding_box(obj) == [[-100, -2, -3], [42, 55, 33]]))
Exemple #8
0
def _update_3d_datalim(ax, obj):
    '''unlike w/ 2d Axes, the dataLim isn't set by collections, so it has to be updated manually'''
    min_bounding_box, max_bounding_box = geom.bounding_box(obj)
    xy_bounds = np.vstack((min_bounding_box[:COLS.Z],
                           max_bounding_box[:COLS.Z]))
    ax.xy_dataLim.update_from_data_xy(xy_bounds, ignore=False)

    z_bounds = np.vstack(((min_bounding_box[COLS.Z], min_bounding_box[COLS.Z]),
                          (max_bounding_box[COLS.Z], max_bounding_box[COLS.Z])))
    ax.zz_dataLim.update_from_data_xy(z_bounds, ignore=False)
Exemple #9
0
def plot_soma(ax,
              soma,
              plane='xy',
              soma_outline=True,
              linewidth=_LINEWIDTH,
              color=None,
              alpha=_ALPHA):
    '''Generates a 2d figure of the soma.

    Args:
        ax(matplotlib axes): on what to plot
        soma(neurom.core.Soma): plotted soma
        plane(str): Any pair of 'xyz'
        diameter_scale(float): Scale factor multiplied with segment diameters before plotting
        linewidth(float): all segments are plotted with this width, but only if diameter_scale=None
        color(str or None): Color of plotted values, None corresponds to default choice
        alpha(float): Transparency of plotted values
    '''
    plane0, plane1 = _plane2col(plane)
    color = _get_color(color, tree_type=NeuriteType.soma)

    if isinstance(soma, SomaCylinders):
        plane0, plane1 = _plane2col(plane)
        for start, end in zip(soma.points, soma.points[1:]):
            common.project_cylinder_onto_2d(ax, (plane0, plane1),
                                            start=start[COLS.XYZ],
                                            end=end[COLS.XYZ],
                                            start_radius=start[COLS.R],
                                            end_radius=end[COLS.R],
                                            color=color,
                                            alpha=alpha)
    else:
        if soma_outline:
            ax.add_artist(
                Circle(soma.center[[plane0, plane1]],
                       soma.radius,
                       color=color,
                       alpha=alpha))
        else:
            plane0, plane1 = _plane2col(plane)
            points = [(p[plane0], p[plane1]) for p in soma.iter()]

            if points:
                points.append(points[0])  # close the loop
                ax.plot(points, color=color, alpha=alpha, linewidth=linewidth)

    ax.set_xlabel(plane[0])
    ax.set_ylabel(plane[1])

    bounding_box = geom.bounding_box(soma)
    ax.dataLim.update_from_data_xy(np.vstack(
        ([bounding_box[0][plane0], bounding_box[0][plane1]],
         [bounding_box[1][plane0], bounding_box[1][plane1]])),
                                   ignore=False)
Exemple #10
0
def test_bounding_box():

    pts = np.array([[-1, -2, -3, -999],
                    [1, 2, 3, 1000],
                    [-100, 5, 33, 42],
                    [42, 55, 12, -3]])

    obj = PointObj()
    obj.points = pts

    nt.assert_true(np.alltrue(geom.bounding_box(obj) == [[-100, -2, -3], [42, 55, 33]]))
Exemple #11
0
def plot_soma(ax, soma, plane='xy',
              soma_outline=True,
              linewidth=_LINEWIDTH,
              color=None, alpha=_ALPHA):
    '''Generates a 2d figure of the soma.

    Args:
        ax(matplotlib axes): on what to plot
        soma(neurom.core.Soma): plotted soma
        plane(str): Any pair of 'xyz'
        diameter_scale(float): Scale factor multiplied with segment diameters before plotting
        linewidth(float): all segments are plotted with this width, but only if diameter_scale=None
        color(str or None): Color of plotted values, None corresponds to default choice
        alpha(float): Transparency of plotted values
    '''
    plane0, plane1 = _plane2col(plane)
    color = _get_color(color, tree_type=NeuriteType.soma)

    if isinstance(soma, SomaCylinders):
        plane0, plane1 = _plane2col(plane)
        for start, end in zip(soma.points, soma.points[1:]):
            common.project_cylinder_onto_2d(ax, (plane0, plane1),
                                            start=start[COLS.XYZ], end=end[COLS.XYZ],
                                            start_radius=start[COLS.R], end_radius=end[COLS.R],
                                            color=color, alpha=alpha)
    else:
        if soma_outline:
            ax.add_artist(Circle(soma.center[[plane0, plane1]], soma.radius,
                                 color=color, alpha=alpha))
        else:
            plane0, plane1 = _plane2col(plane)
            points = [(p[plane0], p[plane1]) for p in soma.iter()]

            if points:
                points.append(points[0])  # close the loop
                ax.plot(points, color=color, alpha=alpha, linewidth=linewidth)

    ax.set_xlabel(plane[0])
    ax.set_ylabel(plane[1])

    bounding_box = geom.bounding_box(soma)
    ax.dataLim.update_from_data_xy(np.vstack(([bounding_box[0][plane0], bounding_box[0][plane1]],
                                              [bounding_box[1][plane0], bounding_box[1][plane1]])),
                                   ignore=False)
Exemple #12
0
def sholl_frequency(nrn, neurite_type=NeuriteType.all, step_size=10):
    """Perform Sholl frequency calculations on a population of neurites.

    Args:
        nrn(morph): nrn or population
        neurite_type(NeuriteType): which neurites to operate on
        step_size(float): step size between Sholl radii

    Note:
        Given a neuron, the soma center is used for the concentric circles,
        which range from the soma radii, and the maximum radial distance
        in steps of `step_size`.  When a population is given, the concentric
        circles range from the smallest soma radius to the largest radial neurite
        distance.  Finally, each segment of the neuron is tested, so a neurite that
        bends back on itself, and crosses the same Sholl radius will get counted as
        having crossed multiple times.
    """
    nrns = neuron_population(nrn)
    neurite_filter = is_type(neurite_type)

    min_soma_edge = float('Inf')
    max_radii = 0
    neurites_list = []
    for neuron in nrns:
        neurites_list.extend(((neurites, neuron.soma.center)
                              for neurites in neuron.neurites
                              if neurite_filter(neurites)))

        min_soma_edge = min(min_soma_edge, neuron.soma.radius)
        max_radii = max(max_radii, np.max(np.abs(bounding_box(neuron))))

    radii = np.arange(min_soma_edge, max_radii + step_size, step_size)
    ret = np.zeros_like(radii)
    for neurites, center in neurites_list:
        ret += sholl_crossings(neurites, center, radii)

    return ret
Exemple #13
0
def test_bounding_box_neurite():
    nrt = NRN.neurites[0]
    ref = np.array([[-33.25305769, -57.600172, 0.], [0., 0., 49.70137991]])
    nt.assert_true(np.allclose(geom.bounding_box(nrt), ref))
Exemple #14
0
def test_bounding_box_neuron():

    ref = np.array([[-40.32853516, -57.600172  , 0.],
                    [ 64.74726272, 48.51626225, 54.20408797]])

    nt.assert_true(np.allclose(geom.bounding_box(NRN), ref))
Exemple #15
0
def test_bounding_box_neurite():
    nrt = NRN.neurites[0]
    ref = np.array([[-33.25305769, -57.600172, 0.], [0., 0., 49.70137991]])
    nt.assert_true(np.allclose(geom.bounding_box(nrt), ref))
Exemple #16
0
def test_bounding_box_soma():
    ref = np.array([[0., 0., 0.], [0.1, 0.2, 0.]])
    nt.assert_true(np.allclose(geom.bounding_box(NRN.soma), ref))
Exemple #17
0
def tree(tr, plane='xy', new_fig=True, subplot=False, **kwargs):
    '''
    Generates a 2d figure of the tree's segments. \
    If the tree contains one single point the plot will be empty \
    since no segments can be constructed.

    Parameters:
        tr: Tree \
            neurom.Tree object
        plane: str \
            Accepted values: Any pair of of xyz \
            Default value is 'xy'.treecolor
        diameter: boolean
            If True the diameter, scaled with diameter_scale factor, \
            will define the width of the tree lines. \
            If False use linewidth to select the width of the tree lines. \
            Default value is True.
        diameter_scale: float \
            Defines the scale factor that will be multiplied \
            with the diameter to define the width of the tree line. \
            Default value is 1.
        white_space: float \
            Defines the white space around \
            the boundary box of the morphology. \
            Default value is 1.
    '''
    if plane not in ('xy', 'yx', 'xz', 'zx', 'yz', 'zy'):
        return None, 'No such plane found! Please select one of: xy, xz, yx, yz, zx, zy.'

    # Initialization of matplotlib figure and axes.
    fig, ax = common.get_figure(new_fig=new_fig, subplot=subplot)

    # Data needed for the viewer: x,y,z,r
    bounding_box = geom.bounding_box(tr)

    white_space = get_default('white_space', **kwargs)

    def _seg_2d(seg):
        '''2d coordinates needed for the plotting of a segment'''
        horz = getattr(COLS, plane[0].capitalize())
        vert = getattr(COLS, plane[1].capitalize())
        parent_point = seg[0]
        child_point = seg[1]
        horz1 = parent_point[horz]
        horz2 = child_point[horz]
        vert1 = parent_point[vert]
        vert2 = child_point[vert]
        return ((horz1, vert1), (horz2, vert2))

    segs = map_segments(tr, _seg_2d)

    linewidth = get_default('linewidth', **kwargs)
    # Definition of the linewidth according to diameter, if diameter is True.
    if get_default('diameter', **kwargs):
        scale = get_default('diameter_scale', **kwargs)
        # TODO: This was originally a numpy array. Did it have to be one?
        linewidth = [2 * r * scale for r in map_segments(tr, segment_radius)]
        if len(linewidth) == 0:
            linewidth = get_default('linewidth', **kwargs)

    # Plot the collection of lines.
    collection = LineCollection(segs,
                                color=common.get_color(get_default('treecolor', **kwargs),
                                                       tr.type),
                                linewidth=linewidth, alpha=get_default('alpha', **kwargs))

    ax.add_collection(collection)

    kwargs['title'] = kwargs.get('title', 'Tree view')
    kwargs['xlabel'] = kwargs.get('xlabel', plane[0])
    kwargs['ylabel'] = kwargs.get('ylabel', plane[1])
    kwargs['xlim'] = kwargs.get('xlim', [bounding_box[0][getattr(COLS, plane[0].capitalize())] -
                                         white_space,
                                         bounding_box[1][getattr(COLS, plane[0].capitalize())] +
                                         white_space])
    kwargs['ylim'] = kwargs.get('ylim', [bounding_box[0][getattr(COLS, plane[1].capitalize())] -
                                         white_space,
                                         bounding_box[1][getattr(COLS, plane[1].capitalize())] +
                                         white_space])

    return common.plot_style(fig=fig, ax=ax, **kwargs)
Exemple #18
0
def test_bounding_box_neuron():

    ref = np.array([[-40.32853516, -57.600172, 0.],
                    [64.74726272, 48.51626225, 54.20408797]])

    assert np.allclose(geom.bounding_box(NRN), ref)
Exemple #19
0
print(
    'Number of bifurcation points:',
    sum(1
        for _ in nm.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 nm.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 nm.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))

#with open(os.curdir + '/exp14_17 Pos_R1_7 M-exported-000.swc', 'r') as f, open(os.curdir + '/new_scw.scw', 'w') as ff:
#    lines = f.readlines()
#
#    for i, line in enumerate(lines):
#        row = line.split(' ')
#
#        if i > 5:
#            row[-2] = '1.0'
#
#        ff.write(' '.join(row))
Exemple #20
0
def test_bounding_box_neurite():
    nrt = SIMPLE.neurites[0]
    ref = np.array([[-5.,  0.,  0.], [ 6.,  5.,  0.]])
    np.testing.assert_allclose(geom.bounding_box(nrt), ref)
Exemple #21
0
def set_neuron(filename):
    '''Globally loads the neuron'''
    global NEURON, FIGURE, BBOX  # pylint: disable=global-statement
    NEURON = load_neuron(filename)
    FIGURE = NeuronBuilder(NEURON, '3d').get_figure()
    BBOX = bounding_box(NEURON)
Exemple #22
0
              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 nm.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 nm.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 nm.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))
Exemple #23
0
def test_bounding_box_soma():
    ref = np.array([[0., 0., 0.], [0.1, 0.2, 0.]])
    assert np.allclose(geom.bounding_box(NRN.soma), ref)
Exemple #24
0
def neuron(nrn, plane='xy', new_fig=True, subplot=False, **kwargs):
    '''
    Generates a 2d figure of the neuron, \
    that contains a soma and a list of trees.

    Parameters:
        neuron: Neuron \
        neurom.Neuron object
        plane: str \
            Accepted values: Any pair of of xyz \
            Default value is 'xy'.treecolor
        diameter: boolean
            If True the diameter, scaled with diameter_scale factor, \
            will define the width of the tree lines. \
            If False use linewidth to select the width of the tree lines. \
            Default value is True.
        diameter_scale: float \
            Defines the scale factor that will be multiplied \
            with the diameter to define the width of the tree line. \
            Default value is 1.
    '''
    if plane not in ('xy', 'yx', 'xz', 'zx', 'yz', 'zy'):
        return None, 'No such plane found! Please select one of: xy, xz, yx, yz, zx, zy.'

    # Initialization of matplotlib figure and axes.
    fig, ax = common.get_figure(new_fig=new_fig, subplot=subplot)

    kwargs['new_fig'] = False
    kwargs['subplot'] = subplot

    kwargs['final'] = False

    white_space = get_default('white_space', **kwargs)

    soma(nrn.soma, plane=plane, **kwargs)

    kwargs['title'] = kwargs.get('title', nrn.name)
    kwargs['xlabel'] = kwargs.get('xlabel', plane[0])
    kwargs['ylabel'] = kwargs.get('ylabel', plane[1])

    h = []
    v = []

    for temp_tree in nrn.neurites:

        bounding_box = geom.bounding_box(temp_tree)

        h.append([bounding_box[0][getattr(COLS, plane[0].capitalize())],
                  bounding_box[1][getattr(COLS, plane[0].capitalize())]])
        v.append([bounding_box[0][getattr(COLS, plane[1].capitalize())],
                  bounding_box[1][getattr(COLS, plane[1].capitalize())]])

        tree(temp_tree, plane=plane, **kwargs)

    if h:
        kwargs['xlim'] = kwargs.get('xlim', [np.min(h) - white_space,
                                             np.max(h) + white_space])
    if v:
        kwargs['ylim'] = kwargs.get('ylim', [np.min(v) - white_space,
                                             np.max(v) + white_space])

    return common.plot_style(fig=fig, ax=ax, **kwargs)
Exemple #25
0
def tree3d(tr, new_fig=True, new_axes=True, subplot=False, **kwargs):
    '''
    Generates a figure of the tree in 3d.
    If the tree contains one single point the plot will be empty \
    since no segments can be constructed.

    Parameters:
        tr: Tree \
        neurom.Tree object
        diameter: boolean \
            If True the diameter, scaled with diameter_scale factor, \
            will define the width of the tree lines. \
            If False use linewidth to select the width of the tree lines. \
            Default value is True.
        diameter_scale: float \
            Defines the scale factor that will be multiplied \
            with the diameter to define the width of the tree line. \
            Default value is 1.
        white_space: float \
            Defines the white space around \
            the boundary box of the morphology. \
            Default value is 1.
    '''
    from mpl_toolkits.mplot3d.art3d import Line3DCollection

    # Initialization of matplotlib figure and axes.
    fig, ax = common.get_figure(new_fig=new_fig, new_axes=new_axes,
                                subplot=subplot, params={'projection': '3d'})

    # Data needed for the viewer: x,y,z,r
    bounding_box = geom.bounding_box(tr)

    def _seg_3d(seg):
        '''2d coordinates needed for the plotting of a segment'''
        horz = getattr(COLS, 'X')
        vert = getattr(COLS, 'Y')
        depth = getattr(COLS, 'Z')
        parent_point = seg[0]
        child_point = seg[1]
        horz1 = parent_point[horz]
        horz2 = child_point[horz]
        vert1 = parent_point[vert]
        vert2 = child_point[vert]
        depth1 = parent_point[depth]
        depth2 = child_point[depth]
        return ((horz1, vert1, depth1), (horz2, vert2, depth2))

    segs = map_segments(tr, _seg_3d)

    linewidth = get_default('linewidth', **kwargs)

    # Definition of the linewidth according to diameter, if diameter is True.
    if get_default('diameter', **kwargs):
        # TODO: This was originally a numpy array. Did it have to be one?
        scale = get_default('diameter_scale', **kwargs)
        linewidth = [2 * r * scale for r in map_segments(tr, segment_radius)]
        if len(linewidth) == 0:
            linewidth = get_default('linewidth', **kwargs)

    # Plot the collection of lines.
    collection = Line3DCollection(segs,
                                  color=common.get_color(get_default('treecolor', **kwargs),
                                                         tr.type),
                                  linewidth=linewidth, alpha=get_default('alpha', **kwargs))

    ax.add_collection3d(collection)

    kwargs['title'] = kwargs.get('title', 'Tree 3d-view')
    kwargs['xlabel'] = kwargs.get('xlabel', 'X')
    kwargs['ylabel'] = kwargs.get('ylabel', 'Y')
    kwargs['zlabel'] = kwargs.get('zlabel', 'Z')

    kwargs['xlim'] = kwargs.get('xlim', [bounding_box[0][0] - get_default('white_space', **kwargs),
                                         bounding_box[1][0] + get_default('white_space', **kwargs)])
    kwargs['ylim'] = kwargs.get('ylim', [bounding_box[0][1] - get_default('white_space', **kwargs),
                                         bounding_box[1][1] + get_default('white_space', **kwargs)])
    kwargs['zlim'] = kwargs.get('zlim', [bounding_box[0][2] - get_default('white_space', **kwargs),
                                         bounding_box[1][2] + get_default('white_space', **kwargs)])

    return common.plot_style(fig=fig, ax=ax, **kwargs)
    for ttype in NEURITES:
        ttt = ttype
        seg_taper_rate = [mm.segment_taper_rate(s)
                          for s in nm.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 nm.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 nm.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 nm.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))