def test_backward_manual_dense_norm(self, adata): backward = True vk = VelocityKernel(adata, backward=backward).compute_transition_matrix( density_normalize=False) ck = ConnectivityKernel(adata, backward=backward).compute_transition_matrix( density_normalize=False) # combine the kernels comb = 0.8 * vk + 0.2 * ck T_1 = comb.transition_matrix conn = _get_neighs(adata, "connectivities") T_1 = density_normalization(T_1, conn) T_1 = _normalize(T_1) transition_matrix( adata, diff_kernel="sum", weight_diffusion=0.2, density_normalize=True, backward=backward, ) T_2 = adata.uns[_transition(Direction.BACKWARD)]["T"] np.testing.assert_allclose(T_1.A, T_2.A, rtol=_rtol)
def _get_connectivities( adata: AnnData, mode: str = "connectivities", n_neighbors: Optional[int] = None) -> Optional[spmatrix]: # utility function, copied from scvelo if _has_neighs(adata): C = _get_neighs(adata, mode) if (n_neighbors is not None and n_neighbors <= _get_neighs_params(adata)["n_neighbors"]): C = (_select_connectivities(C, n_neighbors) if mode == "connectivities" else _select_distances(C, n_neighbors)) return C.tocsr().astype(np.float32)
def test_palantir(self, adata): conn = _get_neighs(adata, "connectivities") n_neighbors = _get_neighs_params(adata)["n_neighbors"] pseudotime = adata.obs["latent_time"] conn_biased = bias_knn(conn, pseudotime, n_neighbors) T_1 = _normalize(conn_biased) pk = PalantirKernel(adata, time_key="latent_time").compute_transition_matrix( density_normalize=False) T_2 = pk.transition_matrix np.testing.assert_allclose(T_1.A, T_2.A, rtol=_rtol)
def transition_matrix( adata: AnnData, vkey: str = "velocity", backward: bool = False, self_transitions: Optional[str] = None, sigma_corr: Optional[float] = None, diff_kernel: Optional[str] = None, weight_diffusion: float = 0.2, density_normalize: bool = True, backward_mode: str = "transpose", inplace: bool = True, ) -> csr_matrix: """ Computes transition probabilities from velocity graph. THIS FUNCTION HAS BEEN DEPRECATED. Interact with kernels via the Kernel class or via cellrank.tools_transition_matrix.transition_matrix Employs ideas of both scvelo as well as velocyto. Parameters -------- adata : :class:`anndata.AnnData` Annotated Data Matrix vkey Name of the velocity estimates to be used backward Whether to use the transition matrix to push forward (`False`) or to pull backward (`True`) self_transitions How to fill the diagonal. Can be either 'velocyto' or 'scvelo'. Two diffent heuristics are used. Can prevent dividing by zero in unlucky sitatuations for the reverse process sigma_corr Kernel width for exp kernel to be used to compute transition probabilities from the velocity graph. If None, the median cosine correlation of all potisive cosine correlations will be used. diff_kernel Whether to multiply the velocity connectivities with transcriptomic distances to make them more robust. Options are ('sum', 'mult', 'both') weight_diffusion Relative weight given to the diffusion kernel. Must be in [0, 1]. Only matters when using 'sum' or 'both' for the diffusion kernel. density_normalize Whether to use the transcriptomic KNN graph for density normalization as performed in scanpy when computing diffusion maps backward_mode Options are ['transpose', 'negate']. inplace If True, adds to adata. Otherwise returns. Returns -------- T: :class:`scipy.sparse.csr_matrix` Transition matrix """ logg.info("Computing transition probability from velocity graph") from datetime import datetime print(datetime.now()) # get the direction of the process direction = Direction.BACKWARD if backward else Direction.FORWARD # get the velocity correlations if (vkey + "_graph" not in adata.uns.keys()) or (vkey + "_graph_neg" not in adata.uns.keys()): raise ValueError( "You need to run `tl.velocity_graph` first to compute cosine correlations" ) velo_corr, velo_corr_neg = ( csr_matrix(adata.uns[vkey + "_graph"]).copy(), csr_matrix(adata.uns[vkey + "_graph_neg"]).copy(), ) velo_corr_comb_ = (velo_corr + velo_corr_neg).astype(np.float64) if backward: if backward_mode == "negate": velo_corr_comb = velo_corr_comb_.multiply(-1) elif backward_mode == "transpose": velo_corr_comb = velo_corr_comb_.T else: raise ValueError(f"Unknown backward_mode `{backward_mode}`.") else: velo_corr_comb = velo_corr_comb_ med_corr = np.median(np.abs(velo_corr_comb.data)) # compute the raw transition matrix. At the moment, this is just an exponential kernel logg.debug("DEBUG: Computing the raw transition matrix") if sigma_corr is None: sigma_corr = 1 / med_corr velo_graph = velo_corr_comb.copy() velo_graph.data = np.exp(velo_graph.data * sigma_corr) # should I row-_normalize the transcriptomic connectivities? if diff_kernel is not None or density_normalize: params = _get_neighs_params(adata) logg.debug( f'DEBUG: Using KNN graph computed in basis {params.get("use_rep", "Unknown")!r} ' 'with {params["n_neighbors"]} neighbors') trans_graph = _get_neighs(adata, "connectivities") dev = norm((trans_graph - trans_graph.T), ord="fro") if dev > 1e-4: logg.warning("KNN base graph not symmetric, `dev={dev}`") # KNN smoothing if diff_kernel is not None: logg.debug("DEBUG: Smoothing KNN graph with diffusion kernel") velo_graph = _knn_smooth(diff_kernel, velo_graph, trans_graph, weight_diffusion) # return velo_graph # set the diagonal elements. This is important especially for the backwards direction logg.debug("DEBUG: Setting diagonal elements") velo_graph = _self_loops(self_transitions, velo_graph) # density normalisation - taken from scanpy if density_normalize: logg.debug("DEBUG: Density correcting the velocity graph") velo_graph = density_normalization(velo_graph, trans_graph) # normalize T = _normalize(velo_graph) if not inplace: logg.info("Computed transition matrix") return T if _transition(direction) in adata.uns.keys(): logg.warning( f"`.uns` already contains a field `{_transition(direction)!r}`. Overwriting" ) params = { "backward": backward, "self_transitions": self_transitions, "sigma_corr": np.round(sigma_corr, 3), "diff_kernel": diff_kernel, "weight_diffusion": weight_diffusion, "density_normalize": density_normalize, } adata.uns[_transition(direction)] = {"T": T, "params": params} logg.info( f"Computed transition matrix and added the key `{_transition(direction)!r}` to `adata.uns`" )