class_docstr: Interface for simple dictionary-based dataset format using a
  compressed representation that uses the cartesian product between
  key dimensions. As with DictInterface, the dictionary keys correspond
  to the column (i.e. dimension) names and the values are NumPy arrays
  representing the values in that column.
  
  To use this compressed format, the key dimensions must be orthogonal
  to one another with each key dimension specifying an axis of the
  multidimensional space occupied by the value dimension data. For
  instance, given an temperature recordings sampled regularly across
  the earth surface, a list of N unique latitudes and M unique
  longitudes can specify the position of NxM temperature samples.
docstr: Canonicalize takes an array of values as input and reorients
  and transposes it to match the canonical format expected by
  plotting functions. In certain cases the dimensions defined
  via the kdims of an Element may not match the dimensions of
  the underlying data. A set of data_coords may be passed in to
  define the dimensionality of the data, which can then be used
  to np.squeeze the data to remove any constant dimensions. If
  the data is also irregular, i.e. contains multi-dimensional
  coordinates, a set of virtual_coords can be supplied, required
  by some interfaces (e.g. xarray) to index irregular datasets
  with a virtual integer index. This ensures these coordinates
  are not simply dropped.
docstr_tok: ["Canonicalize","takes","an","array","of","values","as","input","and","reorients","and","transposes","it","to","match","the","canonical","format","expected","by","plotting","functions",".","In","certain","cases","the","dimensions","defined","via","the","kdims","of","an","Element","may","not","match","the","dimensions","of","the","underlying","data",".","A","set","of","data_coords","may","be","passed","in","to","define","the","dimensionality","of","the","data",",","which","can","then","be","used","to","np.squeeze","the","data","to","remove","any","constant","dimensions",".","If","the","data","is","also","irregular",",","i.e",".","contains","multi-dimensional","coordinates",",","a","set","of","virtual_coords","can","be","supplied",",","required","by","some","interfaces","(","e.g",".","xarray",")","to","index","irregular","datasets","with","a","virtual","integer","index",".","This","ensures","these","coordinates","are","not","simply","dropped","."]
code: def canonicalize(
      cls, dataset, data, data_coords=None, virtual_coords=None
  ):
      """
      Canonicalize takes an array of values as input and reorients
      and transposes it to match the canonical format expected by
      plotting functions. In certain cases the dimensions defined
      via the kdims of an Element may not match the dimensions of
      the underlying data. A set of data_coords may be passed in to
      define the dimensionality of the data, which can then be used
      to np.squeeze the data to remove any constant dimensions. If
      the data is also irregular, i.e. contains multi-dimensional
      coordinates, a set of virtual_coords can be supplied, required
      by some interfaces (e.g. xarray) to index irregular datasets
      with a virtual integer index. This ensures these coordinates
      are not simply dropped.
      """
      if virtual_coords is None:
          virtual_coords = []
      if data_coords is None:
          data_coords = dataset.dimensions("key", label="name")[::-1]
  
      # Transpose data
      dims = [
          name
          for name in data_coords
          if isinstance(cls.coords(dataset, name), get_array_types())
      ]
      dropped = [
          dims.index(d)
          for d in dims
          if d not in dataset.kdims + virtual_coords
      ]
      if dropped:
          if len(dropped) == data.ndim:
              data = data.flatten()
          else:
              data = np.squeeze(data, axis=tuple(dropped))
  
      if not any(cls.irregular(dataset, d) for d in dataset.kdims):
          inds = [dims.index(kd.name) for kd in dataset.kdims]
          inds = [i - sum([1 for d in dropped if i >= d]) for i in inds]
          if inds:
              data = data.transpose(inds[::-1])
  
      # Reorient data
      invert = False
      slices = []
      for d in dataset.kdims[::-1]:
          coords = cls.coords(dataset, d)
          if np.all(coords[1:] < coords[:-1]) and not coords.ndim > 1:
              slices.append(slice(None, None, -1))
              invert = True
          else:
              slices.append(slice(None))
      data = data[tuple(slices)] if invert else data
  
      # Allow lower dimensional views into data
      if len(dataset.kdims) < 2:
          data = data.flatten()
      return data
  
imports: from collections import defaultdict
  import numpy
  from ..None import util
  from ..dimension import dimension_name
  from ..element import Element
  from ..ndmapping import NdMapping, item_check, sorted_context
  from .dictionary import DictInterface
  from .interface import DataError, Interface
  from .util import dask_array_module, finite_range, get_array_types, is_dask
label_desc: Use image node_id 14 for calling the GridInterface obj's underlying member method code with example usage: obj.canonicalize(cls, dataset, data, data_coords, virtual_coords) and returns: data