code: def pca_image(
      img,
      axis="t",
      mask=None,
      ncomp=None,
      standardize=True,
      design_keep=None,
      design_resid="mean",
      tol_ratio=0.01,
  ):
      """Compute the PCA of an image over a specified axis
  
      Parameters
      ----------
      img : Image
          The image on which to perform PCA over the given `axis`
      axis : str or int, optional
          Axis over which to perform PCA. Default is 't'. If `axis` is an integer,
          gives the index of the input (domain) axis of `img`. If `axis` is a str, can be
          an input (domain) name, or an output (range) name, that maps to an input
          (domain) name.
      mask : Image, optional
          An optional mask, should have shape == image.shape[:3] and the same
          coordinate map as `img` but with `axis` dropped
      ncomp : {None, int}, optional
         How many component basis projections to return. If ncomp is None
         (the default) then the number of components is given by the
         calculated rank of the data, after applying `design_keep`,
         `design_resid` and `tol_ratio` below.  We always return all the
         basis vectors and percent variance for each component; `ncomp`
         refers only to the number of basis_projections returned.
      standardize : bool, optional
         If True, standardize so each time series (after application of
         `design_keep` and `design_resid`) has the same standard
         deviation, as calculated by the ``np.std`` function.
      design_keep : None or ndarray, optional
         Data is projected onto the column span of design_keep.
         None (default) equivalent to ``np.identity(data.shape[axis])``
      design_resid : str or None or ndarray, optional
         After projecting onto the column span of design_keep, data is
         projected perpendicular to the column span of this matrix.  If
         None, we do no such second projection.  If a string 'mean', then
         the mean of the data is removed, equivalent to passing a column
         vector matrix of 1s.
      tol_ratio : float, optional
         If ``XZ`` is the vector of singular values of the projection
         matrix from `design_keep` and `design_resid`, and S are the
         singular values of ``XZ``, then `tol_ratio` is the value used to
         calculate the effective rank of the projection of the design, as
         in ``rank = ((S / S.max) > tol_ratio).sum()``
  
      Returns
      -------
      results : dict
          $L$ is the number of non-trivial components found after applying
         `tol_ratio` to the projections of `design_keep` and
         `design_resid`.
  
         `results` has keys:
         * ``basis_vectors``: series over `axis`, shape (data.shape[axis], L) -
            the eigenvectors of the PCA
         * ``pcnt_var``: percent variance explained by component, shape
            (L,)
         * ``basis_projections``: PCA components, with components varying
            over axis `axis`; thus shape given by: ``s = list(data.shape);
            s[axis] = ncomp``
         * ``axis``: axis over which PCA has been performed.
  
      Examples
      --------
      >>> from nipy.testing import funcfile
      >>> from nipy import load_image
      >>> func_img = load_image(funcfile)
  
      Time is the fourth axis
  
      >>> func_img.coordmap.function_range
      CoordinateSystem(coord_names=('aligned-x=L->R', 'aligned-y=P->A', 'aligned-z=I->S', 't'), name='aligned', coord_dtype=float64)
      >>> func_img.shape
      (17, 21, 3, 20)
  
      Calculate the PCA over time, by default
  
      >>> res = pca_image(func_img)
      >>> res['basis_projections'].coordmap.function_range
      CoordinateSystem(coord_names=('aligned-x=L->R', 'aligned-y=P->A', 'aligned-z=I->S', 'PCA components'), name='aligned', coord_dtype=float64)
  
      The number of components is one less than the number of time points
  
      >>> res['basis_projections'].shape
      (17, 21, 3, 19)
      """
      img_klass = img.__class__
      # Which axes are we operating over?
      in_ax, out_ax = io_axis_indices(img.coordmap, axis)
      if None in (in_ax, out_ax):
          raise AxisError(
              f'Cannot identify matching input output axes with "{axis}"'
          )
      if not orth_axes(in_ax, out_ax, img.coordmap.affine):
          raise AxisError(
              'Input and output axes found from "%s" not orthogonal '
              "to rest of affine" % axis
          )
      # Roll the chosen axis to input position zero
      work_img = rollimg(img, axis)
      if mask is not None:
          if not mask.coordmap.similar_to(
              drop_io_dim(img.coordmap, axis)
          ):
              raise ValueError(
                  "Mask should have matching coordmap to `img` "
                  "coordmap with dropped axis %s" % axis
              )
      data = work_img.get_fdata()
      if mask is not None:
          mask_data = mask.get_fdata()
      else:
          mask_data = None
      # do the PCA
      res = pca(
          data,
          0,
          mask_data,
          ncomp,
          standardize,
          design_keep,
          design_resid,
          tol_ratio,
      )
      # Clean up images after PCA
      # Rename the axis we dropped, at position 0 after rollimg
      output_coordmap = work_img.coordmap.renamed_domain(
          {0: "PCA components"}
      )
      # And the matching output axis - which has not moved position
      output_coordmap = output_coordmap.renamed_range(
          {out_ax: "PCA components"}
      )
      output_img = img_klass(res["basis_projections"], output_coordmap)
      # We have to roll the axis back to the original position
      output_img = rollimg(output_img, 0, in_ax + 1)
      key = f"basis_vectors over {axis}"
      res[key] = res["basis_vectors"]
      res["basis_projections"] = output_img
      # Signal the roll in results
      res["axis"] = in_ax
      return res
  
file_path: nipy/nipy/algorithms/utils/pca.py
imports: import numpy
  import numpy.linalg
  from ...core.image.image import rollimg
  from ...core.reference.coordinate_map import AxisError, drop_io_dim, io_axis_indices, orth_axes
label_desc: Use image node_id 4 for calling a global function with example usage: pca_image(img, axis, mask, ncomp, standardize, design_keep, design_resid, tol_ratio) and returns: res