code: def time_slice_diffs(arr, time_axis=-1, slice_axis=None):
      """Time-point to time-point differences over volumes and slices
  
      We think of the passed array as an image.  The image has a "time"
      dimension given by `time_axis` and a "slice" dimension, given by
      `slice_axis`, and one or more other dimensions.  In the case of imaging
      there will usually be two more dimensions (the dimensions defining the size
      of an image slice). A single slice in the time dimension we call a "volume".
      A single entry in `arr` is a "voxel".  For example, if `time_axis` == 0,
      then ``v = arr[0]`` would be the first volume in the series.  The volume
      ``v`` above has ``v.size`` voxels.  If, in addition, `slice_axis` == 1, then
      for the volume ``v`` (above) ``s = v[0]`` would be a "slice", with
      ``s.size`` voxels. These are obviously terms from neuroimaging.
  
      Parameters
      ----------
      arr : array_like
         Array over which to calculate time and slice differences.  We'll
         call this array an 'image' in this doc.
      time_axis : int, optional
         axis of `arr` that varies over time. Default is last
      slice_axis : None or int, optional
         axis of `arr` that varies over image slice.  None gives last non-time
         axis.
  
      Returns
      -------
      results : dict
  
          ``T`` is the number of time points (``arr.shape[time_axis]``)
  
          ``S`` is the number of slices (``arr.shape[slice_axis]``)
  
          ``v`` is the shape of a volume (``rollimg(arr, time_axis)[0].shape``)
  
          ``d2[t]`` is the volume of squared differences between voxels at
          time point ``t`` and time point ``t+1``
  
          `results` has keys:
  
          * 'volume_mean_diff2' : (T-1,) array
             array containing the mean (over voxels in volume) of the
             squared difference from one time point to the next
          * 'slice_mean_diff2' : (T-1, S) array
             giving the mean (over voxels in slice) of the difference from
             one time point to the next, one value per slice, per
             timepoint
          * 'volume_means' : (T,) array
             mean over voxels for each volume ``vol[t] for t in 0:T``
          * 'slice_diff2_max_vol' : v[:] array
             volume, of same shape as input time point volumes, where each slice
             is is the slice from ``d2[t]`` for t in 0:T-1, that has the largest
             variance across ``t``.  Thus each slice in the volume may well result
             from a different difference time point.
          * 'diff2_mean_vol`` : v[:] array
             volume with the mean of ``d2[t]`` across t for t in 0:T-1.
  
      Raises
      ------
      ValueError : if `time_axis` refers to same axis as `slice_axis`
      """
      arr = np.asarray(arr)
      ndim = arr.ndim
      # roll time axis to 0, slice axis to 1 for convenience
      if time_axis < 0:
          time_axis += ndim
      if slice_axis is None:
          slice_axis = ndim - 2 if time_axis == ndim - 1 else ndim - 1
      elif slice_axis < 0:
          slice_axis += ndim
      if time_axis == slice_axis:
          raise ValueError(
              "Time axis refers to same axis as slice axis"
          )
      arr = np.rollaxis(arr, time_axis)
      # we may have changed the position of slice_axis
      if time_axis > slice_axis:
          slice_axis += 1
      arr = np.rollaxis(arr, slice_axis, 1)
      # shapes of things
      shape = arr.shape
      T = shape[0]
      S = shape[1]
      vol_shape = shape[1:]
      # loop over time points to save memory
      volds = np.empty((T - 1,))
      sliceds = np.empty((T - 1, S))
      means = np.empty((T,))
      diff_mean_vol = np.zeros(vol_shape)
      slice_diff_max_vol = np.zeros(vol_shape)
      slice_diff_maxes = np.zeros(S)
      last_tp = arr[0]
      means[0] = last_tp.mean()
      for dtpi in range(T - 1):
          tp = arr[dtpi + 1]  # shape vol_shape
          means[dtpi + 1] = tp.mean()
          dtp_diff2 = (tp - last_tp) ** 2
          diff_mean_vol += dtp_diff2
          sliceds[dtpi] = dtp_diff2.reshape(S, -1).mean(-1)
          # check whether we have found a highest-diff slice
          sdmx_higher = sliceds[dtpi] > slice_diff_maxes
          if any(sdmx_higher):
              slice_diff_maxes[sdmx_higher] = sliceds[dtpi][sdmx_higher]
              slice_diff_max_vol[sdmx_higher] = dtp_diff2[sdmx_higher]
          last_tp = tp
      volds = sliceds.mean(1)
      diff_mean_vol /= T - 1
      # roll vol shapes back to match input
      diff_mean_vol = np.rollaxis(diff_mean_vol, 0, slice_axis)
      slice_diff_max_vol = np.rollaxis(
          slice_diff_max_vol, 0, slice_axis
      )
      return {
          "volume_mean_diff2": volds,
          "slice_mean_diff2": sliceds,
          "volume_means": means,
          "diff2_mean_vol": diff_mean_vol,
          "slice_diff2_max_vol": slice_diff_max_vol,
      }
  
imports: import numpy
  from ...core.reference.coordinate_map import AxisError, drop_io_dim, io_axis_indices
  from ...io.api import as_image
label_desc: Use image node_id 1 for calling a global function with example usage: time_slice_diffs(arr, time_axis, slice_axis) and returns: dict