예제 #1
0
    def add(self, *items, names=None, classes=None, **kwargs):
        """
            General method to add Actors to the scene.

            :param items: vedo.Mesh, Actor, (str, Path).   
                    If str/path it should be a path to a .obj or .stl file.
                    Whatever the input it's turned into an instance of Actor
                    before adding it to the scne
                
            :param names: names to be assigned to the Actors
            :param classs: br_classes to be assigned to the Actors
            :param **kwargs: parameters to be passed to the individual 
                loading functions (e.g. to load from file and specify the color)
        """
        names = names or [None for a in items]
        classes = classes or [None for a in items]

        # turn items into Actors
        actors = []
        for item, name, _class in zip(items, listify(names), listify(classes)):
            if item is None:
                continue

            if isinstance(item, (Mesh, Assembly)):
                actors.append(Actor(item, name=name, br_class=_class))

            elif pi.utils._class_name(item) == "vtkCornerAnnotation":
                # Mark text actors differently because they don't behave like
                # other 3d actors
                actors.append(
                    Actor(
                        item,
                        name=name,
                        br_class=_class,
                        is_text=True,
                        **kwargs,
                    ))
            elif pi.utils._class_name(item) == "Volume" and not isinstance(
                    item, Volume):
                actors.append(
                    Volume(item, name=name, br_class=_class, **kwargs))

            elif isinstance(item, Actor):
                actors.append(item)

            elif isinstance(item, (str, Path)):
                mesh = load_mesh_from_file(item, **kwargs)
                name = name or Path(item).name
                _class = _class or "from file"
                actors.append(Actor(mesh, name=name, br_class=_class))

            else:
                raise ValueError(
                    f"Unrecognized argument: {item} [{pi.utils._class_name(item)}]"
                )

        # Add to the lists actors
        self.actors.extend(actors)
        return return_list_smart(actors)
예제 #2
0
    def get_actors(self, name=None, br_class=None):
        """
        Return's the scene's actors that match some search criteria.

        :param name: strm int or list of str/int, actors' names
        :param br_class: str or list of str, actors br classes
        """
        matches = self.actors
        if name is not None:
            name = listify(name)
            matches = [m for m in matches if m.name in name]
        if br_class is not None:
            br_class = listify(br_class)
            matches = [m for m in matches if m.br_class in br_class]
        return matches
예제 #3
0
    def slice(
        self,
        plane: [str, Plane],
        actors=None,
        close_actors=False,
    ):
        """
        Slices actors with a plane.

        :param plane: str, Plane. If a string it needs to be
            a supported plane from brainglobe's atlas api (e.g. 'frontal')
            otherwise it should be a vedo.Plane mesh
        :param actors: list of actors to be sliced. If None all actors
            will be sliced
        :param close_actors: If true the openings in the actors meshes
            caused by teh cut will be closed.
        """
        if isinstance(plane, str):
            plane = self.atlas.get_plane(plane=plane)

        if not actors or actors is None:
            actors = self.clean_actors.copy()

        for actor in listify(actors):
            actor._mesh = actor._mesh.cutWithPlane(
                origin=plane.center,
                normal=plane.normal,
            )
            if close_actors:
                actor.cap()

            if actor.silhouette is not None:
                self.plotter.remove(actor.silhouette.mesh)
                self.plotter.add(actor.make_silhouette().mesh)
예제 #4
0
def experiments_source_search(SOI):
    """
        Returns data about experiments whose injection was in the SOI, structure of interest
        :param SOI: str, structure of interest. Acronym of structure to use as seed for teh search
        :param source:  (Default value = True)
    """

    transgenic_id = 0  # id = 0 means use only wild type
    primary_structure_only = True

    if not allen_sdk_installed:
        print(
            f"[{orange}]Allen skd package is not installed, cannot download streamlines data."
            "Please install `allensdk` with `pip install allensdk` (note: this requires python < 3.8)"
        )
        return None

    return pd.DataFrame(
        mca.experiment_source_search(
            injection_structures=listify(SOI),
            target_domain=None,
            transgenic_lines=transgenic_id,
            primary_structure_only=primary_structure_only,
        )
    )
예제 #5
0
    def add_brain_region(self,
                         *regions,
                         alpha=1,
                         color=None,
                         silhouette=True,
                         hemisphere="both"):
        """
            Dedicated method to add brain regions to render
            
            :param regions: str. String of regions names
            :param alpha: float
            :param color: str. If None the atlas default color is used
            :param silhouette: bool. If true regions Actors will have 
                a silhouette
            :param hemisphere: str.
                - if "both" the complete mesh is returned
                - if "left"/"right" only the corresponding half
                    of the mesh is returned
        """
        # get regions actors from atlas
        regions = self.atlas.get_region(*regions, alpha=alpha, color=color)
        regions = listify(regions) or []

        if hemisphere == "right":
            plane = self.atlas.get_plane(plane="sagittal", norm=(0, 0, -1))
        elif hemisphere == "left":
            plane = self.atlas.get_plane(plane="sagittal", norm=(0, 0, 1))
        if hemisphere in ("left", "right"):
            self.slice(plane, actors=regions, close_actors=True)

        if silhouette and regions:
            self.add_silhouette(*regions)

        return self.add(*regions)
