code: def nipy2nifti(img, data_dtype=None, strict=None, fix0=True):
      """Return NIFTI image from nipy image `img`
  
      Parameters
      ----------
      img : object
           An object, usually a NIPY ``Image``,  having attributes `coordmap` and
           `shape`
      data_dtype : None or dtype specifier
          None means try and use header dtype, otherwise try and use data dtype,
          otherwise use np.float32.  A dtype specifier means set the header output
          data dtype using ``np.dtype(data_dtype)``.
      strict : bool, optional
          Whether to use strict checking of input image for creating NIFTI
      fix0: bool, optional
          Whether to fix potential 0 column / row in affine. This option only used
          when trying to find time etc axes in the coordmap output names.  In
          order to find matching input names, we need to use the corresponding
          rows and columns in the affine.  Sometimes time, in particular, has 0
          scaling, and thus all 0 in the corresponding row / column.  In that case
          it's hard to work out which input corresponds. If `fix0` is True, and
          there is only one all zero (matrix part of the) affine row, and only one
          all zero (matrix part of the) affine column, fix scaling for that
          combination to zero, assuming this a zero scaling for time.
  
      Returns
      -------
      ni_img : ``nibabel.Nifti1Image``
          NIFTI image
  
      Raises
      ------
      NiftiError: if space axes not orthogonal to non-space axes
      NiftiError: if non-space axes not orthogonal to each other
      NiftiError: if `img` output space does not match named spaces in NIFTI
      NiftiError: if input image has more than 7 dimensions
      NiftiError: if input image has 7 dimensions, but no time dimension, because
          we need to add an extra 1 length axis at position 3
      NiftiError: if we find a time-like input axis but the matching output axis
          is a different time-like.
      NiftiError: if we find a time-like output axis but the matching input axis
          is a different time-like.
      NiftiError: if we find a time output axis and there are non-zero non-spatial
          offsets in the affine, but we can't find a corresponding input axis.
  
      Notes
      -----
      First, we need to create a valid XYZ Affine.  We check if this can be done
      by checking if there are recognizable X, Y, Z output axes and corresponding
      input (voxel) axes.  This requires the input image to be at least 3D. If we
      find these requirements, we reorder the image axes to have XYZ output axes
      and 3 spatial input axes first, and get the corresponding XYZ affine.
  
      If the spatial dimensions are not orthogonal to the non-spatial dimensions,
      raise a NiftiError.
  
      If the non-spatial dimensions are not orthogonal to each other, raise a
      NiftiError.
  
      We check if the XYZ output fits with the NIFTI named spaces of scanner,
      aligned, Talairach, MNI.  If so, set the NIFTI code and qform, sform
      accordingly.  If the space corresponds to 'unknown' then we must set the
      NIFTI transform codes to 0, and the affine must match the affine we will get
      from loading the NIFTI with no qform, sform.  If not, we're going to lose
      information in the affine, and raise an error.
  
      If any of the first three input axes are named ('slice', 'freq', 'phase')
      set the ``dim_info`` field accordingly.
  
      Set the ``xyzt_units`` field to indicate millimeters and seconds, if there
      is a 't' axis, otherwise millimeters and 0 (unknown).
  
      We look to see if we have a time-like axis in the inputs or the outputs. A
      time-like axis has labels 't', 'hz', 'ppm', 'rads'.  If we have an axis 't'
      in the inputs *and* the outputs, check they either correspond, or both
      inputs and output correspond with no other axis, otherwise raise NiftiError.
      Do the same check for 'hz', then 'ppm', then 'rads'.
  
      If we do have a time-like axis, roll that axis to be the 4th axis.  If this
      axis is actually time, take the ``affine[3, -1]`` and put into the
      ``toffset`` field.  If there's no time-like axis, but there are other
      non-spatial axes, make a length 1 4th array axis to indicate this.
  
      If the resulting NIFTI image has more than 7 dimensions, raise a NiftiError.
  
      Set ``pixdim`` for axes >= 3 using vector length of corresponding affine
      columns.
  
      We don't set the intent-related fields for now.
      """
      strict_none = strict is None
      if strict_none:
          warnings.warn(
              "Default `strict` currently False; this will change to "
              "True in a future version of nipy",
              FutureWarning,
              stacklevel=2,
          )
          strict = False
      known_names = ncrs.known_names
      if not strict:  # add simple 'xyz' to acceptable spatial names
          known_names = copy(known_names)  # copy module global dict
          for c in "xyz":
              known_names[c] = c
      try:
          img = as_xyz_image(img, known_names)
      except (ncrs.AxesError, ncrs.AffineError):
          # Python 2.5 / 3 compatibility
          e = sys.exc_info()[1]
          raise NiftiError(
              f'Image cannot be reordered to XYZ because: "{e}"'
          )
      coordmap = img.coordmap
      # Get useful information from old header
      in_hdr = img.metadata.get("header", None)
      hdr = nib.Nifti1Header.from_header(in_hdr)
      # Default behavior is to take datatype from old header, unless there was no
      # header, in which case we try to use the data dtype.
      data = None
      if data_dtype is None:
          if in_hdr is None:
              data = img.get_fdata()
              data_dtype = data.dtype
          else:
              data_dtype = in_hdr.get_data_dtype()
      else:
          data_dtype = np.dtype(data_dtype)
      hdr.set_data_dtype(data_dtype)
      # Remaining axes orthogonal?
      rzs, trans = to_matvec(coordmap.affine)
      if not np.allclose(rzs[3:, :3], 0) or not np.allclose(
          rzs[:3, 3:], 0
      ):
          raise NiftiError("Non space axes not orthogonal to space")
      # And to each other?
      nsp_affine = rzs[3:, 3:]
      nsp_nzs = np.abs(nsp_affine) > TINY
      n_in_col = np.sum(nsp_nzs, axis=0)
      n_in_row = np.sum(nsp_nzs, axis=1)
      if np.any(n_in_col > 1) or np.any(n_in_row > 1):
          raise NiftiError(
              "Non space axes not orthogonal to each other"
          )
      # Affine seems OK, check for space
      xyz_affine = ncrs.xyz_affine(coordmap, known_names)
      spatial_output_names = coordmap.function_range.coord_names[:3]
      out_space = CS(spatial_output_names)
      for name, space in XFORM2SPACE.items():
          if out_space in space:
              hdr.set_sform(xyz_affine, name)
              hdr.set_qform(xyz_affine, name)
              break
      else:
          if not strict and spatial_output_names == ("x", "y", "z"):
              warnings.warn(
                  "Default `strict` currently False; "
                  "this will change to True in a future version of "
                  'nipy; output names of "x", "y", "z" will raise '
                  "an error.  Please use canonical output names from "
                  "nipy.core.reference.spaces",
                  FutureWarning,
                  stacklevel=2,
              )
              hdr.set_sform(xyz_affine, "scanner")
              hdr.set_qform(xyz_affine, "scanner")
          elif (
              out_space not in ncrs.unknown_space
          ):  # no space we recognize
              raise NiftiError("Image world not a NIFTI world")
          else:  # unknown space requires affine that matches
              # Set guessed shape to set zooms correctly
              hdr.set_data_shape(img.shape)
              # Use qform set to set the zooms, but with 'unknown' code
              hdr.set_qform(xyz_affine, "unknown")
              hdr.set_sform(None)
              if not np.allclose(xyz_affine, hdr.get_base_affine()):
                  raise NiftiError(
                      "Image world is 'unknown' but affine not "
                      "compatible; please reset image world or "
                      "affine"
                  )
      # Use list() to get .index method for python < 2.6
      input_names = list(coordmap.function_domain.coord_names)
      spatial_names = input_names[:3]
      dim_infos = []
      for fps in "freq", "phase", "slice":
          dim_infos.append(
              spatial_names.index(fps) if fps in spatial_names else None
          )
      hdr.set_dim_info(*dim_infos)
      # Set units without knowing time
      hdr.set_xyzt_units(xyz="mm")
      # Done if we only have 3 input dimensions
      n_ns = coordmap.ndims[0] - 3
      if n_ns == 0:  # No non-spatial dimensions
          return nib.Nifti1Image(img.get_fdata(), xyz_affine, hdr)
      elif n_ns > 4:
          raise NiftiError("Too many dimensions to convert")
      # Go now to data, pixdims
      if data is None:
          data = img.get_fdata()
      rzs, trans = to_matvec(img.coordmap.affine)
      ns_pixdims = list(np.sqrt(np.sum(rzs[3:, 3:] ** 2, axis=0)))
      in_ax, out_ax, tl_name = _find_time_like(coordmap, fix0)
      if in_ax is None:  # No time-like axes
          # add new 1-length axis
          if n_ns == 4:
              raise NiftiError("Too many dimensions to convert")
          n_ns += 1
          data = data[:, :, :, None, ...]
          # xyzt_units
          hdr.set_xyzt_units(xyz="mm")
          # shift pixdims
          ns_pixdims.insert(0, 0)
      else:  # Time-like
          hdr.set_xyzt_units(
              xyz="mm", t=TIME_LIKE_AXES[tl_name]["units"]
          )
          # If this is really time, set toffset
          if tl_name == "t" and np.any(trans[3:]):
              # Which output axis corresponds to time?
              if out_ax is None:
                  raise NiftiError("Time input and output do not match")
              hdr["toffset"] = trans[out_ax]
          # Make sure this time-like axis is first non-space axis
          if in_ax != 3:
              data = np.rollaxis(data, in_ax, 3)
              order = list(range(n_ns))
              order.pop(in_ax - 3)
              order.insert(0, in_ax - 3)
              ns_pixdims = [ns_pixdims[i] for i in order]
      hdr["pixdim"][4 : (4 + n_ns)] = ns_pixdims
      return nib.Nifti1Image(data, xyz_affine, hdr)
  
file_path: nipy/nipy/io/nifti_ref.py
imports: import sys
  import warnings
  from copy import copy
  import nibabel
  import numpy
  from nibabel.affines import from_matvec, to_matvec
  from ..core.image.image import Image
  from ..core.image.image_spaces import as_xyz_image
  from ..core.reference import spaces
  from ..core.reference.coordinate_map import AffineTransform
  from ..core.reference.coordinate_map import axmap
  from ..core.reference.coordinate_map import product
  from ..core.reference.coordinate_system import CoordinateSystem
  from .nibcompat import get_affine, get_header
label_desc: Use image node_id 1 for calling a global function with example usage: nipy2nifti(img, data_dtype, strict, fix0) and returns: nib, nib