Skip to content

Commit

Permalink
v 0.47
Browse files Browse the repository at this point in the history
- plot.plot3d:
  - made vispy canvas persistent
  - added new functions: clear3d() and close3d()
- morpho: new function prune_by_strahler()
- core:
  - new neuron attribute: n_open_ends
  - new functions: prune_distal_to(), prune_proximal_to() and prune_by_strahler()
  - made summary() function public
  - renamed update() to reload()
  - added tqdm to more for loops
- rmaid:
  - made nblast() and nblast_allbyall() more consistent with R version
- bugfixes in morpho, b3d, core
- updated docs
  • Loading branch information
schlegelp committed Jul 31, 2017
1 parent c332b0d commit 9789885
Show file tree
Hide file tree
Showing 13 changed files with 517 additions and 139 deletions.
Binary file added dist/pymaid-0.47.tar.gz
Binary file not shown.
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@
# built documents.
#
# The short X.Y version.
version = '0.46'
version = '0.47'
# The full version, including alpha/beta/rc tags.
release = '0.46'
release = '0.47'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ PyMaid documentation
source/overview
source/rmaid_doc
source/plotting
source/morpho_doc
source/blender
source/pymaid
source/core
Expand Down
2 changes: 1 addition & 1 deletion docs/source/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Quick install
-------------

PyMaid is *not yet* listed in the Python Packaging Index but you can install
the current version from github using
the current version from `Github <https://github.com/schlegelp/PyMaid>`_ using:

::

Expand Down
48 changes: 48 additions & 0 deletions docs/source/morpho_doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Morphological Analyses
**********************

This section should give you an impression of how to access and compute morphological properties of neurons.

Basic properties
================

Many basic parameters are readily accessible through attributes of :class:`pymaid.core.CatmaidNeuron` or :class:`pymaid.core.CatmaidNeuronList`

>>> from pymaid import pymaid
>>> rm = pymaid.CatmaidInstance('server_url','user','pw','token')
>>> pymaid.remote_instance = rm
>>> nl = pymaid.get_3D_skeletons('annotation:glomerulus DA1')
>>> # Access single attribute: e.g. cable lengths [um]
>>> nl.cable_length
>>> # .. or get a full summary as pandas DataFrame
>>> df = nl.summary()
>>> df.n_connectors.tolist()
[437, 394, 326, 307, 356, 483, 316, 960, 438, 408, 553, 335, 380, 316, 620]

Cutting, pruning, pasting
=========================

The :mod:`pymaid.morpho` module let's you perform (virtual) surgery on neurons. :class:`pymaid.core.CatmaidNeuron` and :class:`pymaid.core.CatmaidNeuronList` have also some thin wrappers for :mod:`pymaid.morpho` functions (e.g. :func:`pymaid.core.CatmaidNeuron.prune_by_strahler` is a wrapper for :func:`pymaid.morpho.prune_by_strahler`).

Some examples continuing with above neuronlist ``nl``:

>>> from pymaid import morpho, core, plot
>>> # Cut a neuron in two using either a treenode ID or (in this case) a node tag
>>> distal, proximal = morpho.cut_neuron( nl[0], cut_node='SCHLEGEL_LH' )
>>> # Plot neuron fragments
>>> core.CatmaidNeuronList( [ distal, proximal ] ).plot3d()
>>> # Alternatively, we can also just prune bits off a neuron objects
>>> nl[0].prune_distal_to('SCHLEGEL_LH')
>>> nl[0].plot3d()
>>> # To undo, simply reload the neuron from server
>>> nl[0].reload()
>>> # These operations can also be performed on a collection of neurons
>>> nl.prune_distal_to('SCHLEGEL_LH')
>>> nl.plot3d(clear3d=True)
>>> # Again, let's undo
>>> nl.reload()
>>> # Something more sophisticated: pruning by strahler index
>>> nl.prune_by_strahler( to_prune = [1,2,3] )
>>> nl.plot3d(connectors=True,clear3d=True)

For morphological comparisons using NBLAST, see * :ref:`_rmaid_link`.
7 changes: 6 additions & 1 deletion docs/source/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Primary attributes:
- ``annotations``: list of neuron(s) annotations
- ``cable_length``: cable length(s) in nm
- ``review_status``: review status of neuron(s)
- ``soma``: returns treenode ID of soma (if applicable)
- ``slabs``: returns slabs (linear segments)
- ``igraph``: iGraph representation of the neuron

:class:`pymaid.core.CatmaidNeuronList`

Expand Down Expand Up @@ -97,6 +100,7 @@ Use e.g. ``help(get_edges)`` to learn more about their function, parameters and
- :func:`pymaid.morpho.downsample_neuron`: takes skeleton data and reduces the number of nodes while preserving synapses, branch points, etc.
- :func:`pymaid.morpho.in_volume`: test if points are within given CATMAID volume
- :func:`pymaid.morpho.longest_neurite`: prunes neuron to its longest neurite
- :func:`pymaid.morpho.prune_by_strahler`: prunes the neuron by strahler index
- :func:`pymaid.morpho.reroot_neuron`: reroot neuron to a specific node
- :func:`pymaid.morpho.synapse_root_distances`: similar to :func:`pymaid.igraph_catmaid.dist_from_root` but does not use iGraph

