def terminal_states(data, vkey='<STR_LIT>', groupby=None, groups=None, self_transitions=False, basis=None,<EOL>weight_diffusion=<NUM_LIT:0>, scale_diffusion=<NUM_LIT:1>, eps=<NUM_LIT>, copy=False):
adata = data.copy() if copy else data<EOL>logg.info('<STR_LIT>', r=True)<EOL>strings_to_categoricals(adata)<EOL>groupby = '<STR_LIT>' if groupby is None and '<STR_LIT>' in adata.obs.keys() else groupby<EOL>categories = adata.obs[groupby].cat.categories if groupby is not None and groups is None else [None]<EOL>for cat in categories:<EOL><INDENT>groups = cat if cat is not None else groups<EOL>cell_subset = groups_to_bool(adata, groups=groups, groupby=groupby)<EOL>_adata = adata if groups is None else adata[cell_subset]<EOL>connectivities = get_connectivities(_adata, '<STR_LIT>')<EOL>T = transition_matrix(_adata, vkey=vkey, basis=basis, weight_diffusion=weight_diffusion,<EOL>scale_diffusion=scale_diffusion, self_transitions=self_transitions, backward=True)<EOL>eigvecs_roots = eigs(T, eps=eps, perc=[<NUM_LIT:2>, <NUM_LIT>])[<NUM_LIT:1>]<EOL>roots = csr_matrix.dot(connectivities, eigvecs_roots).sum(<NUM_LIT:1>)<EOL>roots = scale(np.clip(roots, <NUM_LIT:0>, np.percentile(roots, <NUM_LIT>)))<EOL>write_to_obs(adata, '<STR_LIT>', roots, cell_subset)<EOL>T = transition_matrix(_adata, vkey=vkey, basis=basis, weight_diffusion=weight_diffusion,<EOL>scale_diffusion=scale_diffusion, self_transitions=self_transitions, backward=False)<EOL>eigvecs_ends = eigs(T, eps=eps, perc=[<NUM_LIT:2>, <NUM_LIT>])[<NUM_LIT:1>]<EOL>ends = csr_matrix.dot(connectivities, eigvecs_ends).sum(<NUM_LIT:1>)<EOL>ends = scale(np.clip(ends, <NUM_LIT:0>, np.percentile(ends, <NUM_LIT>)))<EOL>write_to_obs(adata, '<STR_LIT>', ends, cell_subset)<EOL>n_roots, n_ends = eigvecs_roots.shape[<NUM_LIT:1>], eigvecs_ends.shape[<NUM_LIT:1>]<EOL>groups_str = '<STR_LIT>' + groups + '<STR_LIT:)>' if isinstance(groups, str) else '<STR_LIT>'<EOL>logg.info('<STR_LIT>' + str(n_roots) + '<STR_LIT>' + str(n_ends) + '<STR_LIT>' + groups_str)<EOL><DEDENT>logg.info('<STR_LIT>', time=True, end='<STR_LIT:U+0020>' if settings.verbosity > <NUM_LIT:2> else '<STR_LIT:\n>')<EOL>logg.hint(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return adata if copy else None<EOL>
Computes terminal states (root and end points).

    Arguments
    ---------
    data: :class:`~anndata.AnnData`
        Annotated data matrix.
    vkey: `str` (default: `'velocity'`)
        Name of velocity estimates to be used.
    self_transitions: `bool` (default: `False`)
        Allow transitions from one node to itself.
    basis: `str` (default: `None`)
        Basis to use.
    weight_diffusion: `float` (default: 0)
        Relative weight to be given to diffusion kernel (Brownian motion)
    scale_diffusion: `float` (default: 1)
        Scale of diffusion kernel.
    eps: `float` (default: 1e-3)
        Tolerance for eigenvalue selection.
    copy: `bool` (default: `False`)
        Return a copy instead of writing to data.

    Returns
    -------
    Returns or updates `data` with the attributes
    root: `.obs`
        sparse matrix with transition probabilities.
    end: `.obs`
        sparse matrix with transition probabilities.