docs: def to_map_projection(arg, hemi=Ellipsis, chirality=Ellipsis,
                        center=Ellipsis, center_right=Ellipsis, radius=Ellipsis,
                        method=Ellipsis, registration=Ellipsis, sphere_radius=Ellipsis,
                        pre_affine=Ellipsis, post_affine=Ellipsis, meta_data=Ellipsis):
      '''
      to_map_projection(mp) yields mp if mp is a map projection object.
      to_map_projection((name, hemi)) is equivalent to map_projection(name, chirality=hemi).
      to_map_projection((name, opts)) uses the given options dictionary as options to map_projection;
        (name, hemi, opts) is also allowed as input.
      to_map_projection(filename) yields the map projection loaded from the given filename.
      to_map_projection('<name>:<hemi>') is equivalent to to_map_projection(('<name>', '<hemi>')).
      to_map_projection('<name>') is equivalent to to_map_projection(('<name>', 'lr')).
      to_map_projection((affine, hemi)) converts the given affine transformation, which must be a
        transformation from spherical coordinates to 2D map coordinates (once the transformed z-value
        is dropped), to a map projection. The hemi argument may alternately be an options mapping.
  
      The to_map_projection() function may also be called with the the elements of the above tuples
      passed directly; i.e. to_map_projection(name, hemi) is equivalent to
      to_map_projection((name,hemi)).
  
      Additionaly, all optional arguments to the map_projection function may be given and will be
      copied into the map_projection that is returned. Note that the named chirality argument is used
      to set the chirality of the returned map projection but never to specify the chirality of a
      map projection that is being looked up or loaded; for that use the second argument, second tuple
      entry, or hemi keyword.
      '''
      kw = dict(center=center, center_right=center_right, radius=radius, chirality=chirality,
                method=method, registration=registration, sphere_radius=sphere_radius,
                pre_affine=pre_affine, post_affine=post_affine, meta_data=meta_data)
      kw = {k:v for (k,v) in six.iteritems(kw) if v is not Ellipsis}
      if pimms.is_vector(arg):
          if   len(arg) == 1: arg = arg[0]
          elif len(arg) == 2:
              (arg, tmp) = arg
              if pimms.is_map(tmp):
                  kw = {k:v for (k,v) in six.iteritems(pimms.merge(tmp, kw)) if v is not Ellipsis}
              elif hemi is Ellipsis: hemi = arg
          elif len(arg) == 3:
              (arg, h, opts) = arg
              kw = {k:v for (k,v) in six.iteritems(pimms.merge(opts, kw)) if v is not Ellipsis}
              if hemi is Ellipsis: hemi = h
          else: raise ValueError('Invalid vector argument given to to_map_projection()')
      hemi = deduce_chirality(hemi)
      mp = None
      if   is_map_projection(arg): mp = arg
      elif pimms.is_str(arg):
          # first see if there's a hemi appended
          if ':' in arg:
              spl = arg.split(':')
              (a,h) = (':'.join(spl[:-1]), spl[-1])
              try:
                  (hemtmp, arg) = (to_hemi_str(h), a)
                  if hemi is None: hemi = hemtmp
              except Exception: pass
          # otherwise, strings alone might be map projection names or filenames
          mp = map_projection(arg, hemi)
      else: raise ValueError('Cannot interpret argument to to_map_projection')
      if len(kw) == 0: return mp
      else: return mp.copy(**kw)