Beispiel #1
0
    def _add_neurons_get_colors(self, neurons, color):
        """     
            Parses color argument for self.add_neurons
            
            :para, neurons: list of Neuron object or file paths...
            :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
        """
        N = len(neurons)
        colors = dict(
            soma=None,
            axon=None,
            dendrites=None,
        )

        # If no color is passed, get random colors
        if color is None:
            cols = [self.default_neuron_color for n in np.arange(N)]
            colors = dict(
                soma=cols.copy(),
                axon=cols.copy(),
                dendrites=cols.copy(),
            )
        else:
            if isinstance(color, str):
                # Deal with a a cmap being passed
                if color in _mapscales_cmaps:
                    cols = [
                        colorMap(n, name=color, vmin=-2, vmax=N + 2)
                        for n in np.arange(N)
                    ]
                    colors = dict(
                        soma=cols.copy(),
                        axon=cols.copy(),
                        dendrites=cols.copy(),
                    )

                else:
                    # Deal with a single color being passed
                    cols = [getColor(color) for n in np.arange(N)]
                    colors = dict(
                        soma=cols.copy(),
                        axon=cols.copy(),
                        dendrites=cols.copy(),
                    )
            elif isinstance(color, dict):
                # Deal with a dictionary with color for each component
                if "soma" not in color.keys():
                    raise ValueError(
                        f"When passing a dictionary as color argument, \
                                                soma should be one fo the keys: {color}"
                    )
                dendrites_color = color.pop("dendrites", color["soma"])
                axon_color = color.pop("axon", color["soma"])

                colors = dict(
                    soma=[color["soma"] for n in np.arange(N)],
                    axon=[axon_color for n in np.arange(N)],
                    dendrites=[dendrites_color for n in np.arange(N)],
                )

            elif isinstance(color, (list, tuple)):
                # Check that the list content makes sense
                if len(color) != N:
                    raise ValueError(
                        "When passing a list of color arguments, the list length"
                        +
                        f" ({len(color)}) should match the number of neurons ({N})."
                    )
                if len(set([type(c) for c in color])) > 1:
                    raise ValueError(
                        "When passing a list of color arguments, all list elements"
                        + " should have the same type (e.g. str or dict)")

                if isinstance(color[0], dict):
                    # Deal with a list of dictionaries
                    soma_colors, dendrites_colors, axon_colors = [], [], []

                    for col in color:
                        if "soma" not in col.keys():
                            raise ValueError(
                                f"When passing a dictionary as col argument, \
                                                        soma should be one fo the keys: {col}"
                            )
                        dendrites_colors.append(
                            col.pop("dendrites", col["soma"]))
                        axon_colors.append(col.pop("axon", col["soma"]))
                        soma_colors.append(col["soma"])

                    colors = dict(
                        soma=soma_colors,
                        axon=axon_colors,
                        dendrites=dendrites_colors,
                    )

                else:
                    # Deal with a list of colors
                    colors = dict(
                        soma=color.copy(),
                        axon=color.copy(),
                        dendrites=color.copy(),
                    )
            else:
                raise ValueError(
                    f"Color argument passed is not valid. Should be a \
                                        str, dict, list or None, not {type(color)}:{color}"
                )

        # Check colors, if everything went well we should have N colors per entry
        for k, v in colors.items():
            if len(v) != N:
                raise ValueError(
                    f"Something went wrong while preparing colors. Not all \
                                entries have right length. We got: {colors}")

        return colors
Beispiel #2
0
def test_colors():
    if not isinstance(get_random_colormap(), str):
        raise ValueError

    cols = get_n_shades_of("green", 40)
    if not isinstance(cols, list):
        raise ValueError
    if len(cols) != 40:
        raise ValueError

    getColor("orange")
    getColor([1, 1, 1])
    getColor("k")
    getColor("#ffffff")
    getColor(7)
    getColor(-7)

    getColorName("#ffffff")

    cols = colorMap([0, 1, 2])
    if not isinstance(cols, (list, np.ndarray)):
        raise ValueError
    if len(cols) != 3:
        raise ValueError

    c = colorMap(3, vmin=-3, vmax=4)

    check_colors(cols)
    check_colors(c)
