code: def compute_transitions(self, density_normalize=True):
          
          W = self._connectivities
          # density normalization as of Coifman et al. (2005)
          # ensures that kernel matrix is independent of sampling density
          if density_normalize:
              # q[i] is an estimate for the sampling density at point i
              # it's also the degree of the underlying graph
              q = np.asarray(W.sum(axis=0))
              if not issparse(W):
                  Q = np.diag(1.0/q)
              else:
                  Q = scipy.sparse.spdiags(1.0/q, 0, W.shape[0], W.shape[0])
              K = Q.dot(W).dot(Q)
          else:
              K = W
  
          # z[i] is the square root of the row sum of K
          z = np.sqrt(np.asarray(K.sum(axis=0)))
          if not issparse(K):
              self.Z = np.diag(1.0/z)
          else:
              self.Z = scipy.sparse.spdiags(1.0/z, 0, K.shape[0], K.shape[0])
          self._transitions_sym = self.Z.dot(K).dot(self.Z)
          logg.msg('computed transitions', v=4, time=True)
docs: Compute transition matrix.
  
          Parameters
          ----------
          density_normalize : `bool`
              The density rescaling of Coifman and Lafon (2006): Then only the
              geometry of the data matters, not the sampled density.
  
          Returns
          -------
          Makes attributes `.transitions_sym` and `.transitions` available.