code: def test_explain(self):
      model_cls = LightGBMModel if lgbm_available else XGBModel
      m = model_cls(
          lags=4,
          lags_past_covariates=[-1, -2, -3],
          lags_future_covariates=[0],
          output_chunk_length=4,
          add_encoders=self.add_encoders,
      )
      m.fit(
          series=self.target_ts,
          past_covariates=self.past_cov_ts,
          future_covariates=self.fut_cov_ts,
      )
  
      shap_explain = ShapExplainer(m)
      with pytest.raises(ValueError):
          _ = shap_explain.explain(
              horizons=[1, 5]
          )  # horizon > output_chunk_length
      with pytest.raises(ValueError):
          _ = shap_explain.explain(
              horizons=[1, 2], target_components=["test"]
          )  # wrong name
  
      results = shap_explain.explain()
      with pytest.raises(ValueError):
          results.get_explanation(horizon=5, component="price")
      with pytest.raises(ValueError):
          results.get_feature_values(horizon=5, component="price")
      with pytest.raises(ValueError):
          results.get_shap_explanation_object(
              horizon=5, component="price"
          )
      with pytest.raises(ValueError):
          results.get_explanation(horizon=1, component="test")
      with pytest.raises(ValueError):
          results.get_feature_values(horizon=1, component="test")
      with pytest.raises(ValueError):
          results.get_shap_explanation_object(
              horizon=1, component="test"
          )
  
      results = shap_explain.explain(
          horizons=[1, 3], target_components=["power"]
      )
      with pytest.raises(ValueError):
          results.get_explanation(horizon=2, component="power")
      with pytest.raises(ValueError):
          results.get_feature_values(horizon=2, component="power")
      with pytest.raises(ValueError):
          results.get_shap_explanation_object(
              horizon=2, component="power"
          )
      with pytest.raises(ValueError):
          results.get_explanation(horizon=1, component="test")
      with pytest.raises(ValueError):
          results.get_feature_values(horizon=1, component="test")
      with pytest.raises(ValueError):
          results.get_shap_explanation_object(
              horizon=1, component="test"
          )
  
      explanation = results.get_explanation(
          horizon=1, component="power"
      )
      assert len(explanation) == 537
      feature_vals = results.get_feature_values(
          horizon=1, component="power"
      )
      assert len(feature_vals) == 537
  
      # list of foregrounds: encoders have to be corrected first.
      results = shap_explain.explain(
          foreground_series=[self.target_ts, self.target_ts[:100]],
          foreground_past_covariates=[
              self.past_cov_ts,
              self.past_cov_ts[:40],
          ],
          foreground_future_covariates=[
              self.fut_cov_ts,
              self.fut_cov_ts[:40],
          ],
      )
      ts_res = results.get_explanation(horizon=2, component="power")
      assert len(ts_res) == 2
      feature_vals = results.get_feature_values(
          horizon=2, component="power"
      )
      assert len(feature_vals) == 2
  
      # explain with a new foreground, minimum required. We should obtain one
      # timeseries with only one time element
      results = shap_explain.explain(
          foreground_series=self.target_ts[-5:],
          foreground_past_covariates=self.past_cov_ts[-4:],
          foreground_future_covariates=self.fut_cov_ts[-1],
      )
  
      ts_res = results.get_explanation(horizon=2, component="power")
      assert len(ts_res) == 1
      assert ts_res.time_index[-1] == pd.Timestamp(2014, 6, 5)
      feature_vals = results.get_feature_values(
          horizon=2, component="power"
      )
      assert len(feature_vals) == 1
      assert feature_vals.time_index[-1] == pd.Timestamp(2014, 6, 5)
  
      with pytest.raises(ValueError):
          results.get_explanation(horizon=5, component="price")
      with pytest.raises(ValueError):
          results.get_feature_values(horizon=5, component="price")
      with pytest.raises(ValueError):
          results.get_explanation(horizon=1, component="test")
      with pytest.raises(ValueError):
          results.get_feature_values(horizon=1, component="test")
  
      # right instance
      assert isinstance(results, ShapExplainabilityResult)
  
      components_list = [
          "price_target_lag-4",
          "power_target_lag-4",
          "price_target_lag-3",
          "power_target_lag-3",
          "price_target_lag-2",
          "power_target_lag-2",
          "price_target_lag-1",
          "power_target_lag-1",
          "0_past_cov_lag-3",
          "1_past_cov_lag-3",
          "2_past_cov_lag-3",
          "darts_enc_pc_cyc_month_sin_past_cov_lag-3",
          "darts_enc_pc_cyc_month_cos_past_cov_lag-3",
          "darts_enc_pc_cyc_day_sin_past_cov_lag-3",
          "darts_enc_pc_cyc_day_cos_past_cov_lag-3",
          "darts_enc_pc_pos_relative_past_cov_lag-3",
          "darts_enc_pc_cus_custom_past_cov_lag-3",
          "0_past_cov_lag-2",
          "1_past_cov_lag-2",
          "2_past_cov_lag-2",
          "darts_enc_pc_cyc_month_sin_past_cov_lag-2",
          "darts_enc_pc_cyc_month_cos_past_cov_lag-2",
          "darts_enc_pc_cyc_day_sin_past_cov_lag-2",
          "darts_enc_pc_cyc_day_cos_past_cov_lag-2",
          "darts_enc_pc_pos_relative_past_cov_lag-2",
          "darts_enc_pc_cus_custom_past_cov_lag-2",
          "0_past_cov_lag-1",
          "1_past_cov_lag-1",
          "2_past_cov_lag-1",
          "darts_enc_pc_cyc_month_sin_past_cov_lag-1",
          "darts_enc_pc_cyc_month_cos_past_cov_lag-1",
          "darts_enc_pc_cyc_day_sin_past_cov_lag-1",
          "darts_enc_pc_cyc_day_cos_past_cov_lag-1",
          "darts_enc_pc_pos_relative_past_cov_lag-1",
          "darts_enc_pc_cus_custom_past_cov_lag-1",
          "0_fut_cov_lag0",
          "1_fut_cov_lag0",
          "hour_fut_cov_lag0",
          "dayofweek_fut_cov_lag0",
          "relative_idx_fut_cov_lag0",
      ]
  
      results = shap_explain.explain()
  
      # all the features explained are here, in the right order
      assert [
          results.get_explanation(i, "price").components.to_list()
          == components_list
          for i in range(1, 5)
      ]
  
      # No past or future covariates
      m = LinearRegressionModel(
          lags=1,
          output_chunk_length=2,
      )
      m.fit(
          series=self.target_ts,
      )
      shap_explain = ShapExplainer(m)
  
      assert isinstance(
          shap_explain.explain(), ShapExplainabilityResult
      )
  
imports: import copy
  from datetime import date, timedelta
  import matplotlib.pyplot
  import numpy
  import pandas
  import pytest
  import shap
  import sklearn
  from dateutil.relativedelta import relativedelta
  from numpy.testing import assert_array_equal
  from sklearn.preprocessing import MinMaxScaler
  from darts import TimeSeries
  from darts.dataprocessing.transformers import Scaler
  from darts.explainability.explainability_result import ShapExplainabilityResult
  from darts.explainability.shap_explainer import MIN_BACKGROUND_SAMPLE, ShapExplainer
  from darts.models import CatBoostModel, ExponentialSmoothing, LightGBMModel, LinearRegressionModel, NotImportedModule, RegressionModel, XGBModel
  from darts.utils.timeseries_generation import linear_timeseries
label_desc: Use image node_id 2 for calling the TestShapExplainer obj's underlying member method code with example usage: obj.test_explain() without return types