예제 #6
0
def experiments_source_search(SOI):
    """
        Returns data about experiments whose injection was in the SOI, structure of interest
        :param SOI: str, structure of interest. Acronym of structure to use as seed for teh search
        :param source:  (Default value = True)
    """

    transgenic_id = 0  # id = 0 means use only wild type
    primary_structure_only = True

    return pd.DataFrame(
        mca.experiment_source_search(
            injection_structures=listify(SOI),
            target_domain=None,
            transgenic_lines=transgenic_id,
            primary_structure_only=primary_structure_only,
        )
    )
예제 #7
0
    def slice(
        self,
        plane: [str, Plane],
        actors=None,
        close_actors=False,
    ):
        """
            Slices actors with a plane.
            
            :param plane: str, Plane. If a string it needs to be 
                a supported plane from brainglobe's atlas api (e.g. 'frontal')
                otherwise it should be a vedo.Plane mesh
            :param actors: list of actors to be sliced. If None all actors
                will be sliced
            :param close_actors: If true the openings in the actors meshes
                caused by teh cut will be closed.
        """
        if self.transform_applied:
            print(
                f"[b {salmon}]Warning: [/b {salmon}][{amber}]you're attempting to cut actors with a plane "
                +
                "after having rendered the scene, this might give unpredictable results."
                +
                "\nIt's advised to perform all cuts before the first call to `render`"
            )

        if isinstance(plane, str):
            plane = self.atlas.get_plane(plane=plane)

        actors = actors or self.clean_actors.copy()
        for actor in listify(actors):
            actor.mesh = actor.mesh.cutWithPlane(
                origin=plane.center,
                normal=plane.normal,
            )
            if close_actors:
                actor.cap()
예제 #8
0
    def add_brain_region(
        self,
        *regions,
        alpha=1,
        color=None,
        silhouette=None,
        hemisphere="both",
        force=False,
    ):
        """
        Dedicated method to add brain regions to render

        :param regions: str. String of regions names
        :param alpha: float
        :param color: str. If None the atlas default color is used
        :param silhouette: bool. If true regions Actors will have
            a silhouette
        :param hemisphere: str.
            - if "both" the complete mesh is returned
            - if "left"/"right" only the corresponding half
                of the mesh is returned
        :param force: force adding of region even if already rendred
        """
        if silhouette is None:
            silhouette = (
                silhouette or True
                if settings.SHADER_STYLE == "cartoon"
                else False
            )

        # avoid adding regions already rendered
        if not force:
            already_in = [
                r.name for r in self.get_actors(br_class="brain region")
            ]
            regions = [r for r in regions if r not in already_in]

        if not regions:  # they were all already rendered
            logger.debug(
                "Not adding any region because they are all already in the scene"
            )
            return None

        logger.debug(
            f"SCENE: Adding {len(regions)} brain regions to scene: {regions}"
        )

        # get regions actors from atlas
        regions = self.atlas.get_region(*regions, alpha=alpha, color=color)
        regions = listify(regions) or []

        # add actors
        if silhouette and regions and alpha:
            self.add_silhouette(*regions)

        actors = self.add(*regions)

        # slice
        if hemisphere == "right":
            plane = self.atlas.get_plane(
                pos=self.root._mesh.centerOfMass(), norm=(0, 0, 1)
            )
        elif hemisphere == "left":
            plane = self.atlas.get_plane(
                pos=self.root._mesh.centerOfMass(), norm=(0, 0, -1)
            )

        if hemisphere in ("left", "right"):
            self.slice(plane, actors=actors, close_actors=True)
        return actors
예제 #9
0
def make_actor_label(
    atlas,
    actors,
    labels,
    size=300,
    color=None,
    radius=100,
    xoffset=0,
    yoffset=-500,
    zoffset=0,
):
    """
        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. 
    """
    offset = [-yoffset, -zoffset, xoffset]
    default_offset = np.array([0, -200, 100])

    new_actors = []
    for n, (actor, label) in enumerate(zip(listify(actors), listify(labels))):

        # Get label color
        if color is None:
            color = actor.c()

        # Get mesh's highest point
        points = actor.points().copy()
        point = points[np.argmin(points[:, 1]), :]
        point += np.array(offset) + default_offset

        try:
            if atlas.hemisphere_from_coords(point, as_string=True) == "left":
                point = atlas.mirror_point_across_hemispheres(point)
        except IndexError:
            pass

        # Create label
        txt = Text(label, point, s=size, c=color)
        txt._kwargs = dict(
            size=size,
            color=color,
            radius=radius,
            xoffset=xoffset,
            yoffset=yoffset,
            zoffset=zoffset,
        )

        new_actors.append(txt)

        # Mark a point on Mesh that corresponds to the label location
        if radius is not None:
            pt = actor.closestPoint(point)
            sphere = Sphere(pt, r=radius, c=color)
            sphere.ancor = pt
            new_actors.append(sphere)

    return new_actors
예제 #10
0
def test_listify():
    assert isinstance(listify([1, 2, 3]), list)
    assert isinstance(listify((1, 2, 3)), list)
    assert isinstance(listify(1), list)