From de28d6e7802518760155d7b70fbc8d40bc36115d Mon Sep 17 00:00:00 2001 From: Philipp Schlegel Date: Fri, 16 Oct 2020 10:32:03 +0100 Subject: [PATCH] in_volume: allow using any mesh-like objects --- navis/intersection/intersect.py | 16 +++++++++++----- navis/utils/__init__.py | 2 +- navis/utils/misc.py | 24 ++++++++++++++++++++---- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/navis/intersection/intersect.py b/navis/intersection/intersect.py index e484cbcf..e5500e12 100644 --- a/navis/intersection/intersect.py +++ b/navis/intersection/intersect.py @@ -161,9 +161,9 @@ def in_volume(x: Union['core.NeuronObject', Sequence, pd.DataFrame], - ``pandas.DataFrame`` needs to have ``x, y, z`` columns - volume : navis.Volume | dict or list of navis.Volume - :class:`navis.Volume` to test. Multiple volumes can - be given as list (``[volume1, volume2, ...]``) or dict + volume : navis.Volume | navis.MeshNeuron | any mesh-like object + Multiple volumes can be given as list + (``[volume1, volume2, ...]``) or dict (``{'label1': volume1, ...}``). mode : 'IN' | 'OUT', optional If 'IN', parts of the neuron that are within the volume @@ -242,14 +242,17 @@ def in_volume(x: Union['core.NeuronObject', Sequence, pd.DataFrame], # Force into dict if not isinstance(volume, dict): # Make sure all Volumes can be uniquely indexed - vnames = [v.name for v in volume if isinstance(v, core.Volume)] + vnames = [getattr(v, 'name', i) for i, v in enumerate(volume)] dupli = [v for v in set(vnames) if vnames.count(v) > 1] if dupli: raise ValueError('Duplicate Volume names detected: ' f'{",".join(dupli)}. Volume.name must be ' 'unique.') - volume = {v.name: v for v in volume if isinstance(v, core.Volume)} + volume = {getattr(v, 'name', i): v for i, v in enumerate(volume)} + + # Make sure everything is a volume + volume = {k: utils.make_volume(v) for k, v in enumerate(volume)} # Validate now - this might safe us troubles later if validate: @@ -278,6 +281,9 @@ def in_volume(x: Union['core.NeuronObject', Sequence, pd.DataFrame], backend=backend) return data + # Coerce volume into navis.Volume + volume = utils.make_volume(volume) + if not isinstance(volume, core.Volume): raise TypeError(f'Expected navis.Volume, got "{type(volume)}"') diff --git a/navis/utils/__init__.py b/navis/utils/__init__.py index 551db6fb..423883cc 100644 --- a/navis/utils/__init__.py +++ b/navis/utils/__init__.py @@ -1,7 +1,7 @@ from .iterables import make_iterable, make_non_iterable, is_iterable from .misc import (is_jupyter, set_loggers, set_pbars, unpack_neurons, set_default_connector_colors, parse_objects, - is_url, make_url, lock_neuron) + is_url, make_url, lock_neuron, make_volume) from .validate import validate_options, validate_table from .eval import (eval_node_ids, eval_neurons, eval_id, eval_conditions, is_mesh) diff --git a/navis/utils/misc.py b/navis/utils/misc.py index 2325eb34..c3a764fa 100644 --- a/navis/utils/misc.py +++ b/navis/utils/misc.py @@ -11,13 +11,15 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -import pandas as pd -import numpy as np import requests import urllib +import numpy as np +import pandas as pd +import trimesh as tm + from functools import wraps -from typing import Optional, Union, List, Iterable, Dict, Tuple +from typing import Optional, Union, List, Iterable, Dict, Tuple, Any from .. import config, core from .eval import is_mesh @@ -26,6 +28,20 @@ logger = config.logger +def make_volume(x: Any) -> 'core.Volume': + """Try making a navis.Volume from input object.""" + if isinstance(x, core.Volume): + return x + if is_mesh(x): + inits = dict(vertices=x.vertices, faces=x.faces) + for p in ['name', 'id', 'color']: + if hasattr(x, p): + inits[p] = getattr(x, p, None) + return core.Volume(**inits) + + raise TypeError(f'Unable to coerce input of type "{type(x)}" to navis.Volume') + + def lock_neuron(function): """Lock neuron while function is executed. @@ -237,7 +253,7 @@ def parse_objects(x) -> Tuple['core.NeuronList', ------- Neurons : navis.NeuronList Dotprops : pd.DataFrame - Volume : list of navis.Volume + Volume : list of navis.Volume (trimesh.Trimesh will be converted) Points : list of arrays Visuals : list of vispy visuals