class_docstr: Image represents a regularly sampled 2D grid of an underlying
  continuous space of intensity values, which will be colormapped on
  plotting. The grid of intensity values may be specified as a NxM
  sized array of values along with a bounds, but it may also be
  defined through explicit and regularly spaced x/y-coordinate
  arrays of shape M and N respectively. The two most basic supported
  constructors of an Image therefore include:
  
      Image((X, Y, Z))
  
  where X is a 1D array of shape M, Y is a 1D array of shape N and
  Z is a 2D array of shape NxM, or equivalently:
  
      Image(Z, bounds=(x0, y0, x1, y1))
  
  where Z is a 2D array of shape NxM defining the intensity values
  and the bounds define the (left, bottom, top, right) edges of four
  corners of the grid. Other gridded formats which support declaring
  of explicit x/y-coordinate arrays such as xarray are also
  supported.
  
  Note that the interpretation of the orientation of the array
  changes depending on whether bounds or explicit coordinates are
  used.
class_docstr_tok: ["Image","represents","a","regularly","sampled","2D","grid","of","an","underlying","continuous","space","of","intensity","values",",","which","will","be","colormapped","on","plotting",".","The","grid","of","intensity","values","may","be","specified","as","a","NxM","sized","array","of","values","along","with","a","bounds",",","but","it","may","also","be","defined","through","explicit","and","regularly","spaced","x\/y-coordinate","arrays","of","shape","M","and","N","respectively",".","The","two","most","basic","supported","constructors","of","an","Image","therefore","include",":","Image","(","(","X",",","Y",",","Z",")",")","where","X","is","a","1D","array","of","shape","M",",","Y","is","a","1D","array","of","shape","N","and","Z","is","a","2D","array","of","shape","NxM",",","or","equivalently",":","Image","(","Z",",","bounds=","(","x0",",","y0",",","x1",",","y1",")",")","where","Z","is","a","2D","array","of","shape","NxM","defining","the","intensity","values","and","the","bounds","define","the","(","left",",","bottom",",","top",",","right",")","edges","of","four","corners","of","the","grid",".","Other","gridded","formats","which","support","declaring","of","explicit","x\/y-coordinate","arrays","such","as","xarray","are","also","supported",".","Note","that","the","interpretation","of","the","orientation","of","the","array","changes","depending","on","whether","bounds","or","explicit","coordinates","are","used","."]
code: def _validate(self, data_bounds, supplied_bounds):
      if len(self.shape) == 3:
          if self.shape[2] != len(self.vdims):
              raise ValueError(
                  "Input array has shape %r but %d value dimensions defined"
                  % (self.shape, len(self.vdims))
              )
  
      # Ensure coordinates are regularly sampled
      clsname = type(self).__name__
      xdim, ydim = self.kdims
      xvals, yvals = (
          self.dimension_values(d, expanded=False, flat=False)
          for d in self.kdims
      )
      invalid = []
      if xvals.ndim > 1:
          invalid.append(xdim)
      if yvals.ndim > 1:
          invalid.append(ydim)
      if invalid:
          dims = (
              "{} and {}".format(*tuple(invalid))
              if len(invalid) > 1
              else f"{invalid[0]}"
          )
          raise ValueError(
              f"{clsname} coordinates must be 1D arrays, "
              f"{dims} dimension(s) were found to have "
              "multiple dimensions. Either supply 1D "
              "arrays or use the QuadMesh element for "
              "curvilinear coordinates."
          )
  
      xvalid = util.validate_regular_sampling(xvals, self.rtol)
      yvalid = util.validate_regular_sampling(yvals, self.rtol)
      msg = (
          "{clsname} dimension{dims} not evenly sampled to relative "
          "tolerance of {rtol}. Please use the QuadMesh element for "
          "irregularly sampled data or set a higher tolerance on "
          "hv.config.image_rtol or the rtol parameter in the "
          "{clsname} constructor."
      )
      dims = None
      if not xvalid:
          dims = (
              f" {xdim} is " if yvalid else f"(s) {xdim} and {ydim} are"
          )
      elif not yvalid:
          dims = f" {ydim} is"
      if dims:
          self.param.warning(
              msg.format(clsname=clsname, dims=dims, rtol=self.rtol)
          )
  
      if not supplied_bounds:
          return
  
      if data_bounds is None:
          (x0, x1), (y0, y1) = (
              self.interface.range(self, kd.name) for kd in self.kdims
          )
          xstep = (1.0 / self.xdensity) / 2.0
          ystep = (1.0 / self.ydensity) / 2.0
          if not isinstance(x0, util.datetime_types):
              x0, x1 = (x0 - xstep, x1 + xstep)
          if not isinstance(y0, util.datetime_types):
              y0, y1 = (y0 - ystep, y1 + ystep)
          bounds = (x0, y0, x1, y1)
      else:
          bounds = data_bounds
  
      not_close = False
      for r, c in zip(bounds, self.bounds.lbrt()):
          if isinstance(r, util.datetime_types):
              r = util.dt_to_int(r)
          if isinstance(c, util.datetime_types):
              c = util.dt_to_int(c)
          if util.isfinite(r) and not np.isclose(r, c, rtol=self.rtol):
              not_close = True
      if not_close:
          raise ValueError(
              "Supplied Image bounds do not match the coordinates defined "
              "in the data. Bounds only have to be declared if no coordinates "
              "are supplied, otherwise they must match the data. To change "
              "the displayed extents set the range on the x- and y-dimensions."
          )
  
imports: import colorsys
  from copy import deepcopy
  from operator import itemgetter
  import numpy
  import param
  from ..core import Dataset, Dimension, Element2D, Overlay, config, util
  from ..core.boundingregion import BoundingBox, BoundingRegion
  from ..core.data import ImageInterface
  from ..core.data.interface import DataError
  from ..core.dimension import dimension_name
  from ..core.sheetcoords import SheetCoordinateSystem, Slice
  from .chart import Curve
  from .geom import Selection2DExpr
  from .graphs import TriMesh
  from .tabular import Table
  from .util import categorical_aggregate2d, compute_slice_bounds
label_desc: Use image node_id 2 for calling the Image obj's underlying member method code with example usage: obj._validate(data_bounds, supplied_bounds) without return types