docs: def load_variables(layout, types=None, levels=None, skip_empty=True,
                     dataset=None, scope='all', **kwargs):
      ''' A convenience wrapper for one or more load_*_variables() calls.
  
      Args:
          layout (BIDSLayout): BIDSLayout containing variable files.
          types (str, list): Types of variables to retrieve. All valid values
              reflect the filename stipulated in the BIDS spec for each kind of
              variable. Valid values include: 'events', 'physio', 'stim',
              'scans', 'participants', 'sessions', and 'regressors'.
          levels (str, list): Optional level(s) of variables to load. Valid
              values are 'run', 'session', 'subject', or 'dataset'. This is
              simply a shorthand way to specify types--e.g., 'run' will be
              converted to types=['events', 'physio', 'stim', 'regressors'].
          skip_empty (bool): Whether or not to skip empty Variables (i.e.,
              where there are no rows/records in a file after applying any
              filtering operations like dropping NaNs).
          dataset (NodeIndex): An existing NodeIndex container to store the
              loaded data in. Can be used to iteratively construct a dataset
              that contains otherwise heterogeneous sets of variables. If None,
              a new NodeIndex is used.
          scope (str, list): The scope of the space to search for variables. See
              docstring for BIDSLayout for details and valid predefined values.
          kwargs: Optional keyword arguments to pass onto the individual
              load_*_variables() calls.
  
      Returns:
          A NodeIndex instance.
  
      Example:
          >>> load_variables(layout, ['events', 'physio'], subject='01')
          # returns all variables stored in _events.tsv and _physio.tsv.gz files
          # for runs that belong to subject with id '01'.
      '''
  
      TYPES = ['events', 'physio', 'stim', 'scans', 'participants', 'sessions',
               'regressors']
  
      types = listify(types)
  
      if types is None:
          if levels is not None:
              types = []
              lev_map = {
                  'run': ['events', 'physio', 'stim', 'regressors'],
                  'session': ['scans'],
                  'subject': ['sessions'],
                  'dataset': ['participants']
              }
              [types.extend(lev_map[l.lower()]) for l in listify(levels)]
          else:
              types = TYPES
  
      bad_types = set(types) - set(TYPES)
      if bad_types:
          raise ValueError("Invalid variable types: %s" % bad_types)
  
      dataset = dataset or NodeIndex()
  
      run_types = list({'events', 'physio', 'stim', 'regressors'} - set(types))
      type_flags = {t: False for t in run_types}
      if len(type_flags) < 4:
          _kwargs = kwargs.copy()
          _kwargs.update(type_flags)
          dataset = _load_time_variables(layout, dataset, scope=scope, **_kwargs)
  
      for t in ({'scans', 'sessions', 'participants'} & set(types)):
          kwargs.pop('suffix', None) # suffix is always one of values aboves
          dataset = _load_tsv_variables(layout, t, dataset, scope=scope,
                                        **kwargs)
  
      return dataset