docs: def field_of_view(mesh, retinotopy='any', mask=None, search_scale=3.0, bins=6):
      '''
      field_of_view(obj) yields a field-of-view function for the given vertex-set object or mapping of
        retinotopy data obj.
  
      The field-of-view function is a measurement of how much total pRF weight there is at each point
      in the visual field; essentially it is the sum of all visual-field Gaussian pRFs, where the
      Gaussian's are normalized both by the pRF size (i.e., each pRF is a 2D normal distribution whose
      center comes from its polar angle and eccentricity and whose sigma parameter is the pRF radius)
      and the weight (if any weight such as the variance explained is included in the retinotopy data,
      then the normal distributions are multiplied by this weight, otherwise weights are considered to
      be uniform). Note that the weights are normalized by their sum, so the resulting field-of-view
      function should be a valid probability distribution over the visual field.
  
      The returned object fov = field_of_view(obj) is a special field-of-view object that can be
      called as fov(x, y) or fov(coord) where x and y may be lists or values and coord may be a 2D
      vector or an (n x 2) matrix.
  
      The following options may be provided (also in argument order):
        * retinotopy (default: 'any') specifies the retinotopy data to be used; if this is a string,
          then runs retinotopy_data(obj, retinotopy) and uses the result, otherwise runs
          retinotopy_data(retinotopy) and uses the result; note that this must have a radius parameter
          as well as polar angle and eccentricity or equivalent parameters that specify the pRF center
        * mask (default: None) specifies the mask that should be used; this is interpreted by a call
          to mesh.mask(mask)
        * search_scale (default: 3.0) specifies how many Gaussian standard deviations away from a pRF
          center should be included when calculating the sum of Gaussians at a point
        * bins (default: 6) specifies the number of bins to divide the pRFs into based on the radius
          value; this is used to prune the search of pRFs that overlap a point to just those
          reasonanly close to the point in question
      '''
      # First, find the retino data
      if pimms.is_str(retinotopy):
          retino = retinotopy_data(mesh, retinotopy)
      else:
          retino = retinotopy_data(retinotopy)
      # Convert from polar angle/eccen to longitude/latitude
      (ang,ecc) = as_retinotopy(retino, 'visual')
      if 'radius' not in retino:
          raise ValueError('Retinotopy data must contain a radius, sigma, or size value')
      sig = retino['radius']
      wgt = next((retino[q] for q in ('variance_explained', 'weight') if q in retino), None)
      # Get the indices we care about
      ii = geo.to_mask(mesh, mask, indices=True)
      return FieldOfView(ang[ii], ecc[ii], sig[ii], weight=wgt[ii],
                         search_scale=search_scale, bins=bins)