def add_plane(self, plane, **kwargs): """ Adds one or more planes to the scene. For more details on how to build custom planes, check: brainrender/atlases/base.py -> Base.get_plane_at_point method. :param plane: either a string with the name of one of the predifined planes ['sagittal', 'coronal', 'horizontal'] or an instance of the Plane class from vedo.shapes """ if isinstance(plane, (list, tuple)): planes = plane.copy() else: planes = [plane] actors = [] for plane in planes: if isinstance(plane, str): plane = self.atlas.get_plane_at_point(plane=plane, **kwargs) else: if not isinstance(plane, Plane): raise ValueError( "The plane arguments should either be a Plane actor or" + "a string with the name of predefined planes." + f" Not: {plane.__type__}") plane.name = "plane" plane._br_class = "plane" actors.append(plane) self.add_actor(*actors) return return_list_smart(actors)
def add_actor(self, *actors, name=None, br_class=None, store=None): """ Add a vtk actor to the scene :param actor: :param store: a list to store added actors """ # Parse inputs to match a name and br class to each actor actors, names, br_classes = parse_add_actors_inputs( actors, name, br_class) # Add actors to scene to_return = [] for actor, name, br_class in zip(actors, names, br_classes): for act in listify(actor): if act is None: continue try: act = Actor(act, name=name, br_class=br_class) except Exception: # doesn't work for annotations act.name = name act.br_class = br_class act._is_transformed = False if store is None: self.actors.append(act) else: store.append(act) to_return.append(act) return return_list_smart(to_return)
def add_brain_regions(self, *args, **kwargs): """ Adds brain regions meshes to scene. Check the atlas' method to know how it works """ add_labels = kwargs.pop("add_labels", False) allactors = self.atlas.get_brain_regions(*args, verbose=self.verbose, **kwargs) actors = [] for region, actor in allactors.items(): if region in [a.name for a in self.actors if isinstance(a, Mesh)]: # Avoid inserting again continue if add_labels: self.add_actor_label(actor, region, **kwargs) actor.name = region actor._br_class = "brain region" actors.append(actor) self.actors.extend(actors) return return_list_smart(actors)
def add_streamlines(self, *args, **kwargs): """ Render streamline data. Check the function definition in ABA for more details """ actors = self.atlas.get_streamlines(*args, **kwargs) for act in actors: self.add_actor(actors, name="streamlines", br_class="streamlines") return return_list_smart(actors)
def add_tractography(self, *args, **kwargs): """ Renders tractography data and adds it to the scene. Check the function definition in ABA for more details """ actors = self.atlas.get_tractography(*args, **kwargs) for act in actors: self.add_actor(actors, name="tractography", br_class="tractography") return return_list_smart(actors)
def add_actor(self, *actors, store=None): """ Add a vtk actor to the scene :param actor: :param store: a list to store added actors """ for actor in actors: if store is None: self.actors.append(actor) else: store.append(actor) return return_list_smart(actors)
def add_from_file(self, *filepaths, **kwargs): """ Add data to the scene by loading them from a file. Should handle .obj, .vtk and .nii files. :param filepaths: path to the file. Can pass as many arguments as needed :param **kwargs: """ actors = [] for filepath in filepaths: actor = load_mesh_from_file(filepath, **kwargs) name = Path(filepath).name act = self.add_actor(actor, name=name, br_class=name) actors.append(act) return return_list_smart(actors)
def get_colors_from_coordinates(self, p0): """ Given a point or a list of points returns a list of colors where each item is the color of the brain region each point is in """ if isinstance(p0[0], (float, int)): p0 = [p0] resolution = int(self.metadata["resolution"][0]) colors = [] for point in p0: point = np.round(np.array(point) / resolution).astype(int) try: struct = self.structure_from_coords(point, as_acronym=True) except KeyError: # couldn't find any region struct = "root" colors.append(self._get_from_structure(struct, "rgb_triplet")) return return_list_smart(colors)
def add_actor_label(self, actors, labels, **kwargs): """ Adds a 2D text ancored to a point on the actor's mesh to label what the actor is :param kwargs: key word arguments can be passed to determine text appearance and location: - size: int, text size. Default 300 - color: str, text color. A list of colors can be passed if None the actor's color is used. Default None. - xoffset, yoffset, zoffset: integers that shift the label position - radius: radius of sphere used to denote label anchor. Set to 0 or None to hide. """ labels = make_actor_label(self.atlas, actors, labels, **kwargs) # Add to scene and return self.add_actor(*labels, store=self.actors_labels) return return_list_smart(labels)
def add_plane(self, plane, **kwargs): """ Adds one or more planes to the scene. For more details on how to build custom planes, check: brainrender/atlases/base.py -> Base.get_plane_at_point method. :param plane: either a string with the name of one of the predifined planes ['sagittal', 'coronal', 'horizontal'] or an instance of the Plane class from vedo.shapes """ if self.transform_applied: rprint( f"[b {salmon}]Warning: [/b {salmon}][{mocassin}]you're attempting to add a plane " + "after having rendered the scene at lest once, this might give unpredicable results." + "\nIt's advised to perform add all planes before the first call to `render`" ) planes = listify(plane).copy() actors = [] for plane in planes: if isinstance(plane, str): plane = self.atlas.get_plane_at_point(plane=plane, **kwargs) else: if not isinstance(plane, Plane): raise ValueError( "The plane arguments should either be a Plane actor or" + "a string with the name of predefined planes." + f" Not: {plane.__type__}") actors.append(plane) self.add_actor(*actors, name="plane", br_class="plane") return return_list_smart(actors)
def get_neurons( self, neurons, color=None, display_axon=True, display_dendrites=True, alpha=1, neurite_radius=None, soma_radius=None, use_cache=True, ): """ Gets rendered morphological data of neurons reconstructions Accepts neurons argument as: - file(s) with morphological data - vedo mesh actor(s) of entire neurons reconstructions - dictionary or list of dictionary with actors for different neuron parts :param neurons: str, list, dict. File(s) with neurons data or list of rendered neurons. :param display_axon, display_dendrites: if set to False the corresponding neurite is not rendered :param color: default None. Can be: - None: each neuron is given a random color - color: rbg, hex etc. If a single color is passed all neurons will have that color - cmap: str with name of a colormap: neurons are colored based on their sequential order and cmap - dict: a dictionary specifying a color for soma, dendrites and axon actors, will be the same for all neurons - list: a list of length = number of neurons with either a single color for each neuron or a dictionary of colors for each neuron :param alpha: float in range 0,1. Neurons transparency :param neurite_radius: float > 0 , radius of tube actor representing neurites :param use_cache: bool, if True a cache is used to avoid having to crate a neuron's mesh anew, otherwise a new mesh is created """ if not isinstance(neurons, (list, tuple)): neurons = [neurons] # ---------------------------------- Render ---------------------------------- # _neurons_actors = [] for neuron in neurons: neuron_actors = {"soma": None, "dendrites": None, "axon": None} # Deal with neuron as filepath if isinstance(neuron, str): if os.path.isfile(neuron): if neuron.endswith(".swc"): neuron_actors, _ = get_neuron_actors_with_morphapi( swcfile=neuron, neurite_radius=neurite_radius, soma_radius=soma_radius, use_cache=use_cache, ) else: raise NotImplementedError( "Currently we can only parse morphological reconstructions from swc files" ) else: raise ValueError( f"Passed neruon {neuron} is not a valid input. Maybe the file doesn't exist?" ) # Deal with neuron as single actor elif isinstance(neuron, Mesh): # A single actor was passed, maybe it's the entire neuron neuron_actors["soma"] = neuron # store it as soma pass # Deal with neuron as dictionary of actor elif isinstance(neuron, dict): neuron_actors["soma"] = neuron.pop("soma", None) neuron_actors["axon"] = neuron.pop("axon", None) # Get dendrites actors if ( "apical_dendrites" in neuron.keys() or "basal_dendrites" in neuron.keys() ): if "apical_dendrites" not in neuron.keys(): neuron_actors["dendrites"] = neuron["basal_dendrites"] elif "basal_dendrites" not in neuron.keys(): neuron_actors["dendrites"] = neuron["apical_dendrites"] else: neuron_actors["dendrites"] = merge( neuron["apical_dendrites"], neuron["basal_dendrites"], ) else: neuron_actors["dendrites"] = neuron.pop("dendrites", None) # Deal with neuron as instance of Neuron from morphapi elif isinstance(neuron, Neuron): neuron_actors, _ = get_neuron_actors_with_morphapi( neuron=neuron, neurite_radius=neurite_radius, use_cache=use_cache, ) # Deal with other inputs else: raise ValueError( f"Passed neuron {neuron} is not a valid input" ) # Check that we don't have anything weird in neuron_actors for key, act in neuron_actors.items(): if act is not None: if not isinstance(act, Mesh): raise ValueError( f"Neuron actor {key} is {type(act)} but should be a vedo Mesh. Not: {act}" ) if not display_axon: neuron_actors["axon"] = None if not display_dendrites: neuron_actors["dendrites"] = None _neurons_actors.append(neuron_actors) # Color actors colors = parse_neurons_colors(neurons, color) for n, neuron in enumerate(_neurons_actors): if neuron["axon"] is not None: neuron["axon"].c(colors["axon"][n]) neuron["axon"].name = "neuron-axon" if neuron["soma"] is not None: neuron["soma"].c(colors["soma"][n]) neuron["soma"].name = "neuron-soma" if neuron["dendrites"] is not None: neuron["dendrites"].c(colors["dendrites"][n]) neuron["dendrites"].name = "neuron-dendrites" # Return return return_list_smart(_neurons_actors), None
def add_neurons( self, neurons, color=None, display_axon=True, display_dendrites=True, alpha=1, neurite_radius=None, ): """ Adds rendered morphological data of neurons reconstructions downloaded from the Mouse Light project at Janelia, neuromorpho.org and other sources. Accepts neurons argument as: - file(s) with morphological data - vedo mesh actor(s) of neurons reconstructions - dictionary or list of dictionary with actors for different neuron parts :param self: instance of brainrender Scene to use to render neurons :param neurons: str, list, dict. File(s) with neurons data or list of rendered neurons. :param display_axon, display_dendrites: if set to False the corresponding neurite is not rendered :param color: default None. Can be: - None: each neuron is colored according to the default color - color: rbg, hex etc. If a single color is passed all neurons will have that color - cmap: str with name of a colormap: neurons are colored based on their sequential order and cmap - dict: a dictionary specifying a color for soma, dendrites and axon actors, will be the same for all neurons - list: a list of length = number of neurons with either a single color for each neuron or a dictionary of colors for each neuron :param alpha: float in range 0,1. Neurons transparency :param neurite_radius: float > 0 , radius of tube actor representing neurites """ if not isinstance(neurons, (list, tuple)): neurons = [neurons] # ------------------------------ Prepare colors ------------------------------ # colors = self._add_neurons_get_colors(neurons, color) # ---------------------------------- Render ---------------------------------- # _neurons_actors = [] for neuron in neurons: neuron_actors = {"soma": None, "dendrites": None, "axon": None} # Deal with neuron as filepath if isinstance(neuron, str): if os.path.isfile(neuron): if neuron.endswith(".swc"): neuron_actors, _ = get_neuron_actors_with_morphapi( swcfile=neuron, neurite_radius=neurite_radius) else: raise NotImplementedError( "Currently we can only parse morphological reconstructions from swc files" ) else: raise ValueError( f"Passed neruon {neuron} is not a valid input. Maybe the file doesn't exist?" ) # Deal with neuron as single actor elif isinstance(neuron, Actor): # A single actor was passed, maybe it's the entire neuron neuron_actors["soma"] = neuron # store it as soma anyway pass # Deal with neuron as dictionary of actor elif isinstance(neuron, dict): neuron_actors["soma"] = neuron.pop("soma", None) neuron_actors["axon"] = neuron.pop("axon", None) # Get dendrites actors if ("apical_dendrites" in neuron.keys() or "basal_dendrites" in neuron.keys()): if "apical_dendrites" not in neuron.keys(): neuron_actors["dendrites"] = neuron["basal_dendrites"] elif "basal_dendrites" not in neuron.keys(): neuron_actors["dendrites"] = neuron["apical_dendrites"] else: neuron_actors["dendrites"] = merge( neuron["apical_dendrites"], neuron["basal_dendrites"], ) else: neuron_actors["dendrites"] = neuron.pop("dendrites", None) # Deal with neuron as instance of Neuron from morphapi elif isinstance(neuron, Neuron): neuron_actors, _ = get_neuron_actors_with_morphapi( neuron=neuron) # Deal with other inputs else: raise ValueError( f"Passed neuron {neuron} is not a valid input") # Check that we don't have anything weird in neuron_actors for key, act in neuron_actors.items(): if act is not None: if not isinstance(act, Actor): raise ValueError( f"Neuron actor {key} is {act.__type__} but should be a vedo Mesh. Not: {act}" ) if not display_axon: neuron_actors["axon"] = None if not display_dendrites: neuron_actors["dendrites"] = None _neurons_actors.append(neuron_actors) # Color actors for n, neuron in enumerate(_neurons_actors): if neuron["axon"] is not None: neuron["axon"].c(colors["axon"][n]) neuron["soma"].c(colors["soma"][n]) if neuron["dendrites"] is not None: neuron["dendrites"].c(colors["dendrites"][n]) # Add to actors storage self.actors.extend([list(n.values()) for n in _neurons_actors]) return return_list_smart(_neurons_actors)