code: def _interpolate(
      agg,
      cmap,
      how,
      alpha,
      span,
      min_alpha,
      name,
      rescale_discrete_levels,
  ):
      if cupy and isinstance(agg.data, cupy.ndarray):
          from ._cuda_utils import masked_clip_2d, interp
      else:
          from ._cpu_utils import masked_clip_2d
  
          interp = np.interp
  
      if agg.ndim != 2:
          raise ValueError("agg must be 2D")
      interpolater = _normalize_interpolate_how(how)
  
      data = agg.data
      if isinstance(data, da.Array):
          data = data.compute()
      else:
          data = data.copy()
  
      # Compute mask
      if np.issubdtype(data.dtype, np.bool_):
          mask = ~data
          data = data.astype(np.int8)
      else:
          if data.dtype.kind == "u":
              mask = data == 0
          else:
              mask = np.isnan(data)
  
      # Handle case where everything is masked out
      if mask.all():
          return Image(
              np.zeros(shape=agg.data.shape, dtype=np.uint32),
              coords=agg.coords,
              dims=agg.dims,
              attrs=agg.attrs,
              name=name,
          )
  
      # Handle offset / clip
      if span is None:
          offset = np.nanmin(data[~mask])
      else:
          offset = np.array(span, dtype=data.dtype)[0]
          masked_clip_2d(data, mask, *span)
  
      # If log/cbrt, could case to float64 right away
      # If linear, can keep current type
      data -= offset
  
      with np.errstate(invalid="ignore", divide="ignore"):
          # Transform data (log, eq_hist, etc.)
          data = interpolater(data, mask)
          discrete_levels = None
          if isinstance(data, (list, tuple)):
              data, discrete_levels = data
  
          # Transform span
          if span is None:
              masked_data = np.where(~mask, data, np.nan)
              span = np.nanmin(masked_data), np.nanmax(masked_data)
  
              if (
                  rescale_discrete_levels
                  and discrete_levels is not None
              ):  # Only valid for eq_hist
                  span = _rescale_discrete_levels(discrete_levels, span)
          else:
              if how == "eq_hist":
                  # For eq_hist to work with span, we'd need to compute the histogram
                  # only on the specified span's range.
                  raise ValueError(
                      "span is not (yet) valid to use with eq_hist"
                  )
  
              span = interpolater([0, span[1] - span[0]], 0)
  
      if isinstance(cmap, Iterator):
          cmap = list(cmap)
      if isinstance(cmap, tuple) and isinstance(cmap[0], str):
          cmap = list(
              cmap
          )  # Tuple of hex values or color names, as produced by Bokeh
      if isinstance(cmap, list):
          rspan, gspan, bspan = np.array(list(zip(*map(rgb, cmap))))
          span = np.linspace(span[0], span[1], len(cmap))
          r = np.nan_to_num(
              interp(data, span, rspan, left=255), copy=False
          ).astype(np.uint8)
          g = np.nan_to_num(
              interp(data, span, gspan, left=255), copy=False
          ).astype(np.uint8)
          b = np.nan_to_num(
              interp(data, span, bspan, left=255), copy=False
          ).astype(np.uint8)
          a = np.where(np.isnan(data), 0, alpha).astype(np.uint8)
          rgba = np.dstack([r, g, b, a])
      elif isinstance(cmap, str) or isinstance(cmap, tuple):
          color = rgb(cmap)
          aspan = np.arange(min_alpha, alpha + 1)
          span = np.linspace(span[0], span[1], len(aspan))
          r = np.full(data.shape, color[0], dtype=np.uint8)
          g = np.full(data.shape, color[1], dtype=np.uint8)
          b = np.full(data.shape, color[2], dtype=np.uint8)
          a = np.nan_to_num(
              interp(data, span, aspan, left=0, right=255), copy=False
          ).astype(np.uint8)
          rgba = np.dstack([r, g, b, a])
      elif callable(cmap):
          # Assume callable is matplotlib colormap
          scaled_data = (data - span[0]) / (span[1] - span[0])
          if cupy and isinstance(scaled_data, cupy.ndarray):
              # Convert cupy array to numpy before passing to matplotlib colormap
              scaled_data = cupy.asnumpy(scaled_data)
  
          rgba = cmap(scaled_data, bytes=True)
          rgba[:, :, 3] = np.where(
              np.isnan(scaled_data), 0, alpha
          ).astype(np.uint8)
      else:
          raise TypeError(
              "Expected `cmap` of `matplotlib.colors.Colormap`, "
              "`list`, `str`, or `tuple`; got: '{0}'".format(type(cmap))
          )
  
      img = rgba.view(np.uint32).reshape(data.shape)
  
      if cupy and isinstance(img, cupy.ndarray):
          # Convert cupy array to numpy for final image
          img = cupy.asnumpy(img)
  
      return Image(img, coords=agg.coords, dims=agg.dims, name=name)
  
imports: from __future__ import annotations
  from collections.abc import Iterator
  from io import BytesIO
  import warnings
  import numpy
  import numba
  import toolz
  import xarray
  import dask.array
  from PIL.Image import fromarray
  from datashader.colors import rgb, Sets1to3
  from datashader.utils import nansum_missing, ngjit
label_desc: Use image node_id 5 for calling a global function with example usage: _interpolate(agg, cmap, how, alpha, span, min_alpha, name, rescale_discrete_levels) and returns: Image, Image