docs: def pertibate(self, pertibate_columns=None, filter_func=None,
                    max_size=1000):
          """
          :param pertibate_columns: list of str fo columns to pertibate see DOE
          :param filter_func: func that takes a SeabornRow and return
                              True if this row should be exist
          :param max_size: int of the max number of rows to try
                              but some may be filtered out
          :return:  None
          """
          pertibate_columns = pertibate_columns or self.columns
          for c in pertibate_columns:
              assert c in self.columns, 'Column %s was not part of this self' % c
  
          # noinspection PyTypeChecker
          column_size = [c in pertibate_columns and len(self._parameters[c]) or 1
                         for c in self.columns]
  
          max_size = min(max_size, reduce(lambda x, y: x * y, column_size))
  
          for indexes in self._index_iterator(column_size, max_size):
              row = SeabornRow(self._column_index,
                               [self._pertibate_value(indexes.pop(0), c) for
                                c in self.columns])
  
              kwargs = row.obj_to_dict()
              if filter_func is None or filter_func(_row_index=len(self.table),
                                                    **kwargs):
                  self.table.append(row)
  
          for c in self.columns:  # if the parameter is a dynamic function
              if hasattr(self._parameters.get(c, ''), '__call__'):
                  # noinspection PyTypeChecker
                  self.set_column(c, self._parameters[c])