code: def __call__(
      self,
      name,
      explanation,
      *model_args,
      percent=0.01,
      indices=[],
      y=None,
      label=None,
      silent=False,
      debug_mode=False,
      batch_size=10,
  ):
      # if explainer is already the attributions
      if isinstance(explanation, np.ndarray):
          attributions = explanation
      elif isinstance(explanation, Explanation):
          attributions = explanation.values
      else:
          raise ValueError(
              "The passed explanation must be either of type numpy.ndarray or shap.Explanation!"
          )
  
      assert len(attributions) == len(
          model_args[0]
      ), "The explanation passed must have the same number of rows as the model_args that were passed!"
  
      if label is None:
          label = "Score %d" % len(self.score_values)
  
      # convert dataframes
      # if isinstance(X, (pd.Series, pd.DataFrame)):
      #     X = X.values
  
      # convert all single-sample vectors to matrices
      # if not hasattr(attributions[0], "__len__"):
      #     attributions = np.array([attributions])
      # if not hasattr(X[0], "__len__") and self.data_type == "tabular":
      #     X = np.array([X])
  
      pbar = None
      start_time = time.time()
      svals = []
      mask_vals = []
  
      for i, args in enumerate(zip(*model_args)):
          # if self.data_type == "image":
          #     x_shape, y_shape = attributions[i].shape[0], attributions[i].shape[1]
          #     feature_size = np.prod([x_shape, y_shape])
          #     sample_attributions = attributions[i].mean(2).reshape(feature_size, -1)
          #     data = X[i].flatten()
          #     mask_shape = X[i].shape
          # else:
          feature_size = np.prod(attributions[i].shape)
          sample_attributions = attributions[i].flatten()
          # data = X[i]
          # mask_shape = feature_size
  
          self.masked_model = MaskedModel(
              self.model,
              self.masker,
              links.identity,
              self.linearize_link,
              *args,
          )
  
          masks = []
  
          mask = np.ones(feature_size, dtype=bool) * (
              self.perturbation == "remove"
          )
          masks.append(mask.copy())
  
          ordered_inds = self.sort_order_map(sample_attributions)
          increment = max(1, int(feature_size * percent))
          for j in range(0, feature_size, increment):
              oind_list = [
                  ordered_inds[t]
                  for t in range(j, min(feature_size, j + increment))
              ]
  
              for oind in oind_list:
                  if not (
                      (
                          self.sort_order == "positive"
                          and sample_attributions[oind] <= 0
                      )
                      or (
                          self.sort_order == "negative"
                          and sample_attributions[oind] >= 0
                      )
                  ):
                      mask[oind] = self.perturbation == "keep"
  
              masks.append(mask.copy())
  
          mask_vals.append(masks)
  
          # mask_size = len(range(0, feature_size, increment)) + 1
          values = []
          masks_arr = np.array(masks)
          for j in range(0, len(masks_arr), batch_size):
              values.append(
                  self.masked_model(masks_arr[j : j + batch_size])
              )
          values = np.concatenate(values)
  
          svals.append(values)
  
          if pbar is None and time.time() - start_time > 5:
              pbar = tqdm(
                  total=len(model_args[0]),
                  disable=silent,
                  leave=False,
                  desc="SequentialMasker",
              )
              pbar.update(i + 1)
          if pbar is not None:
              pbar.update(1)
  
      if pbar is not None:
          pbar.close()
  
      self.score_values.append(np.array(svals))
  
      # if self.sort_order == "negative":
      #     curve_sign = -1
      # else:
      curve_sign = 1
  
      self.labels.append(label)
  
      xs = np.linspace(0, 1, 100)
      curves = np.zeros((len(self.score_values[-1]), len(xs)))
      for j in range(len(self.score_values[-1])):
          xp = np.linspace(0, 1, len(self.score_values[-1][j]))
          yp = self.score_values[-1][j]
          curves[j, :] = np.interp(xs, xp, yp)
      ys = curves.mean(0)
      std = curves.std(0) / np.sqrt(curves.shape[0])
      auc = sklearn.metrics.auc(
          np.linspace(0, 1, len(ys)), curve_sign * (ys - ys[0])
      )
  
      if not debug_mode:
          return BenchmarkResult(
              self.perturbation + " " + self.sort_order,
              name,
              curve_x=xs,
              curve_y=ys,
              curve_y_std=std,
          )
      else:
          aucs = []
          for j in range(len(self.score_values[-1])):
              curve = curves[j, :]
              auc = sklearn.metrics.auc(
                  np.linspace(0, 1, len(curve)),
                  curve_sign * (curve - curve[0]),
              )
              aucs.append(auc)
          return mask_vals, curves, aucs
  
file_path: shap/shap/benchmark/_sequential.py
imports: import time
  import matplotlib.pyplot
  import numpy
  import pandas
  import sklearn
  from tqdm.auto import tqdm
  from shap import Explanation, links
  from shap.maskers import FixedComposite, Image, Text
  from shap.utils import MaskedModel
  from ._result import BenchmarkResult
label_desc: Use image node_id 2 for calling the SequentialPerturbation obj's underlying member method code with example usage: obj.__call__(name, explanation) and returns: BenchmarkResult, mask_vals,  curves,  aucs