docs: def by_col(cls, df, e, b, x_grid, y_grid, geom_col='geometry', **kwargs):
          """
          Compute smoothing by columns in a dataframe. The bounding box and point
          information is computed from the geometry column.
  
          Parameters
          -----------
          df      :  pandas.DataFrame
                     a dataframe containing the data to be smoothed
          e       :  string or list of strings
                     the name or names of columns containing event variables to be
                     smoothed
          b       :  string or list of strings
                     the name or names of columns containing the population
                     variables to be smoothed
          x_grid  :  integer
                     number of grid cells to use along the x-axis
          y_grid  :  integer
                     number of grid cells to use along the y-axis
          geom_col:  string
                     the name of the column in the dataframe containing the
                     geometry information.
          **kwargs:  optional keyword arguments
                     optional keyword options that are passed directly to the
                     smoother.
          Returns
          ---------
          a new dataframe of dimension (x_grid*y_grid, 3), containing the
          coordinates of the grid cells and the rates associated with those grid
          cells.
          """
          import pandas as pd
          # prep for application over multiple event/population pairs
          if isinstance(e, str):
              e = [e]
          if isinstance(b, str):
              b = [b]
          if len(e) > len(b):
              b = b * len(e)
          if isinstance(x_grid, (int, float)):
              x_grid = [x_grid] * len(e)
          if isinstance(y_grid, (int, float)):
              y_grid = [y_grid] * len(e)
  
          bbox = get_bounding_box(df[geom_col])
          bbox = [[bbox.left, bbox.lower], [bbox.right, bbox.upper]]
          data = get_points_array(df[geom_col])
          res = []
          for ename, bname, xgi, ygi in zip(e, b, x_grid, y_grid):
              r = cls(bbox, data, df[ename], df[bname], xgi, ygi, **kwargs)
              grid = np.asarray(r.grid).reshape(-1,2)
              name = '_'.join(('-'.join((ename, bname)), cls.__name__.lower()))
              colnames = ('_'.join((name, suffix)) for suffix in ['X', 'Y', 'R'])
              items = [(name, col) for name,col in zip(colnames, [grid[:,0],
                                                                  grid[:,1],
                                                                  r.r])]
              res.append(pd.DataFrame.from_items(items))
          outdf = pd.concat(res)
          return outdf