docstr: Explain instance and return counterfactual with metadata.
  
  Parameters
  ----------
  X
      Instances to attack.
  Y
      Labels for `X` as one-hot-encoding.
  target_class
      List with target classes used to find closest prototype. If ``None``, the nearest prototype
      except for the predict class on the instance is used.
  k
      Number of nearest instances used to define the prototype for a class. Defaults to using all
      instances belonging to the class if an encoder is used and to 1 for k-d trees.
  k_type
      Use either the average encoding of the `k` nearest instances in a class (``k_type='mean'``) or
      the k-nearest encoding in the class (``k_type='point'``) to define the prototype of that class.
      Only relevant if an encoder is used to define the prototypes.
  threshold
      Threshold level for the ratio between the distance of the counterfactual to the prototype of the
      predicted class for the original instance over the distance to the prototype of the predicted class
      for the counterfactual. If the trust score is below the threshold, the proposed counterfactual does
      not meet the requirements.
  verbose
      Print intermediate results of optimization if ``True``.
  print_every
      Print frequency if verbose is ``True``.
  log_every
      `tensorboard` log frequency if write directory is specified
  
  Returns
  -------
  explanation
      `Explanation` object containing the counterfactual with additional metadata as attributes.
      See usage at `CFProto examples`_ for details.
  
      .. _CFProto examples:
          https://docs.seldon.io/projects/alibi/en/stable/methods/CFProto.html
