docs: def predict_retinotopy(sub, template='benson14', registration='fsaverage'):
      '''
      predict_retinotopy(subject) yields a pair of dictionaries each with four keys: angle, eccen,
        sigma, and varea. Each of these keys maps to a numpy array with one entry per vertex.  The
        first element of the yielded pair is the left hemisphere map and the second is the right
        hemisphere map. The values are obtained by resampling the Benson et al. 2014 anatomically
        defined template of retinotopy to the given subject.
  
      The following optional arguments may be given:
        * template (default: 'benson14') specifies the template to use.
        * registration (default: 'fsaverage') specifies the subject registration to use; generally can
          only be 'fsaverage' or 'fsaverage_sym'.
      '''
      template = template.lower()
      retino_tmpls = predict_retinotopy.retinotopy_templates[registration]
      hemis = ['lh','rh'] if registration == 'fsaverage' else ['sym']
      if template not in retino_tmpls:
          libdir = os.path.join(library_path(), 'data')
          search_paths = [libdir]
          # just hard-baked-in for now.
          suff = 'v4_0' if registration == 'fsaverage' else 'v3_0'
          filenames = {(hname, fnm): ('%s.%s_%s.%s.mgz' % (hname,template,fnm,suff))
                       for fnm in ['angle','eccen','varea','sigma']
                       for hname in hemis}
          # find an appropriate directory
          tmpl_path = next((os.path.join(path0, registration)
                            for path0 in search_paths
                            if all(os.path.isfile(os.path.join(path0, registration, 'surf', s))
                                   for s in six.itervalues(filenames))),
                           None)
          if tmpl_path is None:
              raise ValueError('No subject found with appropriate surf/*.%s_* files!' % template)
          tmpl_sub = nyfs.subject(registration)
          spath = os.path.join(tmpl_path, 'surf')
          retino_tmpls[template] = pimms.persist(
              {h:{k: pimms.imm_array(dat)
                  for k in ['angle', 'eccen', 'varea', 'sigma']
                  for dat in [nyio.load(os.path.join(tmpl_path, 'surf', filenames[(h,k)]))]}
               for h in hemis})
  
      # Okay, we just need to interpolate over to this subject
      tmpl = retino_tmpls[template]
      if not all(s in tmpl for s in hemis):
          raise ValueError('could not find matching template')
      if registration == 'fsaverage_sym':
          sym = nyfs.subject('fsaverage_sym')
          if isinstance(sub, mri.Subject):
              subj_hems = (sub.lh, sub.hemis['rhx'])
              tmpl_hems = (sym.lh, sym.lh)
              chrs_hems = ('lh','rh')
          else:
              subj_hems = (sub,)
              tmpl_hems = (sym.lh,)
              chrs_hems = (sub.chirality,)
      else:
          fsa = nyfs.subject('fsaverage')
          if isinstance(sub, mri.Subject):
              subj_hems = (sub.lh, sub.rh)
              tmpl_hems = (fsa.lh, fsa.rh)
              chrs_hems = ('lh','rh')
          else:
              subj_hems = (sub,)
              tmpl_hems = ((fsa.lh if sub.chirality == 'lh' else fsa.rh),)
              chrs_hems = (sub.chirality,)
      tpl = tuple([th.interpolate(sh, tmpl[h if registration == 'fsaverage' else 'sym'])
                  for (sh,th,h) in zip(subj_hems, tmpl_hems, chrs_hems)])
      return tpl[0] if len(tpl) == 1 else tpl