Beispiel #3
0
    def add_neurons_synapses(self, 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.atlas._check_neuron_argument(neurons)

        for neuron in neurons:
            if pre:
                if colorby == 'synapse_type':
                    color = self.atlas.pre_synapses_color
                else:
                    color = self.atlas.get_neuron_color(neuron, colorby=colorby)

                data = self.atlas.synapses_data.loc[self.atlas.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']
                    self.add_cells(data, color=color, verbose=False, alpha=alpha,
                                        radius=self.atlas.synapses_radius, res=24, col_names = col_names)

            if post:
                if colorby == 'synapse_type':
                    color = self.atlas.post_synapses_color
                else:
                    color = self.atlas.get_neuron_color(neuron, colorby=colorby)

                rows = [i for i,row in self.atlas.synapses_data.iterrows()
                            if neuron in row.posts]
                data = self.atlas.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.
                    """

                    # get a sphere at each post synaptic location
                    # spheres = self.add_cells(data, color=color, verbose=False, alpha=.1,
                    #     radius=self.atlas.synapses_radius*4, res=24, col_names = col_names)

                    spheres = self.add_cells(data, color='black', verbose=False, alpha=0,
                        radius=self.atlas.synapses_radius*4, res=24, col_names = col_names)

                    # Get mesh points for neuron the synapses belong to
                    if neuron not in self.store.keys():
                        neuron_file = [f for f in self.atlas.neurons_files if neuron in f][0]
                        neuron_act = load_mesh_from_file(neuron_file, c=color)
                    else:
                        neuron_act, as_skeleton = self.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
                            
                            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, -.5) for p1, p2, d in zip(points1, points2, dists)]

                        arrows = Arrows(points0, endPoints=points2, c=color, s=4)
                        self.add_vtkactor(arrows)
Beispiel #4
0
	def __init__(self,  
				brain_regions=None, 
				regions_aba_color=False,
				neurons=None, 
				tracts=None, 
				add_root=None, 
				verbose=True, 
				jupyter=False,
				display_inset=None, 
				base_dir=None,
				camera=None, 
				screenshot_kwargs = {},
				use_default_key_bindings=False,
				title=None,
				atlas=None,
				atlas_kwargs=dict(),
				**kwargs):
		"""

			Creates and manages a Plotter instance

			:param brain_regions: list of brain regions acronyms to be added to the rendered scene (default value None)
			:param regions_aba_color: if True, use the Allen Brain Atlas regions colors (default value None)
			:param neurons: path to JSON or SWC file with data of neurons to be rendered [or list of files] (default value None)
			:param tracts: list of JSON files with tractography data to be rendered (default value None)
			:param add_root: if False a rendered outline of the whole brain is added to the scene (default value None)
			:param verbose: if False less feedback is printed to screen (default value True)
			:param display_insert: if False the inset displaying the brain's outline is not rendered (but the root is added to the scene) (default value None)
			:param base_dir: path to directory to use for saving data (default value None)
			:param camera: name of the camera parameters setting to use (controls the orientation of the rendered scene)
			:param kwargs: can be used to pass path to individual data folders. See brainrender/Utils/paths_manager.py
			:param screenshot_kwargs: pass a dictionary with keys:
						- 'folder' -> str, path to folder where to save screenshots
						- 'name' -> str, filename to prepend to screenshots files
						- 'format' -> str, 'png', 'svg' or 'jpg'
						- scale -> float, values > 1 yield higher resultion screenshots
			:param use_default_key_bindings: if True the defualt keybindings from VtkPlotter are used, otherwise
							a custom function that can be used to take screenshots with the parameter above. 
			:param title: str, if a string is passed a text is added to the top of the rendering window as a title
			:param atlas: an instance of a valid Atlas class to use to fetch anatomical data for the scene. By default
				if not atlas is passed the allen brain atlas for the adult mouse brain is used.
			:param atlas_kwargs: dictionary used to pass extra arguments to atlas class
		"""
		if atlas is None:
			self.atlas = ABA(base_dir=base_dir,  **atlas_kwargs, **kwargs)
		else:
			self.atlas = atlas(base_dir=base_dir, **atlas_kwargs, **kwargs)


		# Setup a few rendering options
		self.verbose = verbose
		self.regions_aba_color = regions_aba_color

		# Infer if we are using k3d from vtkplotter.settings
		if settings.notebookBackend == 'k3d':
			self.jupyter = True
		else:
			self.jupyter = False

		if display_inset is None:
			self.display_inset = brainrender.DISPLAY_INSET
		else:
			self.display_inset = display_inset

		if self.display_inset and jupyter:
			print("Setting 'display_inset' to False as this feature is not available in juputer notebooks")
			self.display_inset = False


		if add_root is None:
			add_root = brainrender.DISPLAY_ROOT

		# Camera parameters
		if camera is None:
			if self.atlas.default_camera is not None:
				self.camera = check_camera_param(self.atlas.default_camera)
			else:
				self.camera = brainrender.CAMERA
		else:
			self.camera = check_camera_param(camera)

		# Set up vtkplotter plotter and actors records
		if brainrender.WHOLE_SCREEN and not self.jupyter:
			sz = "full"
		elif brainrender.WHOLE_SCREEN and self.jupyter:
			print("Setting window size to 'auto' as whole screen is not available in jupyter")
			sz='auto'
		else:
			sz = "auto"

		if brainrender.SHOW_AXES:
			axes = 1
		else:
			axes = 0

		# Create plotter
		self.plotter = Plotter(axes=axes, size=sz, pos=brainrender.WINDOW_POS, title='brainrender')
		self.plotter.legendBC = getColor('blackboard')

		# SCreenshots and keypresses variables
		self.screenshots_folder = screenshot_kwargs.pop('folder', self.atlas.output_screenshots)
		self.screenshots_name = screenshot_kwargs.pop('name', brainrender.DEFAULT_SCREENSHOT_NAME)
		self.screenshots_extension = screenshot_kwargs.pop('type', brainrender.DEFAULT_SCREENSHOT_TYPE)
		self.screenshots_scale = screenshot_kwargs.pop('scale', brainrender.DEFAULT_SCREENSHOT_SCALE)

		if not use_default_key_bindings:
			self.plotter.keyPressFunction = self.keypress
			self.verbose = False

		if not brainrender.SCREENSHOT_TRANSPARENT_BACKGROUND:
			settings.screenshotTransparentBackground = False
			settings.useFXAA = True

		
		# Prepare store for actors added to scene
		self.actors = {"regions":{}, "tracts":[], "neurons":[], "root":None, "injection_sites":[], 
						"others":[], "labels":[],}
		self._actors = None # store a copy of the actors when manipulations like slicing are done
		self.store = {} # in case we need to store some data

		# Add items to scene
		if brain_regions is not None:
			self.add_brain_regions(brain_regions)

		if neurons is not None:
			self.add_neurons(neurons)

		if tracts is not None:
			self.add_tractography(tracts)

		if add_root:
			self.add_root(render=True)
		else:
			self.root = None

		if title is not None:
			self.add_text(title)

		# Placeholder variables
		self.inset = None  # the first time the scene is rendered create and store the inset here
		self.is_rendered = False # keep track of if the scene has already been rendered
Beispiel #5
0
    def get_neurons(self, neurons, color=None, display_axon=True, display_dendrites=True,
                alpha=1, neurite_radius=None):
        """
        Gets rendered morphological data of neurons reconstructions downloaded from the
        Mouse Light project at Janelia (or other sources). 
        Accepts neurons argument as:
            - file(s) with morphological data
            - vtkplotter 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
        """

        if not isinstance(neurons, (list, tuple)):
            neurons = [neurons]

        # ------------------------------ Prepare colors ------------------------------ #
        N = len(neurons)
        colors = dict(
            soma = None,
            axon = None,
            dendrites = None,
        )

        # If no color is passed, get random colors
        if color is None:
            cols = get_random_colors(N)
            colors = dict(
                soma = cols.copy(),
                axon = cols.copy(),
                dendrites = cols.copy(),)
        else:
            if isinstance(color, str):
                # Deal with a a cmap being passed
                if color in _mapscales_cmaps:
                    cols = [colorMap(n, name=color, vmin=-2, vmax=N+2) for n in np.arange(N)]
                    colors = dict(
                        soma = cols.copy(),
                        axon = cols.copy(),
                        dendrites = cols.copy(),)

                else:
                    # Deal with a single color being passed
                    cols = [getColor(color) for n in np.arange(N)]
                    colors = dict(
                        soma = cols.copy(),
                        axon = cols.copy(),
                        dendrites = cols.copy(),)
            elif isinstance(color, dict):
                # Deal with a dictionary with color for each component
                if not 'soma' in color.keys():
                    raise ValueError(f"When passing a dictionary as color argument, \
                                                soma should be one fo the keys: {color}")
                dendrites_color = color.pop('dendrites', color['soma'])
                axon_color = color.pop('axon', color['soma'])

                colors = dict(
                        soma = [color['soma'] for n in np.arange(N)],
                        axon = [axon_color for n in np.arange(N)],
                        dendrites = [dendrites_color for n in np.arange(N)],)
                        
            elif isinstance(color, (list, tuple)):
                # Check that the list content makes sense
                if len(color) != N:
                    raise ValueError(f"When passing a list of color arguments, the list length"+
                                f" ({len(color)}) should match the number of neurons ({N}).")
                if len(set([type(c) for c in color])) > 1:
                    raise ValueError(f"When passing a list of color arguments, all list elements"+
                                " should have the same type (e.g. str or dict)")

                if isinstance(color[0], dict):
                    # Deal with a list of dictionaries
                    soma_colors, dendrites_colors, axon_colors = [], [], []

                    for col in colors:
                        if not 'soma' in col.keys():
                            raise ValueError(f"When passing a dictionary as col argument, \
                                                        soma should be one fo the keys: {col}")
                        dendrites_colors.append(col.pop('dendrites', col['soma']))
                        axon_colors.append(col.pop('axon', col['soma']))
                        soma_colors.append(col['soma'])

                    colors = dict(
                        soma = soma_colors,
                        axon = axon_colors,
                        dendrites = dendrites_colors,)

                else:
                    # Deal with a list of colors
                    colors = dict(
                        soma = color.copy(),
                        axon = color.copy(),
                        dendrites = color.copy(),)
            else:
                raise ValueError(f"Color argument passed is not valid. Should be a \
                                        str, dict, list or None, not {type(color)}:{color}")

        # Check colors, if everything went well we should have N colors per entry
        for k,v in colors.items():
            if len(v) != N:
                raise ValueError(f"Something went wrong while preparing colors. Not all \
                                entries have right length. We got: {colors}")



        # ---------------------------------- 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_ctors['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 vtkplotter 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])

        # Return
        if len(_neurons_actors) == 1:
            return _neurons_actors[0], None
        elif not _neurons_actors:
            return None, None
        else:
            return _neurons_actors, None