docs: def model(self, data,
              ind_col=None, dep_col=None,
              project_ind_col=None,
              baseline_period=[None, None], projection_period=None, exclude_time_period=None,
              alphas=np.logspace(-4,1,30),
              cv=3, plot=True, figsize=None,
              custom_model_func=None):
          """ Split data into baseline and projection periods, run models on them and display metrics & plots.
  
          Parameters
          ----------
          data                    : pd.DataFrame()
              Dataframe to model.
          ind_col                 : list(str)
              Independent column(s) of dataframe. Defaults to all columns except the last.
          dep_col                 : str
              Dependent column of dataframe.
          project_ind_col         : list(str)
              Independent column(s) to use for projection. If none, use ind_col.
          baseline_period         : list(str)
              List of time periods to split the data into baseline periods. It needs to have a start and an end date.
          projection_period       : list(str)
              List of time periods to split the data into projection periods. It needs to have a start and an end date.
          exclude_time_period     : list(str)
              List of time periods to exclude for modeling.
          alphas                  : list(int)
              List of alphas to run regression on.
          cv                      : int
              Number of folds for cross-validation.
          plot                    : bool
              Specifies whether to save plots or not.
          figsize                 : tuple
              Size of the plots.
          custom_model_func       : function
              Model with specific hyper-parameters provided by user.
  
          Returns
          -------
          dict
              Metrics of the optimal/best model.
  
          """
  
          # Check to ensure data is a pandas dataframe
          if not isinstance(data, pd.DataFrame):
              raise SystemError('data has to be a pandas dataframe.')
          
          # Create instance
          model_data_obj = Model_Data(data, ind_col, dep_col, alphas, cv, exclude_time_period, baseline_period, projection_period)
  
          # Split data into baseline and projection
          model_data_obj.split_data()
  
          # Logging
          self.result['Model'] = {
              'Independent Col': ind_col,
              'Dependent Col': dep_col,
              'Projection Independent Col': project_ind_col,
              'Baseline Period': baseline_period,
              'Projection Period': projection_period,
              'Exclude Time Period': exclude_time_period,
              'Alphas': list(alphas),
              'CV': cv,
              'Plot': plot,
              'Fig Size': figsize
          }
  
          # Runs all models on the data and returns optimal model
          all_metrics = model_data_obj.run_models()
          self.result['Model']['All Model\'s Metrics'] = all_metrics
  
          # CHECK: Define custom model's parameter and return types in documentation.
          if custom_model_func:
              self.result['Model']['Custom Model\'s Metrics'] = model_data_obj.custom_model(custom_model_func)
  
          # Fit optimal model to data
          self.result['Model']['Optimal Model\'s Metrics'] = model_data_obj.best_model_fit()
  
          if plot:
  
              # Use project_ind_col if projecting into the future (no input data other than weather data)
              input_col = model_data_obj.input_col if not project_ind_col else project_ind_col
              fig, y_true, y_pred = self.plot_data_obj.baseline_projection_plot(model_data_obj.y_true, model_data_obj.y_pred, 
                                                              model_data_obj.baseline_period, model_data_obj.projection_period,
                                                              model_data_obj.best_model_name, model_data_obj.best_metrics['adj_r2'],
                                                              model_data_obj.original_data,
                                                              input_col, model_data_obj.output_col,
                                                              model_data_obj.best_model,
                                                              self.result['Site'])
  
              fig.savefig(self.results_folder_name + '/baseline_projection_plot-' + str(self.get_global_count()) + '.png')
              
              if not y_true.empty and not y_pred.empty:
                  saving_absolute = (y_pred - y_true).sum()
                  saving_perc = (saving_absolute / y_pred.sum()) * 100
                  self.result['Energy Savings (%)'] = float(saving_perc)
                  self.result['Energy Savings (absolute)'] = saving_absolute
  
                  # Temporary
                  self.project_df['true'] = y_true
                  self.project_df['pred'] = y_pred
  
                  # Calculate uncertainity of savings
                  self.result['Uncertainity'] = self.uncertainity_equation(model_data_obj, y_true, y_pred, 0.9)
              
              else:
                  print('y_true: ', y_true)
                  print('y_pred: ', y_pred)
                  print('Error: y_true and y_pred are empty. Default to -1.0 savings.')
                  self.result['Energy Savings (%)'] = float(-1.0)
                  self.result['Energy Savings (absolute)'] = float(-1.0)
          
          return self.best_metrics