docs: def get_min_max_lat_lon(self):
          """
          Find latitude/longitude information from sites table
          and group it by location.
  
          Returns
          ---------
          """
          if 'sites' not in self.tables:
              return
          # get min/max lat/lon from sites table
          site_container = self.tables['sites']
          if not ('lat' in site_container.df.columns and 'lon' in site_container.df.columns):
              return
          # convert lat/lon columns to string type
          # (this is necessary for consistency because they MAY be string type already)
          site_container.df['lat'] = site_container.df['lat'].fillna('').astype(str)
          site_container.df['lon'] = site_container.df['lon'].fillna('').astype(str)
          # replace empty strings with np.nan
          site_container.df['lat'] = np.where(site_container.df['lat'].str.len(), site_container.df['lat'], np.nan)
          site_container.df['lon'] = np.where(site_container.df['lon'].str.len(), site_container.df['lon'], np.nan)
          # convert lat/lon values to float (they make be string from grid)
          try:
              site_container.df['lat'] = site_container.df['lat'].astype(float)
          except ValueError as ex:
              print('-W- Improperly formatted numbers in sites.lat')
              return
          try:
              site_container.df['lon'] = site_container.df['lon'].astype(float)
          except ValueError as ex:
              print('-W- Improperly formatted numbers in sites.lon')
              return
          # group lat/lon by location
          grouped_lon = site_container.df[['lon', 'location']].groupby('location')
          grouped_lat = site_container.df[['lat', 'location']].groupby('location')
          # get min/max longitude by location
          lon_w = grouped_lon.min()
          lon_e = grouped_lon.max()
          # get min/max latitude by location
          lat_s = grouped_lat.min()
          lat_n = grouped_lat.max()
          # assign lat/lon to location table
          locs = {}
          if 'locations' not in self.tables:
              return
          loc_container = self.tables['locations']
          for loc in lat_s.index:
              coords = {}
              coords['lat_s'] = lat_s.loc[loc]['lat']
              coords['lat_n'] = lat_n.loc[loc]['lat']
              coords['lon_e'] = lon_e.loc[loc]['lon']
              coords['lon_w'] = lon_w.loc[loc]['lon']
              locs[loc] = coords
          loc_container = self.tables['locations']
          for loc_name in locs:
              if loc_name in loc_container.df.index:
                  coords = locs[loc_name]
                  for coord in locs[loc_name]:
                      # warn user if an old value will be overwritten
                      new_value = coords[coord]
                      # if the new value is null, ignore it
                      if is_null(new_value, zero_as_null=False):
                          continue
                      # set old value to None if it wasn't in table
                      if coord not in loc_container.df.columns:
                          loc_container.df[coord] = None
                      old_value = loc_container.df.loc[loc_name, coord]
                      # use first value if multiple values returned, but don't shorten a string
                      if not (isinstance(old_value, str)):
                          try:
                              old_value = old_value.values.astype(str)[0]
                          except (TypeError,IndexError,AttributeError) as e: # if only one value, or np.nan, or NoneType
                              pass
                      if is_null(old_value, zero_as_null=False):
                          pass
                      elif isinstance(old_value, str):
                          try:
                              old_value = float(old_value)
                          except ValueError:
                              print('-W- In {}, automatically generated {} value ({}) will overwrite previous value ({})'.format(loc_name, coord, new_value, old_value))
                              old_value = None
                      elif not math.isclose(new_value, old_value):
                          print('-W- In {}, automatically generated {} value ({}) will overwrite previous value ({})'.format(loc_name, coord, new_value, old_value))
                      # set new value
                      new_value = round(float(new_value), 5)
                      loc_container.df.loc[loc_name, coord] = new_value
          self.write_table_to_file('locations')
          return locs