parameters: (subject, xfmname, roi_list=None, gm_sampler='cortical', split_lr=False,
                    allow_overlap=False, fail_for_missing_rois=True, exclude_empty_rois=False,
                    threshold=None, return_dict=True, overlay_file=None)
docstring: Return a dictionary of roi masks
  
      This function returns a single 3D array with a separate numerical index for each ROI,
  
      Parameters
      ----------
      subject : string
          pycortex subject ID
      xfmname : string
          pycortex transformation name
      roi_list : list or None
          List of names of ROIs to retrieve (e.g. ['FFA','OFA','EBA']). Names should match
          the ROI layers in the overlays.svg file for the `subject` specified. If None is
          provided (default), all available ROIs for the subject are returned. If 'Cortex'
          is included in roi_list*, a mask of all cortical voxels NOT included in other
          requested rois is included in the output.
          * works for gm_sampler = 'cortical', 'think', 'thick', or (any scalar value);
          does not work for mapper-based gray matter samplers.
      gm_sampler : scalar or string
          How to sample the cortical gray matter. Options are:
          <an integer> - Distance from fiducial surface to define ROI. Reasonable values
              for this input range from 1-3.
          The following will only work if you have used Freesurfer to define the subject's
          surface, and so have separate pial and white matter surfaces:
          'cortical' - selection of all voxels with centers within the cortical ribbon
              (directly computed from distance of each voxel from fiducial surface)
          'thick' - selection of voxels within 'thick' mask (see cortex.get_mask())
          'thin' - selection of voxels within 'thin' mask (see cortex.get_mask())
          'cortical-liberal' - selection of all voxels that have any part within the
              cortical ribbon ('line_nearest' mapper)
          'cortical-conservative' - selection of only the closest voxel to each surface
              vertex ('nearest' mapper)
          mapper-based gm_samplers will return floating point values from 0-1 for each
          voxel (reflecting the fraction of that voxel inside the ROI) unless a threshold
          is provided.
      threshold : float [0-1]
          value used to convert probablistic ROI values to a boolean mask for the ROI.
      split_lr : bool
          Whether to separate ROIs in to left and right hemispheres (e.g., 'V1' becomes
          'V1_L' and 'V1_R')
      allow_overlap : bool
          Whether to allow ROIs to include voxels in other ROIs (default:False). This
          should only be relevant if (a) spline shapes defining ROIs in overlays.svg
          overlap at all, or (b) a low threshold is set for a mapper-based gm_sampler
      fail_for_missing_rois : bool
          Whether to fail if one or more of the rois specified in roi_list are not
          defined in the overlays.svg file
      exclude_empty_rois : bool
          Whether to fail if an ROI that is present in the overlays.svg file contains no
          voxels due to the scan not targeting that region of the brain.
      return_dict : bool
          If True (default), function returns a dictionary of ROI masks; if False, a volume
          with integer indices for each ROI (similar to Freesurfer's aseg masks) and a
          dictionary of how the indices map to ROI names are returned.
  
      Returns
      -------
      roi_masks : dict
          Dictionary of arrays; keys are ROI names, values are roi masks.
      - OR -
      index_volume, index_labels : array, dict
          `index_volume` is a 3D array with a separate numerical index value for each ROI. Index values
          in the left hemisphere are negative. (For example, if V1 in the right hemisphere is 1, then V1 in
          the left hemisphere will be -1). `index_labels` is a dict that maps roi names to index values
          (e.g. {'V1': 1}).
  
      Notes
      -----
      Some gm_samplers may fail if you have very high-resolution data (i.e., with voxels on the
      order of the spacing between vertices in your cortical mesh). In such cases, there may be
      voxels in the middle of your ROI that are not assigned to the ROI (because no vertex falls
      within that voxel). For such cases, it is recommended to use 'cortical', 'thick', or
      'thin' as your `gm_sampler`.
docstring_summary: Return a dictionary of roi masks
docstring_tokens: Return a dictionary of roi masks
function: def get_roi_masks(subject, xfmname, roi_list=None, gm_sampler='cortical', split_lr=False,
                    allow_overlap=False, fail_for_missing_rois=True, exclude_empty_rois=False,
                    threshold=None, return_dict=True, overlay_file=None):
      """Return a dictionary of roi masks
  
      This function returns a single 3D array with a separate numerical index for each ROI,
  
      Parameters
      ----------
      subject : string
          pycortex subject ID
      xfmname : string
          pycortex transformation name
      roi_list : list or None
          List of names of ROIs to retrieve (e.g. ['FFA','OFA','EBA']). Names should match
          the ROI layers in the overlays.svg file for the `subject` specified. If None is
          provided (default), all available ROIs for the subject are returned. If 'Cortex'
          is included in roi_list*, a mask of all cortical voxels NOT included in other
          requested rois is included in the output.
          * works for gm_sampler = 'cortical', 'think', 'thick', or (any scalar value);
          does not work for mapper-based gray matter samplers.
      gm_sampler : scalar or string
          How to sample the cortical gray matter. Options are:
          <an integer> - Distance from fiducial surface to define ROI. Reasonable values
              for this input range from 1-3.
          The following will only work if you have used Freesurfer to define the subject's
          surface, and so have separate pial and white matter surfaces:
          'cortical' - selection of all voxels with centers within the cortical ribbon
              (directly computed from distance of each voxel from fiducial surface)
          'thick' - selection of voxels within 'thick' mask (see cortex.get_mask())
          'thin' - selection of voxels within 'thin' mask (see cortex.get_mask())
          'cortical-liberal' - selection of all voxels that have any part within the
              cortical ribbon ('line_nearest' mapper)
          'cortical-conservative' - selection of only the closest voxel to each surface
              vertex ('nearest' mapper)
          mapper-based gm_samplers will return floating point values from 0-1 for each
          voxel (reflecting the fraction of that voxel inside the ROI) unless a threshold
          is provided.
      threshold : float [0-1]
          value used to convert probablistic ROI values to a boolean mask for the ROI.
      split_lr : bool
          Whether to separate ROIs in to left and right hemispheres (e.g., 'V1' becomes
          'V1_L' and 'V1_R')
      allow_overlap : bool
          Whether to allow ROIs to include voxels in other ROIs (default:False). This
          should only be relevant if (a) spline shapes defining ROIs in overlays.svg
          overlap at all, or (b) a low threshold is set for a mapper-based gm_sampler
      fail_for_missing_rois : bool
          Whether to fail if one or more of the rois specified in roi_list are not
          defined in the overlays.svg file
      exclude_empty_rois : bool
          Whether to fail if an ROI that is present in the overlays.svg file contains no
          voxels due to the scan not targeting that region of the brain.
      return_dict : bool
          If True (default), function returns a dictionary of ROI masks; if False, a volume
          with integer indices for each ROI (similar to Freesurfer's aseg masks) and a
          dictionary of how the indices map to ROI names are returned.
  
      Returns
      -------
      roi_masks : dict
          Dictionary of arrays; keys are ROI names, values are roi masks.
      - OR -
      index_volume, index_labels : array, dict
          `index_volume` is a 3D array with a separate numerical index value for each ROI. Index values
          in the left hemisphere are negative. (For example, if V1 in the right hemisphere is 1, then V1 in
          the left hemisphere will be -1). `index_labels` is a dict that maps roi names to index values
          (e.g. {'V1': 1}).
  
      Notes
      -----
      Some gm_samplers may fail if you have very high-resolution data (i.e., with voxels on the
      order of the spacing between vertices in your cortical mesh). In such cases, there may be
      voxels in the middle of your ROI that are not assigned to the ROI (because no vertex falls
      within that voxel). For such cases, it is recommended to use 'cortical', 'thick', or
      'thin' as your `gm_sampler`.
      """
      # Convert mapper names to pycortex sampler types
      mapper_dict = {'cortical-conservative':'nearest',
                     'cortical-liberal':'line_nearest'}
      # Method
      use_mapper = gm_sampler in mapper_dict
      use_cortex_mask = (gm_sampler in ('cortical', 'thick', 'thin')) or not isinstance(gm_sampler, string_types)
      if not (use_mapper or use_cortex_mask):
          raise ValueError('Unknown gray matter sampler (gm_sampler)!')
      # Initialize
      roi_voxels = {}
      pct_coverage = {}
      # Catch single-ROI input
      if isinstance(roi_list, string_types):
          roi_list = [roi_list]
      if not return_dict:
          split_lr = True
          if use_mapper and threshold is None:
              raise Exception("You must set a threshold for gm_mapper='%s' if you want an indexed volume output"%gm_mapper)
      # Start with vertices
      if roi_list is None:
          roi_verts = get_roi_verts(subject, mask=use_mapper, overlay_file=overlay_file)
          roi_list = list(roi_verts.keys())
      else:
          tmp_list = [r for r in roi_list if not r=='Cortex']
          try:
              roi_verts = get_roi_verts(subject, roi=tmp_list, mask=use_mapper, overlay_file=overlay_file)
          except KeyError as key:
              if fail_for_missing_rois:
                  raise KeyError("Requested ROI {} not found in overlays.svg!".format(key))
              else:
                  roi_verts = get_roi_verts(subject, roi=None, mask=use_mapper, overlay_file=overlay_file)
                  missing = [r for r in roi_list if not r in roi_verts.keys()+['Cortex']]
                  roi_verts = dict((roi, verts) for roi, verts in roi_verts.items() if roi in roi_list)
                  roi_list = list(set(roi_list)-set(missing))
                  print('Requested ROI(s) {} not found in overlays.svg!'.format(missing))
      # Get (a) indices for nearest vertex to each voxel
      # and (b) distance from each voxel to nearest vertex in fiducial surface
      if (use_cortex_mask or split_lr) or (not return_dict):
          vox_dst, vox_idx = get_vox_dist(subject, xfmname)
      if use_mapper:
          mapper = get_mapper(subject, xfmname, type=mapper_dict[gm_sampler])
      elif use_cortex_mask:
          if isinstance(gm_sampler, string_types):
              cortex_mask = db.get_mask(subject, xfmname, type=gm_sampler)
          else:
              cortex_mask = vox_dst <= gm_sampler
      # Loop over ROIs to map vertices to volume, using mapper or cortex mask + vertex indices
      for roi in roi_list:
          if roi not in roi_verts:
              if not roi=='Cortex':
                  print("ROI {} not found...".format(roi))
              continue
          if use_mapper:
              roi_voxels[roi] = mapper.backwards(roi_verts[roi].astype(np.float))
              # Optionally threshold probablistic values returned by mapper
              if threshold is not None:
                  roi_voxels[roi] = roi_voxels[roi] > threshold
              # Check for partial / empty rois:
              vert_in_scan = np.hstack([np.array((m>0).sum(1)).flatten() for m in mapper.masks])
              vert_in_scan = vert_in_scan[roi_verts[roi]]
          elif use_cortex_mask:
              vox_in_roi = np.in1d(vox_idx.flatten(), roi_verts[roi]).reshape(vox_idx.shape)
              roi_voxels[roi] = vox_in_roi & cortex_mask
              # This is not accurate... because vox_idx only contains the indices of the *nearest*
              # vertex to each voxel, it excludes many vertices. I can't think of a way to compute
              # this accurately for non-mapper gm_samplers for now... ML 2017.07.14
              vert_in_scan = np.in1d(roi_verts[roi], vox_idx[cortex_mask])
          # Compute ROI coverage
          pct_coverage[roi] = vert_in_scan.mean() * 100
          if use_mapper:
              print("Found %0.2f%% of %s"%(pct_coverage[roi], roi))
  
      # Create cortex mask
      all_mask = np.array(list(roi_voxels.values())).sum(0)
      if 'Cortex' in roi_list:
          if use_mapper:
              # cortex_mask isn't defined / exactly definable if you're using a mapper
              print("Cortex roi not included b/c currently not compatible with your selection for gm_sampler")
              _ = roi_list.pop(roi_list.index('Cortex'))
          else:
              roi_voxels['Cortex'] = (all_mask==0) & cortex_mask
      # Optionally cull voxels assigned to > 1 ROI due to partly overlapping ROI splines
      # in inkscape overlays.svg file:
      if not allow_overlap:
          print('Cutting {} overlapping voxels (should be < ~50)'.format(np.sum(all_mask > 1)))
          for roi in roi_list:
              roi_voxels[roi][all_mask > 1] = False
      # Split left / right hemispheres if desired
      # There ought to be a more succinct way to do this - get_hemi_masks only does the cortical
      # ribbon, and is not guaranteed to have all voxels in the cortex_mask specified in this fn
      if split_lr:
          left_verts, right_verts = db.get_surf(subject, "flat", merge=False, nudge=True)
          left_mask = vox_idx < len(np.unique(left_verts[1]))
          right_mask = np.logical_not(left_mask)
          roi_voxels_lr = {}
          for roi in roi_list:
              roi_voxels_lr[roi+'_L'] = copy.copy(roi_voxels[roi]) # & left_mask
              roi_voxels_lr[roi+'_L'][right_mask] = False # ?
              roi_voxels_lr[roi+'_R'] = copy.copy(roi_voxels[roi]) # & right_mask
              roi_voxels_lr[roi+'_R'][left_mask] = False # ?
          output = roi_voxels_lr
      else:
          output = roi_voxels
  
      # Check percent coverage / optionally cull emtpy ROIs
      for roi in set(roi_list)-set(['Cortex']):
          if pct_coverage[roi] < 100:
              # if not np.any(mask) : reject ROI
              if pct_coverage[roi]==0:
                  warnings.warn('ROI %s is entirely missing from your scan protocol!'%(roi))
                  if exclude_empty_rois:
                      if split_lr:
                          _ = output.pop(roi+'_L')
                          _ = output.pop(roi+'_R')
                      else:
                          _ = output.pop(roi)
              else:
                  # I think this is the only one for which this works correctly...
                  if gm_sampler=='cortical-conservative':
                      warnings.warn('ROI %s is only %0.2f%% contained in your scan protocol!'%(roi, pct_coverage[roi]))
  
      # Support alternative outputs for backward compatibility
      if return_dict:
          return output
      else:
          idx_vol = np.zeros(vox_idx.shape, dtype=np.int64)
          idx_labels = {}
          for iroi, roi in enumerate(roi_list, 1):
              idx_vol[roi_voxels[roi]] = iroi
              idx_labels[roi] = iroi
          idx_vol[left_mask] *= -1
          return idx_vol, idx_labels
function_tokens: def get_roi_masks ( subject , xfmname , roi_list = None , gm_sampler = 'cortical' , split_lr = False , allow_overlap = False , fail_for_missing_rois = True , exclude_empty_rois = False , threshold = None , return_dict = True , overlay_file = None ) : # Convert mapper names to pycortex sampler types mapper_dict = { 'cortical-conservative' : 'nearest' , 'cortical-liberal' : 'line_nearest' } # Method use_mapper = gm_sampler in mapper_dict use_cortex_mask = ( gm_sampler in ( 'cortical' , 'thick' , 'thin' ) ) or not isinstance ( gm_sampler , string_types ) if not ( use_mapper or use_cortex_mask ) : raise ValueError ( 'Unknown gray matter sampler (gm_sampler)!' ) # Initialize roi_voxels = { } pct_coverage = { } # Catch single-ROI input if isinstance ( roi_list , string_types ) : roi_list = [ roi_list ] if not return_dict : split_lr = True if use_mapper and threshold is None : raise Exception ( "You must set a threshold for gm_mapper='%s' if you want an indexed volume output" % gm_mapper ) # Start with vertices if roi_list is None : roi_verts = get_roi_verts ( subject , mask = use_mapper , overlay_file = overlay_file ) roi_list = list ( roi_verts . keys ( ) ) else : tmp_list = [ r for r in roi_list if not r == 'Cortex' ] try : roi_verts = get_roi_verts ( subject , roi = tmp_list , mask = use_mapper , overlay_file = overlay_file ) except KeyError as key : if fail_for_missing_rois : raise KeyError ( "Requested ROI {} not found in overlays.svg!" . format ( key ) ) else : roi_verts = get_roi_verts ( subject , roi = None , mask = use_mapper , overlay_file = overlay_file ) missing = [ r for r in roi_list if not r in roi_verts . keys ( ) + [ 'Cortex' ] ] roi_verts = dict ( ( roi , verts ) for roi , verts in roi_verts . items ( ) if roi in roi_list ) roi_list = list ( set ( roi_list ) - set ( missing ) ) print ( 'Requested ROI(s) {} not found in overlays.svg!' . format ( missing ) ) # Get (a) indices for nearest vertex to each voxel # and (b) distance from each voxel to nearest vertex in fiducial surface if ( use_cortex_mask or split_lr ) or ( not return_dict ) : vox_dst , vox_idx = get_vox_dist ( subject , xfmname ) if use_mapper : mapper = get_mapper ( subject , xfmname , type = mapper_dict [ gm_sampler ] ) elif use_cortex_mask : if isinstance ( gm_sampler , string_types ) : cortex_mask = db . get_mask ( subject , xfmname , type = gm_sampler ) else : cortex_mask = vox_dst <= gm_sampler # Loop over ROIs to map vertices to volume, using mapper or cortex mask + vertex indices for roi in roi_list : if roi not in roi_verts : if not roi == 'Cortex' : print ( "ROI {} not found..." . format ( roi ) ) continue if use_mapper : roi_voxels [ roi ] = mapper . backwards ( roi_verts [ roi ] . astype ( np . float ) ) # Optionally threshold probablistic values returned by mapper if threshold is not None : roi_voxels [ roi ] = roi_voxels [ roi ] > threshold # Check for partial / empty rois: vert_in_scan = np . hstack ( [ np . array ( ( m > 0 ) . sum ( 1 ) ) . flatten ( ) for m in mapper . masks ] ) vert_in_scan = vert_in_scan [ roi_verts [ roi ] ] elif use_cortex_mask : vox_in_roi = np . in1d ( vox_idx . flatten ( ) , roi_verts [ roi ] ) . reshape ( vox_idx . shape ) roi_voxels [ roi ] = vox_in_roi & cortex_mask # This is not accurate... because vox_idx only contains the indices of the *nearest* # vertex to each voxel, it excludes many vertices. I can't think of a way to compute # this accurately for non-mapper gm_samplers for now... ML 2017.07.14 vert_in_scan = np . in1d ( roi_verts [ roi ] , vox_idx [ cortex_mask ] ) # Compute ROI coverage pct_coverage [ roi ] = vert_in_scan . mean ( ) * 100 if use_mapper : print ( "Found %0.2f%% of %s" % ( pct_coverage [ roi ] , roi ) ) # Create cortex mask all_mask = np . array ( list ( roi_voxels . values ( ) ) ) . sum ( 0 ) if 'Cortex' in roi_list : if use_mapper : # cortex_mask isn't defined / exactly definable if you're using a mapper print ( "Cortex roi not included b/c currently not compatible with your selection for gm_sampler" ) _ = roi_list . pop ( roi_list . index ( 'Cortex' ) ) else : roi_voxels [ 'Cortex' ] = ( all_mask == 0 ) & cortex_mask # Optionally cull voxels assigned to > 1 ROI due to partly overlapping ROI splines # in inkscape overlays.svg file: if not allow_overlap : print ( 'Cutting {} overlapping voxels (should be < ~50)' . format ( np . sum ( all_mask > 1 ) ) ) for roi in roi_list : roi_voxels [ roi ] [ all_mask > 1 ] = False # Split left / right hemispheres if desired # There ought to be a more succinct way to do this - get_hemi_masks only does the cortical # ribbon, and is not guaranteed to have all voxels in the cortex_mask specified in this fn if split_lr : left_verts , right_verts = db . get_surf ( subject , "flat" , merge = False , nudge = True ) left_mask = vox_idx < len ( np . unique ( left_verts [ 1 ] ) ) right_mask = np . logical_not ( left_mask ) roi_voxels_lr = { } for roi in roi_list : roi_voxels_lr [ roi + '_L' ] = copy . copy ( roi_voxels [ roi ] ) # & left_mask roi_voxels_lr [ roi + '_L' ] [ right_mask ] = False # ? roi_voxels_lr [ roi + '_R' ] = copy . copy ( roi_voxels [ roi ] ) # & right_mask roi_voxels_lr [ roi + '_R' ] [ left_mask ] = False # ? output = roi_voxels_lr else : output = roi_voxels # Check percent coverage / optionally cull emtpy ROIs for roi in set ( roi_list ) - set ( [ 'Cortex' ] ) : if pct_coverage [ roi ] < 100 : # if not np.any(mask) : reject ROI if pct_coverage [ roi ] == 0 : warnings . warn ( 'ROI %s is entirely missing from your scan protocol!' % ( roi ) ) if exclude_empty_rois : if split_lr : _ = output . pop ( roi + '_L' ) _ = output . pop ( roi + '_R' ) else : _ = output . pop ( roi ) else : # I think this is the only one for which this works correctly... if gm_sampler == 'cortical-conservative' : warnings . warn ( 'ROI %s is only %0.2f%% contained in your scan protocol!' % ( roi , pct_coverage [ roi ] ) ) # Support alternative outputs for backward compatibility if return_dict : return output else : idx_vol = np . zeros ( vox_idx . shape , dtype = np . int64 ) idx_labels = { } for iroi , roi in enumerate ( roi_list , 1 ) : idx_vol [ roi_voxels [ roi ] ] = iroi idx_labels [ roi ] = iroi idx_vol [ left_mask ] *= - 1 return idx_vol , idx_labels