Source code for brainrender.actors.streamlines

"""Create actors for rendering axonal projection streamlines."""

from pathlib import Path

import numpy as np
import pandas as pd
from loguru import logger
from vedo import Mesh, merge
from vedo.shapes import Spheres, Tube

from brainrender.actor import Actor


[docs] def make_streamlines( *streamlines: pd.DataFrame, color: str = "salmon", alpha: float = 1, radius: float = 10, show_injection: bool = True, ) -> list["Streamlines"]: """ Create Streamlines actors from one or more dataframes. Parameters ---------- *streamlines DataFrames with streamlines data. color Colour name. Default ``"salmon"``. alpha Transparency. Default 1. radius Radius of the Tube mesh. Default 10. show_injection If True, spheres mark the injection sites. Default True. Returns ------- list of Streamlines A list of Streamlines actors, one for each input DataFrame. """ return [ Streamlines( s, color=color, alpha=alpha, radius=radius, show_injection=show_injection, ) for s in streamlines ]
[docs] class Streamlines(Actor): """ Actor created from streamlines projection data. Renders axonal streamlines as tube meshes, optionally marking injection sites with spheres. """ def __init__( self, data: pd.DataFrame | str | Path, radius: float = 10, color: str = "salmon", alpha: float = 1, show_injection: bool = True, name: str | None = None, ) -> None: """ Parameters ---------- data DataFrame with streamlines points data, or a path to a JSON file. radius Radius of the Tube mesh. Default 10. color Colour name. Default ``"salmon"``. alpha Transparency. Default 1. show_injection If True, spheres mark the injection sites. Default True. name Actor name. Default ``"Streamlines"``. Raises ------ TypeError If ``data`` is not a DataFrame or a path to a JSON file. """ logger.debug("Creating a streamlines actor") if isinstance(data, (str, Path)): data = pd.read_json(data) elif not isinstance(data, pd.DataFrame): raise TypeError("Input data should be a dataframe") self.radius = radius mesh = ( self._make_mesh(data, show_injection=show_injection) .c(color) .alpha(alpha) .clean() ) name = name or "Streamlines" Actor.__init__(self, mesh, name=name, br_class="Streamliness") def _make_mesh( self, data: pd.DataFrame, show_injection: bool = True, ) -> Mesh: """ Build a merged vedo mesh from streamlines and injection sites. Parameters ---------- data DataFrame with ``lines`` and ``injection_sites`` columns. show_injection If True, add spheres at injection sites. Returns ------- vedo.Mesh A merged vedo mesh containing the streamlines and, optionally, injection sites. """ lines = [] if len(data["lines"]) == 1: try: lines_data = data["lines"][0] except KeyError: # pragma: no cover lines_data = data["lines"]["0"] # pragma: no cover else: lines_data = data["lines"] for line in lines_data: points = [[lin["x"], lin["y"], lin["z"]] for lin in line] lines.append( Tube( points, r=self.radius, res=8, ) ) if show_injection: coords = np.vstack( [ list(point.values()) for point in data.injection_sites.iloc[0] ] ) lines.append( Spheres( coords, r=self.radius * 10, res=8, ) ) return merge(*lines)