Expand All @@ -105,7 +109,8 @@ Use e.g. ``help(get_edges)`` to learn more about their function, parameters and

- :func:`pymaid.rmaid.init_rcatmaid`: initialize connection with Catmaid server in R
- :func:`pymaid.rmaid.data2py`: wrapper to convert R data to Python
- :func:`pymaid.rmaid.nblast`: wrapper to use Nat's NBLAST on Pymaid neurons
- :func:`pymaid.rmaid.nblast`: wrapper to nblast a set neurons against external database
- :func:`pymaid.rmaid.nblast_allby_all`: wrapper to nblast a set of neurons against each other
- :func:`pymaid.rmaid.neuron2py`: converts R neuron and neuronlist objects to Pymaid neurons
- :func:`pymaid.rmaid.neuron2r`: converts Pymaid neuron and list of neurons to R neuron and neuronlist objects, respectively

Expand Down
22 changes: 17 additions & 5 deletions docs/source/plotting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Neuron classes ( :class:`pymaid.core.CatmaidNeuron` and :class:`pymaid.core.Catm
... 'HTTP_PASSWORD',
... 'TOKEN' )
>>> nl = core.CatmaidNeuronList([123456, 567890], remote_instance = rm)
>>> #Plot using standard parameters
>>> # Plot using standard parameters
>>> fig, ax = nl.plot2d()
2017-07-25 14:56:08,701 - pymaid.plot - INFO - Done. Use matplotlib.pyplot.show() to show plot.
>>> plt.show()
Expand All @@ -35,15 +35,27 @@ Adding volumes:
3D Plotting:
------------

>>> from pymaid import core, pymaid
>>> from pymaid import core, pymaid, plot
>>> rm = pymaid.CatmaidInstance( 'www.your.catmaid-server.org',
... 'HTTP_USER' ,
... 'HTTP_PASSWORD',
... 'TOKEN' )
>>> nl = core.CatmaidNeuronList([123456, 567890], remote_instance = rm)
>>> #Plot using standard parameters
>>> # Plot using standard parameters
>>> nl.plot3d()

The canvas persistent and survives simply closing the window. Calling :func:`pymaid.plot.plot3d` again will add objects to the canvas and open it again.

>>> # Add another set of neurons
>>> nl2 = core.CatmaidNeuronList([987675,543210], remote_instance = rm)
>>> nl2.plot3d()
>>> # To clear canvas either pass parameter when plotting
>>> nl2.plot3d(clear3d=True)
>>> # ... or call explicitly
>>> plot.clear3d()
>>> # To wipe canvas from memory
>>> plot.close3d()

By default, calling :func:`pymaid.plot.plot3d` uses the vispy backend and does not plot connectors. By passing **kwargs, we can change that behavior:
>>> fig = nl.plot3d( backend = 'plotly', connectors = True )
Expand Down Expand Up @@ -72,9 +84,9 @@ Adding volumes:
... 'HTTP_PASSWORD',
... 'TOKEN' )
>>> nl = core.CatmaidNeuronList([123456, 567890], remote_instance = rm)
>>> #Plot volumes without specifying color
>>> # Plot volumes without specifying color
>>> nl.plot3d( volumes = ['v13.LH_R', 'v13_LH_L'] )
>>> #Provide colors
>>> # Provide colors
>>> nl.plot3d( volumes = {'v13.LH_R':(255,0,0), 'v13_LH_L':(0,255,0)} )

You can also pass your own custom volumes as dictionarys:
Expand Down
2 changes: 1 addition & 1 deletion pymaid/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.46"
__version__ = "0.47"
30 changes: 19 additions & 11 deletions pymaid/b3d.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class handler:
neurons : returns list containing all neurons
connectors : returns list containing all connectors
soma : returns list containing all somata
selected : returns list containing selected objects
selected : returns list containing selected Catmaid objects
presynapses : returns list containing all presynapses
postsynapses : returns list containing all postsynapses
gapjunctions : returns list containing all gap junctions
Expand All @@ -104,9 +104,7 @@ class handler:
>>> handler.clear()
>>> # Add only soma
>>> handler.add( nl, neurites=False, connectors=False )
"""

# Default colors of connectors are defined here
"""
cn_dict = {
0: dict(name='presynapses',
color=(1, 0, 0)),
Expand All @@ -116,7 +114,7 @@ class handler:
color=(0, 1, 0)),
3: dict(name='abutting',
color=(1, 0, 1))
}
} #: defines default colours/names for different connector types

def __init__(self, conversion=1 / 10000):
self.conversion = conversion
Expand All @@ -133,7 +131,7 @@ def __getattr__(self, key):
elif key == 'soma' or key == 'somas':
return object_list([ob.name for ob in bpy.data.objects if ob['type'] == 'SOMA'])
elif key == 'selected':
return object_list([ob.name for ob in bpy.context.selected_objects])
return object_list([ob.name for ob in bpy.context.selected_objects if 'catmaid_object' in ob])
elif key == 'presynapses':
return object_list([ob.name for ob in bpy.data.objects if ob['type'] == 'CONNECTORS' and ob['cn_type'] == 0])
elif key == 'postsynapses':
Expand Down Expand Up @@ -205,6 +203,7 @@ def _create_neurites(self, x, mat):
ob.location = (0, 0, 0)
ob.show_name = True
ob['type'] = 'NEURON'
ob['catmaid_object'] = True
ob['skeleton_id'] = x.skeleton_id
cu.dimensions = '3D'
cu.fill_mode = 'FULL'
Expand All @@ -218,12 +217,16 @@ def _create_neurites(self, x, mat):
coords *= self.conversion
coords = coords.tolist()

ids = x.nodes.treenode_id.tolist()

# Add points
newSpline.points.add(len(coords) - 1)

# Move points
for i, p in enumerate(coords):
newSpline.points[i].co = (p[0], p[2], -p[1], 0)
#Hijack weight property to store treenode ID
newSpline.points[i].weight = int(ids[i])

ob.active_material = mat

Expand All @@ -242,6 +245,7 @@ def _create_soma(self, x, mat):
bpy.ops.object.shade_smooth()
bpy.context.active_object.name = 'Soma of ' + x.neuron_name
bpy.context.active_object['type'] = 'SOMA'
bpy.context.active_object['catmaid_object'] = True
bpy.context.active_object['skeleton_id'] = x.skeleton_id

bpy.context.scene.objects.active.active_material = mat
Expand All @@ -268,6 +272,7 @@ def _create_connectors(self, x):
cu = bpy.data.curves.new(ob_name + ' mesh', 'CURVE')
ob = bpy.data.objects.new(ob_name, cu)
ob['type'] = 'CONNECTORS'
ob['catmaid_object'] = True
ob['cn_type'] = i
ob['skeleton_id'] = x.skeleton_id
bpy.context.scene.objects.link(ob)
Expand Down Expand Up @@ -397,7 +402,7 @@ class object_list:
Notes
-----
1. Object_lists should normally be constructed via the handler
(see :class:`pymaid.b3d.handler`)!
2. List works with object NAMES to prevent Blender from crashing when
Expand All @@ -414,7 +419,8 @@ class object_list:
presynapses : returns list containing all presynapses
postsynapses : returns list containing all postsynapses
gapjunctions : returns list containing all gap junctions
abutting : returns list containing all abutting connectors
abutting : returns list containing all abutting connectors
skeleton_id : returns list of skeleton IDs
Examples
--------
Expand All @@ -439,11 +445,11 @@ def __init__(self, object_names, handler=None):
self.handler = handler

def __getattr__(self, key):
if key == 'neurons' or key == 'neuron' or key == 'neurites':
if key in ['neurons','neuron','neurites']:
return object_list([n for n in self.object_names if n in bpy.data.objects and bpy.data.objects[n]['type'] == 'NEURON'])
elif key == 'connectors' or key == 'connector':
elif key in ['connectors', 'connector']:
return object_list([n for n in self.object_names if n in bpy.data.objects and bpy.data.objects[n]['type'] == 'CONNECTORS'])
elif key == 'soma' or key == 'somas':
elif key in ['soma','somas']:
return object_list([n for n in self.object_names if n in bpy.data.objects and bpy.data.objects[n]['type'] == 'SOMA'])
elif key == 'presynapses':
return object_list([n for n in self.object_names if n in bpy.data.objects and bpy.data.objects[n]['type'] == 'CONNECTORS' and bpy.data.objects[n]['cn_type'] == 0])
Expand All @@ -453,6 +459,8 @@ def __getattr__(self, key):
return object_list([n for n in self.object_names if n in bpy.data.objects and bpy.data.objects[n]['type'] == 'CONNECTORS' and bpy.data.objects[n]['cn_type'] == 2])
elif key == 'abutting':
return object_list([n for n in self.object_names if n in bpy.data.objects and bpy.data.objects[n]['type'] == 'CONNECTORS' and bpy.data.objects[n]['cn_type'] == 3])
elif key in ['skeleton_id','skeleton_ids','skeletonid','skeletonids','skid','skids']:
return [ bpy.data.objects[n]['skeleton_id'] for n in self.object_names if n in bpy.data.objects ]
else:
raise AttributeError('Unknown attribute ' + key)

Expand Down
Loading

0 comments on commit 9789885

Please sign in to comment.