def _get_structure_mesh(self, acronym, **kwargs): """ Fetches the mesh for a brain region from the atlas. :param acronym: string, acronym of brain region :param **kwargs: """ if self.structures is None: print("No atlas was loaded, use self.get_brain first") return None if acronym not in self.region_acronyms and acronym != "root": raise ValueError( f"Acronym {acronym} not in available regions: {self.structures}" ) # Get obj file path if acronym != "root": mesh_format = self.mesh_format else: mesh_format = "vtk" obj_path = os.path.join(self.meshes_folder, "{}.{}".format(acronym, mesh_format)) # Load if self._check_obj_file(acronym, obj_path): mesh = load_mesh_from_file(obj_path, **kwargs) return mesh else: mesh = self.download_and_write_mesh(acronym, obj_path) return None
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_structure_mesh(self, acronym, **kwargs): """ Fetches the mesh for a brain region from the Allen Brain Atlas SDK. :param acronym: string, acronym of brain region :param **kwargs: """ structure = self.structure_tree.get_structures_by_acronym([acronym])[0] obj_path = os.path.join(self.mouse_meshes, "{}.obj".format(acronym)) if self._check_obj_file(structure, obj_path): mesh = load_mesh_from_file(obj_path, **kwargs) return mesh else: return None
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) self.actors['others'].append(actor) actors.append(actor) if len(actors) == 1: return actors[0] elif len(actors) > 1: return actors else: return None
def get_neurons(self, neurons, alpha=1, as_skeleton=False, colorby="type"): """ Renders neurons and adds returns to the scene. :param neurons: list of names of neurons :param alpha: float in range 0,1 - neurons transparency :param as_skeleton: bool (Default value = False), if True neurons are rendered as skeletons otherwise as a full mesh showing the whole morphology :param colorby: str, criteria to use to color the neurons. Accepts values like type, individual etc. """ neurons = self._check_neuron_argument(neurons) actors, store = [], {} for neuron in neurons: if neuron not in self.neurons_names: print(f"Neuron {neuron} not included in dataset") else: color = self.get_neuron_color(neuron, colorby=colorby) if as_skeleton: # reconstruct skeleton from json actor = self._parse_neuron_skeleton(neuron) else: # load as .obj file try: neuron_file = [ f for f in self.neurons_files if neuron in f ][0] except: print(f"Could not find .obj file for neuron {neuron}") continue actor = load_mesh_from_file(neuron_file) if actor is not None: # Refine actor's look actor.alpha(alpha).c(color) actors.append(actor) store[neuron] = (actor, as_skeleton) return actors, store
def add_neurons(self, neurons, alpha=1, as_skeleton=False, colorby='type'): """ THIS METHODS GETS CALLED BY SCENE, self referes to the instance of Scene not to this class. Renders neurons and adds them to the scene. :param neurons: list of names of neurons :param alpha: float in range 0,1 - neurons transparency :param as_skeleton: bool (Default value = False), if True neurons are rendered as skeletons otherwise as a full mesh showing the whole morphology :param colorby: str, criteria to use to color the neurons. Accepts values like type, individual etc. """ neurons = self.atlas._check_neuron_argument(neurons) for neuron in neurons: if neuron not in self.atlas.neurons_names: print(f"Neuron {neuron} not included in dataset") else: color = self.atlas.get_neuron_color(neuron, colorby=colorby) if as_skeleton: # reconstruct skeleton from json actor = self.atlas._parse_neuron_skeleton(neuron) else: # load as .obj file try: neuron_file = [f for f in self.atlas.neurons_files if neuron in f][0] except: print(f"Could not find .obj file for neuron {neuron}") continue actor = load_mesh_from_file(neuron_file) if actor is not None: # Refine actor's look actor.alpha(alpha).c(color) # Add to scene self.actors['neurons'].append(actor) self.store[neuron] = (actor, as_skeleton) # repurpusing the region's actors store for hosting neurons as dict
def get_brain_regions( self, brain_regions, add_labels=False, colors=None, use_original_color=True, alpha=None, hemisphere=None, verbose=False, **kwargs, ): """ Gets brain regions meshes for rendering Many parameters can be passed to specify how the regions should be rendered. To treat a subset of the rendered regions, specify which regions are VIP. Use the kwargs to specify more detailes on how the regins should be rendered (e.g. wireframe look) :param brain_regions: str list of acronyms of brain regions :param colors: str, color of rendered brian regions (Default value = None) :param use_original_color: bool, if True, the allen's default color for the region is used. (Default value = False) :param alpha: float, transparency of the rendered brain regions (Default value = None) :param hemisphere: str (Default value = None) :param add_labels: bool (default False). If true a label is added to each regions' actor. The label is visible when hovering the mouse over the actor :param **kwargs: used to determine a bunch of thigs, including the look and location of lables from scene.add_labels """ # Parse arguments if alpha is None: alpha = brainrender.DEFAULT_STRUCTURE_ALPHA # check that we have a list if not isinstance(brain_regions, list): brain_regions = [brain_regions] # check the colors input is correct if colors is not None: if isinstance(colors, (list, tuple)): if not len(colors) == len(brain_regions): raise ValueError( "when passing colors as a list, the number of colors must match the number of brain regions" ) for col in colors: if not check_colors(col): raise ValueError( "Invalide colors in input: {}".format(col)) else: if not check_colors(colors): raise ValueError( "Invalide colors in input: {}".format(colors)) colors = [colors for i in range(len(brain_regions))] # loop over all brain regions actors = {} for i, region in enumerate(brain_regions): if verbose: print("Rendering: ({})".format(region)) # get the structure and check if we need to download the object file if region not in self.lookup_df.acronym.values: print( f"The region {region} doesn't seem to belong to the atlas being used: {self.atlas_name}. Skipping" ) continue # Get path to .obj file obj_file = str(self.meshfile_from_structure(region)) # check which color to assign to the brain region if use_original_color: color = [ x / 255 for x in self._get_from_structure(region, "rgb_triplet") ] else: if colors is None: color = brainrender.DEFAULT_STRUCTURE_COLOR elif isinstance(colors, list): color = colors[i] else: color = colors # Load the object file as a mesh and store the actor if hemisphere is not None: if (hemisphere.lower() == "left" or hemisphere.lower() == "right"): obj = self.get_region_unilateral(region, hemisphere=hemisphere, color=color, alpha=alpha) else: raise ValueError( f"Invalid hemisphere argument: {hemisphere}") else: obj = load_mesh_from_file(obj_file, color=color, alpha=alpha) if obj is not None: actors_funcs.edit_actor(obj, **kwargs) actors[region] = obj else: print( f"Something went wrong while loading mesh data for {region}, skipping." ) return actors
def _get_structure_mesh(self, acronym, **kwargs): obj_path = self._get_from_structure(acronym, "mesh_filename") return load_mesh_from_file(obj_path, **kwargs)
def get_neurons_synapses( self, scene_store, neurons, alpha=1, pre=False, post=False, colorby="synapse_type", draw_patches=False, draw_arrows=True, ): """ THIS METHODS GETS CALLED BY SCENE, self referes to the instance of Scene not to this class. Renders neurons and adds them to the scene. :param neurons: list of names of neurons :param alpha: float in range 0,1 - neurons transparency :param pre: bool, if True the presynaptic sites of each neuron are rendered :param post: bool, if True the postsynaptic sites on each neuron are rendered :param colorby: str, criteria to use to color the neurons. Accepts values like synapse_type, type, individual etc. :param draw_patches: bool, default True. If true dark patches are used to show the location of post synapses :param draw_arrows: bool, default True. If true arrows are used to show the location of post synapses """ col_names = ["x", "z", "y"] # used to correctly position synapses on .obj files neurons = self._check_neuron_argument(neurons) spheres_data, actors = [], [] for neuron in neurons: if pre: if colorby == "synapse_type": color = self.pre_synapses_color else: color = self.get_neuron_color(neuron, colorby=colorby) data = self.synapses_data.loc[self.synapses_data.pre == neuron] if not len(data): print(f"No pre- synapses found for neuron {neuron}") else: data = data[["x", "y", "z"]] data["y"] = -data["y"] spheres_data.append(( data, dict( color=color, verbose=False, alpha=alpha, radius=self.synapses_radius, res=24, col_names=col_names, ), )) if post: if colorby == "synapse_type": color = self.post_synapses_color else: color = self.get_neuron_color(neuron, colorby=colorby) rows = [ i for i, row in self.synapses_data.iterrows() if neuron in row.posts ] data = self.synapses_data.iloc[rows] if not len(data): print(f"No post- synapses found for neuron {neuron}") else: data = data[["x", "y", "z"]] data["y"] = -data["y"] """ Post synaptic locations are shown as darkening of patches of a neuron's mesh and or as a 3d arrow point toward the neuron. """ spheres_data.append(( data, dict( color="black", verbose=False, alpha=0, radius=self.synapses_radius * 4, res=24, col_names=col_names, ), )) # Get mesh points for neuron the synapses belong to if neuron not in scene_store.keys(): neuron_file = [ f for f in self.neurons_files if neuron in f ][0] neuron_act = load_mesh_from_file(neuron_file, c=color) else: neuron_act, as_skeleton = scene_store[neuron] # Draw post synapses as dark patches if draw_patches: if as_skeleton: print( "Can't display post synapses as dark spots when neron is rendered in skeleton mode" ) else: # Get faces that are inside the synapses spheres and color them darker raise NotImplementedError("This needs some fixing") # neuron_points = neuron_act.cellCenters() # inside_points = spheres.insidePoints( # neuron_points, returnIds=True # ) # n_cells = neuron_act.polydata().GetNumberOfCells() # scals = np.zeros((n_cells)) # scals[inside_points] = 1 # colors = [ # neuron_act.c() # if s == 0 # else getColor("blackboard") # for s in scals # ] # neuron_act.cellIndividualColors(colors) # Draw post synapses as arrow if draw_arrows: points1 = [[x, y, z] for x, y, z in zip( data[col_names[0]].values, data[col_names[1]].values, data[col_names[2]].values, )] points2 = [neuron_act.closestPoint(p) for p in points1] # shift point1 to make arrows longer def dist(p1, p2): return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2 + (p1[2] - p2[2])**2) def get_point(p1, p2, d, u): alpha = (1 / d) * u x = (1 - alpha) * p1[0] + alpha * p2[0] y = (1 - alpha) * p1[1] + alpha * p2[1] z = (1 - alpha) * p1[2] + alpha * p2[2] return [x, y, z] dists = [ dist(p1, p2) for p1, p2 in zip(points1, points2) ] points0 = [ get_point(p1, p2, d, -0.5) for p1, p2, d in zip(points1, points2, dists) ] arrows = Arrows(points0, endPoints=points2, c=color, s=4) # ! aasduaisdbasiudbuia actors.append(arrows) return spheres_data, actors