code: def cell_fate(data, groupby='clusters', disconnected_groups=None, self_transitions=False, n_neighbors=None, copy=False):
      adata = data.copy() if copy else data
      logg.info('computing cell fates', r=True)
      n_neighbors = 10 if n_neighbors is None else n_neighbors
      _adata = adata.copy()
      vgraph = VelocityGraph(_adata, n_neighbors=n_neighbors, approx=True, n_recurse_neighbors=1)
      vgraph.compute_cosines()
      _adata.uns['velocity_graph'] = vgraph.graph
      _adata.uns['velocity_graph_neg'] = vgraph.graph_neg
      T = transition_matrix(_adata, self_transitions=self_transitions)
      I = np.eye(_adata.n_obs)
      fate = np.linalg.inv(I - T)
      if issparse(T): fate = fate.A
      cell_fates = np.array(_adata.obs[groupby][fate.argmax(1)])
      if disconnected_groups is not None:
          idx = _adata.obs[groupby].isin(disconnected_groups)
          cell_fates[idx] = _adata.obs[groupby][idx]
      adata.obs['cell_fate'] = cell_fates
      adata.obs['cell_fate_confidence'] = fate.max(1) / fate.sum(1)
      strings_to_categoricals(adata)
      logg.info('    finished', time=True, end=' ' if settings.verbosity > 2 else '\n')
      logg.hint(
          'added\n'
          '    \'cell_fate\', most likely cell fate (adata.obs)\n'
          '    \'cell_fate_confidence\', confidence of transitioning to the assigned fate (adata.obs)')
      return adata if copy else None