docs: def calc_retinotopy(note, error, subject, clean, run_lh, run_rh,
                      invert_rh_angle, max_in_eccen, min_in_eccen,
                      angle_lh_file, theta_lh_file,
                      eccen_lh_file, rho_lh_file,
                      weight_lh_file, radius_lh_file,
                      angle_rh_file, theta_rh_file,
                      eccen_rh_file, rho_rh_file,
                      weight_rh_file, radius_rh_file):
      '''
      calc_retinotopy extracts the retinotopy options from the command line, loads the relevant files,
      and stores them as properties on the subject's lh and rh cortices.
      '''
      ctcs = {}
      for (h,ang,tht,ecc,rho,wgt,rad,run) in [
              ('lh', angle_lh_file,theta_lh_file, eccen_lh_file,rho_lh_file,
               weight_lh_file, radius_lh_file, run_lh),
              ('rh', angle_rh_file,theta_rh_file, eccen_rh_file,rho_rh_file,
               weight_rh_file, radius_rh_file, run_rh)]:
          if not run: continue
          hemi = getattr(subject, h)
          props = {}
          # load the properties or find them in the auto-properties
          if ang:
              try: props['polar_angle'] = _guess_surf_file(ang)
              except Exception: error('could not load surface file %s' % ang)
          elif tht:
              try:
                  tmp = _guess_surf_file(tht)
                  props['polar_angle'] = 90.0 - 180.0 / np.pi * tmp
              except Exception: error('could not load surface file %s' % tht)
          else:
              props['polar_angle'] = empirical_retinotopy_data(hemi, 'polar_angle')
          if ecc:
              try: props['eccentricity'] = _guess_surf_file(ecc)
              except Exception: error('could not load surface file %s' % ecc)
          elif rho:
              try:
                  tmp = _guess_surf_file(rhp)
                  props['eccentricity'] = 180.0 / np.pi * tmp
              except Exception: error('could not load surface file %s' % rho)
          else:
              props['eccentricity'] = empirical_retinotopy_data(hemi, 'eccentricity')
          if wgt:
              try: props['weight'] = _guess_surf_file(wgt)
              except Exception: error('could not load surface file %s' % wgt)
          else:
              props['weight'] = empirical_retinotopy_data(hemi, 'weight')
          if rad:
              try: props['radius'] = _guess_surf_file(rad)
              except Exception: error('could not load surface file %s' % rad)
          else:
              props['radius'] = empirical_retinotopy_data(hemi, 'radius')
          # Check for inverted rh
          if h == 'rh' and invert_rh_angle:
              props['polar_angle'] = -props['polar_angle']
          # and zero-out weights for high eccentricities
          props['weight'] = np.array(props['weight'])
          if max_in_eccen is not None:
              props['weight'][props['eccentricity'] > max_in_eccen] = 0
          if min_in_eccen is not None:
              props['weight'][props['eccentricity'] < min_in_eccen] = 0
          # Do smoothing, if requested
          if clean:
              note('Cleaning %s retinotopy...' % h.upper())
              (ang,ecc) = clean_retinotopy(hemi, retinotopy=props, mask=None, weight='weight')
              props['polar_angle']  = ang
              props['eccentricity'] = ecc
          ctcs[h] = hemi.with_prop(props)
      return {'cortices': pyr.pmap(ctcs)}