docs: def sad(patch, cols, splits, clean=True):
      """
      Calculates an empirical species abundance distribution
  
      Parameters
      ----------
      {0}
      clean : bool
          If True, all species with zero abundance are removed from SAD results.
          Default False.
  
      Returns
      -------
      {1} Result has two columns: spp (species identifier) and y (individuals of
      that species).
  
      Notes
      -----
      {2}
  
      {3}
  
      Examples
      --------
  
      {4}
  
      >>> # Get the SAD of the full plot
      >>> sad = meco.empirical.sad(pat, 'spp_col:spp; count_col:count', '')
  
      >>> # Extract the SAD
      >>> sad_df = sad[0][1]
      >>> sad_df
             spp     y
      0    arsp1     2
      1     cabr    31
      2   caspi1    58
      3     chst     1
      4    comp1     5
      5     cran     4
      6     crcr    65
      7    crsp2    79
      8     enfa     1
      9     gnwe    41
      10   grass  1110
      11   lesp1     1
      12    magl     1
      13    mesp     6
      14    mobe     4
      15    phdi   210
      16   plsp1     1
      17    pypo    73
      18    sasp     2
      19    ticr   729
      20   unsh1     1
      21   unsp1    18
      22   unsp3     1
      23   unsp4     1
  
      >>> # Get SAD for 4 subplots within the full plot and keep absent species
      >>> # using clean = False
      >>> sad_subplots = meco.empirical.sad(pat, 'spp_col:spp; count_col:count', splits = "row:2; column:2", clean=False)
      >>> len(sad_subplots)
      4
  
      >>> # Look at SAD in one of the 4 cells
      >>> sad_subplots[0]
      ('row>=-0.5; row<1.5; column>=-0.5; column<1.5',
             spp    y
      0    arsp1    0
      1     cabr    7
      2   caspi1    0
      3     chst    1
      4    comp1    1
      5     cran    3
      6     crcr   21
      7    crsp2   16
      8     enfa    0
      9     gnwe    8
      10   grass  236
      11   lesp1    0
      12    magl    0
      13    mesp    4
      14    mobe    0
      15    phdi   33
      16   plsp1    1
      17    pypo    8
      18    sasp    2
      19    ticr  317
      20   unsh1    1
      21   unsp1    0
      22   unsp3    1
      23   unsp4    1)
  
      See http://www.macroeco.org/tutorial_macroeco.html for additional
      examples and explanation
  
      """
  
      (spp_col, count_col), patch = \
          _get_cols(['spp_col', 'count_col'], cols, patch)
  
      full_spp_list = np.unique(patch.table[spp_col])
  
      # Loop through each split
      result_list = []
      for substring, subpatch in _yield_subpatches(patch, splits):
  
          # Get abundance for each species
          sad_list = []
          for spp in full_spp_list:
              this_spp = (subpatch.table[spp_col] == spp)
              count = np.sum(subpatch.table[count_col][this_spp])
              sad_list.append(count)
  
          # Create dataframe of spp names and abundances
          subdf = pd.DataFrame({'spp': full_spp_list, 'y': sad_list})
  
          # Remove zero abundance rows if requested
          if clean:
              subdf = subdf[subdf['y'] > 0]
  
          # Append subset result
          result_list.append((substring, subdf))
  
      # Return all results
      return result_list