docs: def imshow(data, photometric=None, planarconfig=None, bitspersample=None,
             interpolation=None, cmap=None, vmin=None, vmax=None,
             figure=None, title=None, dpi=96, subplot=None, maxdim=None,
             **kwargs):
      """Plot n-dimensional images using matplotlib.pyplot.
  
      Return figure, subplot and plot axis.
      Requires pyplot already imported C{from matplotlib import pyplot}.
  
      Parameters
      ----------
      data : nd array
          The image data.
      photometric : {'MINISWHITE', 'MINISBLACK', 'RGB', or 'PALETTE'}
          The color space of the image data.
      planarconfig : {'CONTIG' or 'SEPARATE'}
          Defines how components of each pixel are stored.
      bitspersample : int
          Number of bits per channel in integer RGB images.
      interpolation : str
          The image interpolation method used in matplotlib.imshow. By default,
          'nearest' will be used for image dimensions <= 512, else 'bilinear'.
      cmap : str or matplotlib.colors.Colormap
          The colormap maps non-RGBA scalar data to colors.
      vmin, vmax : scalar
          Data range covered by the colormap. By default, the complete
          range of the data is covered.
      figure : matplotlib.figure.Figure
          Matplotlib figure to use for plotting.
      title : str
          Window and subplot title.
      subplot : int
          A matplotlib.pyplot.subplot axis.
      maxdim : int
          Maximum image width and length.
      kwargs : dict
          Additional arguments for matplotlib.pyplot.imshow.
  
      """
      # TODO: rewrite detection of isrgb, iscontig
      # TODO: use planarconfig
      if photometric is None:
          photometric = 'RGB'
      if maxdim is None:
          maxdim = 2**16
      isrgb = photometric in ('RGB', 'YCBCR')  # 'PALETTE', 'YCBCR'
  
      if data.dtype == 'float16':
          data = data.astype('float32')
  
      if data.dtype.kind == 'b':
          isrgb = False
  
      if isrgb and not (data.shape[-1] in (3, 4) or (
              data.ndim > 2 and data.shape[-3] in (3, 4))):
          isrgb = False
          photometric = 'MINISBLACK'
  
      data = data.squeeze()
      if photometric in ('MINISWHITE', 'MINISBLACK', None):
          data = reshape_nd(data, 2)
      else:
          data = reshape_nd(data, 3)
  
      dims = data.ndim
      if dims < 2:
          raise ValueError('not an image')
      if dims == 2:
          dims = 0
          isrgb = False
      else:
          if isrgb and data.shape[-3] in (3, 4):
              data = numpy.swapaxes(data, -3, -2)
              data = numpy.swapaxes(data, -2, -1)
          elif not isrgb and (data.shape[-1] < data.shape[-2] // 8 and
                              data.shape[-1] < data.shape[-3] // 8 and
                              data.shape[-1] < 5):
              data = numpy.swapaxes(data, -3, -1)
              data = numpy.swapaxes(data, -2, -1)
          isrgb = isrgb and data.shape[-1] in (3, 4)
          dims -= 3 if isrgb else 2
  
      if interpolation is None:
          threshold = 512
      elif isinstance(interpolation, int):
          threshold = interpolation
      else:
          threshold = 0
  
      if isrgb:
          data = data[..., :maxdim, :maxdim, :maxdim]
          if threshold:
              if (data.shape[-2] > threshold or data.shape[-3] > threshold):
                  interpolation = 'bilinear'
              else:
                  interpolation = 'nearest'
      else:
          data = data[..., :maxdim, :maxdim]
          if threshold:
              if (data.shape[-1] > threshold or data.shape[-2] > threshold):
                  interpolation = 'bilinear'
              else:
                  interpolation = 'nearest'
  
      if photometric == 'PALETTE' and isrgb:
          datamax = data.max()
          if datamax > 255:
              data = data >> 8  # possible precision loss
          data = data.astype('B')
      elif data.dtype.kind in 'ui':
          if not (isrgb and data.dtype.itemsize <= 1) or bitspersample is None:
              try:
                  bitspersample = int(math.ceil(math.log(data.max(), 2)))
              except Exception:
                  bitspersample = data.dtype.itemsize * 8
          elif not isinstance(bitspersample, inttypes):
              # bitspersample can be tuple, e.g. (5, 6, 5)
              bitspersample = data.dtype.itemsize * 8
          datamax = 2**bitspersample
          if isrgb:
              if bitspersample < 8:
                  data = data << (8 - bitspersample)
              elif bitspersample > 8:
                  data = data >> (bitspersample - 8)  # precision loss
              data = data.astype('B')
      elif data.dtype.kind == 'f':
          datamax = data.max()
          if isrgb and datamax > 1.0:
              if data.dtype.char == 'd':
                  data = data.astype('f')
                  data /= datamax
              else:
                  data = data / datamax
      elif data.dtype.kind == 'b':
          datamax = 1
      elif data.dtype.kind == 'c':
          data = numpy.absolute(data)
          datamax = data.max()
  
      if isrgb:
          vmin = 0
      else:
          if vmax is None:
              vmax = datamax
          if vmin is None:
              if data.dtype.kind == 'i':
                  dtmin = numpy.iinfo(data.dtype).min
                  vmin = numpy.min(data)
                  if vmin == dtmin:
                      vmin = numpy.min(data[data > dtmin])
              elif data.dtype.kind == 'f':
                  dtmin = numpy.finfo(data.dtype).min
                  vmin = numpy.min(data)
                  if vmin == dtmin:
                      vmin = numpy.min(data[data > dtmin])
              else:
                  vmin = 0
  
      pyplot = sys.modules['matplotlib.pyplot']
  
      if figure is None:
          pyplot.rc('font', family='sans-serif', weight='normal', size=8)
          figure = pyplot.figure(dpi=dpi, figsize=(10.3, 6.3), frameon=True,
                                 facecolor='1.0', edgecolor='w')
          try:
              figure.canvas.manager.window.title(title)
          except Exception:
              pass
          size = len(title.splitlines()) if title else 1
          pyplot.subplots_adjust(bottom=0.03*(dims+2), top=0.98-size*0.03,
                                 left=0.1, right=0.95, hspace=0.05, wspace=0.0)
      if subplot is None:
          subplot = 111
      subplot = pyplot.subplot(subplot)
      subplot.set_facecolor((0, 0, 0))
  
      if title:
          try:
              title = unicode(title, 'Windows-1252')
          except TypeError:
              pass
          pyplot.title(title, size=11)
  
      if cmap is None:
          if data.dtype.char == '?':
              cmap = 'gray'
          elif data.dtype.kind in 'buf' or vmin == 0:
              cmap = 'viridis'
          else:
              cmap = 'coolwarm'
          if photometric == 'MINISWHITE':
              cmap += '_r'
  
      image = pyplot.imshow(numpy.atleast_2d(data[(0,) * dims].squeeze()),
                            vmin=vmin, vmax=vmax, cmap=cmap,
                            interpolation=interpolation, **kwargs)
  
      if not isrgb:
          pyplot.colorbar()  # panchor=(0.55, 0.5), fraction=0.05
  
      def format_coord(x, y):
          # callback function to format coordinate display in toolbar
          x = int(x + 0.5)
          y = int(y + 0.5)
          try:
              if dims:
                  return '%s @ %s [%4i, %4i]' % (
                      curaxdat[1][y, x], current, y, x)
              return '%s @ [%4i, %4i]' % (data[y, x], y, x)
          except IndexError:
              return ''
  
      def none(event):
          return ''
  
      subplot.format_coord = format_coord
      image.get_cursor_data = none
      image.format_cursor_data = none
  
      if dims:
          current = list((0,) * dims)
          curaxdat = [0, data[tuple(current)].squeeze()]
          sliders = [pyplot.Slider(
              pyplot.axes([0.125, 0.03*(axis+1), 0.725, 0.025]),
              'Dimension %i' % axis, 0, data.shape[axis]-1, 0, facecolor='0.5',
              valfmt='%%.0f [%i]' % data.shape[axis]) for axis in range(dims)]
          for slider in sliders:
              slider.drawon = False
  
          def set_image(current, sliders=sliders, data=data):
              # change image and redraw canvas
              curaxdat[1] = data[tuple(current)].squeeze()
              image.set_data(curaxdat[1])
              for ctrl, index in zip(sliders, current):
                  ctrl.eventson = False
                  ctrl.set_val(index)
                  ctrl.eventson = True
              figure.canvas.draw()
  
          def on_changed(index, axis, data=data, current=current):
              # callback function for slider change event
              index = int(round(index))
              curaxdat[0] = axis
              if index == current[axis]:
                  return
              if index >= data.shape[axis]:
                  index = 0
              elif index < 0:
                  index = data.shape[axis] - 1
              current[axis] = index
              set_image(current)
  
          def on_keypressed(event, data=data, current=current):
              # callback function for key press event
              key = event.key
              axis = curaxdat[0]
              if str(key) in '0123456789':
                  on_changed(key, axis)
              elif key == 'right':
                  on_changed(current[axis] + 1, axis)
              elif key == 'left':
                  on_changed(current[axis] - 1, axis)
              elif key == 'up':
                  curaxdat[0] = 0 if axis == len(data.shape)-1 else axis + 1
              elif key == 'down':
                  curaxdat[0] = len(data.shape)-1 if axis == 0 else axis - 1
              elif key == 'end':
                  on_changed(data.shape[axis] - 1, axis)
              elif key == 'home':
                  on_changed(0, axis)
  
          figure.canvas.mpl_connect('key_press_event', on_keypressed)
          for axis, ctrl in enumerate(sliders):
              ctrl.on_changed(lambda k, a=axis: on_changed(k, a))
  
      return figure, subplot, image