docstr_tok: ["Explain","instance","and","return","counterfactual","with","metadata",".","Parameters","--","--","--","--","--","X","Instances","to","attack",".","Y","Labels","for","`","X","`","as","one-hot-encoding",".","target_class","List","with","target","classes","used","to","find","closest","prototype",".","If","``","None","``",",","the","nearest","prototype","except","for","the","predict","class","on","the","instance","is","used",".","k","Number","of","nearest","instances","used","to","define","the","prototype","for","a","class",".","Defaults","to","using","all","instances","belonging","to","the","class","if","an","encoder","is","used","and","to","1","for","k-d","trees",".","k_type","Use","either","the","average","encoding","of","the","`","k","`","nearest","instances","in","a","class","(","``","k_type='mean","'","``",")","or","the","k-nearest","encoding","in","the","class","(","``","k_type='point","'","``",")","to","define","the","prototype","of","that","class",".","Only","relevant","if","an","encoder","is","used","to","define","the","prototypes",".","threshold","Threshold","level","for","the","ratio","between","the","distance","of","the","counterfactual","to","the","prototype","of","the","predicted","class","for","the","original","instance","over","the","distance","to","the","prototype","of","the","predicted","class","for","the","counterfactual",".","If","the","trust","score","is","below","the","threshold",",","the","proposed","counterfactual","does","not","meet","the","requirements",".","verbose","Print","intermediate","results","of","optimization","if","``","True","``",".","print_every","Print","frequency","if","verbose","is","``","True","``",".","log_every","`","tensorboard","`","log","frequency","if","write","directory","is","specified","Returns","--","--","--","-","explanation","`","Explanation","`","object","containing","the","counterfactual","with","additional","metadata","as","attributes",".","See","usage","at","`","CFProto","examples","`","_","for","details",".","..","_CFProto","examples",":","https",":","\/\/docs.seldon.io\/projects\/alibi\/en\/stable\/methods\/CFProto.html"]
code: def explain(
      self,
      X: np.ndarray,
      Y: Optional[np.ndarray] = None,
      target_class: Optional[list] = None,
      k: Optional[int] = None,
      k_type: str = "mean",
      threshold: float = 0.0,
      verbose: bool = False,
      print_every: int = 100,
      log_every: int = 100,
  ) -> Explanation:
      """
      Explain instance and return counterfactual with metadata.
  
      Parameters
      ----------
      X
          Instances to attack.
      Y
          Labels for `X` as one-hot-encoding.
      target_class
          List with target classes used to find closest prototype. If ``None``, the nearest prototype
          except for the predict class on the instance is used.
      k
          Number of nearest instances used to define the prototype for a class. Defaults to using all
          instances belonging to the class if an encoder is used and to 1 for k-d trees.
      k_type
          Use either the average encoding of the `k` nearest instances in a class (``k_type='mean'``) or
          the k-nearest encoding in the class (``k_type='point'``) to define the prototype of that class.
          Only relevant if an encoder is used to define the prototypes.
      threshold
          Threshold level for the ratio between the distance of the counterfactual to the prototype of the
          predicted class for the original instance over the distance to the prototype of the predicted class
          for the counterfactual. If the trust score is below the threshold, the proposed counterfactual does
          not meet the requirements.
      verbose
          Print intermediate results of optimization if ``True``.
      print_every
          Print frequency if verbose is ``True``.
      log_every
          `tensorboard` log frequency if write directory is specified
  
      Returns
      -------
      explanation
          `Explanation` object containing the counterfactual with additional metadata as attributes.
          See usage at `CFProto examples`_ for details.
  
          .. _CFProto examples:
              https://docs.seldon.io/projects/alibi/en/stable/methods/CFProto.html
      """
      # get params for storage in meta
      params = locals()
      remove = ["self", "X", "Y"]
      for key in remove:
          params.pop(key)
  
      if X.shape[0] != 1:
          logger.warning(
              "Currently only single instance explanations supported (first dim = 1), "
              "but first dim = %s",
              X.shape[0],
          )
  
      # output explanation dictionary
      data = copy.deepcopy(DEFAULT_DATA_CFP)
  
      if Y is None:
          if self.model:
              Y_proba = self.predict.predict(X)  # type: ignore
          else:
              Y_proba = self.predict(X)
          Y_ohe = np.zeros(Y_proba.shape)
          Y_class = np.argmax(Y_proba, axis=1)
          Y_ohe[np.arange(Y_proba.shape[0]), Y_class] = 1
          Y = Y_ohe.copy()
          data["orig_proba"] = Y_proba
      else:  # provided one-hot-encoding of prediction on X
          data["orig_proba"] = None
      data["orig_class"] = np.argmax(Y, axis=1)[0]
  
      # find best counterfactual
      self.best_attack = False
      best_attack, grads = self.attack(
          X,
          Y=Y,
          target_class=target_class,
          k=k,
          k_type=k_type,
          verbose=verbose,
          threshold=threshold,
          print_every=print_every,
          log_every=log_every,
      )
  
      if self.enc_or_kdtree:
          data["id_proto"] = self.id_proto
  
      # add to explanation dict
      if not self.best_attack:
          logger.warning("No counterfactual found!")
  
          # create explanation object
          explanation = Explanation(
              meta=copy.deepcopy(self.meta), data=data
          )
          return explanation
  
      data["all"] = self.cf_global
      data["cf"] = {}
      data["cf"]["X"] = best_attack
      if self.model:
          Y_pert = self.predict.predict(best_attack)  # type: ignore
      else:
          Y_pert = self.predict(best_attack)
      data["cf"]["class"] = np.argmax(Y_pert, axis=1)[0]
      data["cf"]["proba"] = Y_pert
      data["cf"]["grads_graph"], data["cf"]["grads_num"] = (
          grads[0],
          grads[1],
      )
  
      # create explanation object
      explanation = Explanation(
          meta=copy.deepcopy(self.meta), data=data
      )
  
      return explanation
  
imports: import copy
  import logging
  import sys
  from typing import Any, Callable, Dict, Optional, Sequence, Tuple, Union
  import numpy
  import tensorflow.compat.v1
  from alibi.api.defaults import DEFAULT_DATA_CFP, DEFAULT_META_CFP
  from alibi.api.interfaces import Explainer, Explanation, FitMixin
  from alibi.confidence import TrustScore
  from alibi.utils.discretizer import Discretizer
  from alibi.utils.distance import abdm, multidim_scaling, mvdm
  from alibi.utils.gradients import perturb
  from alibi.utils.mapping import num_to_ord, ohe_to_ord, ohe_to_ord_shape, ord_to_num, ord_to_ohe
  from alibi.utils.tf import argmax_grad, argmin_grad, one_hot_grad, round_grad
label_desc: Use image node_id 7 for calling the CounterfactualProto obj's underlying member method code with example usage: obj.explain(X, Y, target_class, k, k_type, threshold, verbose, print_every, log_every) and returns: explanation, explanation