class_docstr: SmartPlotter is a Bridge pattern decoupling plotting functions from SmartExplainer.
  The smartplotter class includes all the methods used to display graphics
  Each SmartPlotter method is easy to use from a Smart explainer object,
  just use the following syntax
  Attributes :
  explainer: object
      SmartExplainer instance to point to.
  Example
  --------
  >>> xpl.plot.my_plot_method(param=value)
class_docstr_tok: ["SmartPlotter","is","a","Bridge","pattern","decoupling","plotting","functions","from","SmartExplainer",".","The","smartplotter","class","includes","all","the","methods","used","to","display","graphics","Each","SmartPlotter","method","is","easy","to","use","from","a","Smart","explainer","object",",","just","use","the","following","syntax","Attributes",":","explainer",":","object","SmartExplainer","instance","to","point","to",".","Example","--","--","--","--",">",">",">","xpl.plot.my_plot_method","(","param=value",")"]
docstr: The Local_neighbors_plot has the main objective of increasing confidence         in interpreting the contribution values of a selected instance.
  This plot analyzes the local neighborhood of the instance,         and compares its contribution values with those of its neighbors.
  Intuitively, for similar instances, we would expect similar contributions.
  Those neighbors are selected as follows :
  * We select top N neighbors for each instance (using L1 norm + variance normalization)
  * We discard neighbors whose model output is too **different** (see equations below)
  from the instance output
  * We discard additional neighbors if their distance to the instance         is bigger than a predefined value (to remove outliers)
  In this neighborhood, we would expect instances to have similar SHAP values.         If not, one might need to be cautious when interpreting SHAP values.
  The **difference** between outputs is measured with the following distance definition :
  * For regression:
  .. math::
      distance = \frac{|output_{allFeatures} -
                        output_{currentFeatures}|}{|output_{allFeatures}|}
  * For classification:
  .. math::
      distance = |output_{allFeatures} - output_{currentFeatures}|
  Parameters
  ----------
  index: int
      Contains index row of the input DataFrame that we use to display contribution values in the neighborhood
  max_features: int, optional
      Maximum number of displayed features, by default 10
  file_name: string, optional
      Specify the save path of html files. If it is not provided, no file will be saved, by default None
  auto_open: bool, optional
      open automatically the plot, by default False
  Returns
  -------
  fig
      The figure that will be displayed
code: def local_neighbors_plot(
      self, index, max_features=10, file_name=None, auto_open=False
  ):
      """
          The Local_neighbors_plot has the main objective of increasing confidence \
          in interpreting the contribution values of a selected instance.
          This plot analyzes the local neighborhood of the instance, \
          and compares its contribution values with those of its neighbors.
          Intuitively, for similar instances, we would expect similar contributions.
          Those neighbors are selected as follows :
          * We select top N neighbors for each instance (using L1 norm + variance normalization)
          * We discard neighbors whose model output is too **different** (see equations below)
          from the instance output
          * We discard additional neighbors if their distance to the instance \
          is bigger than a predefined value (to remove outliers)
          In this neighborhood, we would expect instances to have similar SHAP values. \
          If not, one might need to be cautious when interpreting SHAP values.
          The **difference** between outputs is measured with the following distance definition :
          * For regression:
          .. math::
              distance = \\frac{|output_{allFeatures} -
                                output_{currentFeatures}|}{|output_{allFeatures}|}
          * For classification:
          .. math::
              distance = |output_{allFeatures} - output_{currentFeatures}|
          Parameters
          ----------
          index: int
              Contains index row of the input DataFrame that we use to display contribution values in the neighborhood
          max_features: int, optional
              Maximum number of displayed features, by default 10
          file_name: string, optional
              Specify the save path of html files. If it is not provided, no file will be saved, by default None
          auto_open: bool, optional
              open automatically the plot, by default False
          Returns
          -------
          fig
              The figure that will be displayed
          """
      assert (
          index in self.explainer.x_init.index
      ), "index must exist in pandas dataframe"
  
      self.explainer.compute_features_stability([index])
  
      column_names = np.array(
          [
              self.explainer.features_dict.get(x)
              for x in self.explainer.x_init.columns
          ]
      )
  
      def ordinal(n):
          return "%d%s" % (
              n,
              "tsnrhtdd"[
                  (math.floor(n / 10) % 10 != 1)
                  * (n % 10 < 4)
                  * n
                  % 10 :: 4
              ],
          )
  
      # Compute explanations for instance and neighbors
      g = self.explainer.local_neighbors["norm_shap"]
  
      # Reorder indices based on absolute values of the 1st row (i.e. the instance) in descending order
      inds = np.flip(np.abs(g[0, :]).argsort())
      g = g[:, inds]
      columns = [column_names[i] for i in inds]
  
      # Plot
      g_df = pd.DataFrame(g, columns=columns).T.rename(
          columns={
              **{0: "instance", 1: "closest neighbor"},
              **{
                  i: ordinal(i) + " closest neighbor"
                  for i in range(2, len(g))
              },
          }
      )
  
      # Keep only max_features
      if max_features is not None:
          g_df = g_df[:max_features]
  
      fig = go.Figure(
          data=[
              go.Bar(
                  name=g_df.iloc[::-1, ::-1].columns[i],
                  y=g_df.iloc[::-1, ::-1].index.tolist(),
                  x=g_df.iloc[::-1, ::-1].iloc[:, i],
                  marker_color=self._style_dict[
                      "dict_stability_bar_colors"
                  ][1]
                  if i == g_df.shape[1] - 1
                  else self._style_dict["dict_stability_bar_colors"][0],
                  orientation="h",
                  opacity=np.clip(
                      0.2 + i * (1 - 0.2) / (g_df.shape[1] - 1), 0.2, 1
                  )
                  if g_df.shape[1] > 1
                  else 1,
              )
              for i in range(g_df.shape[1])
          ]
      )
  
      title = f"Comparing local explanations in a neighborhood - Id: <b>{index}</b>"
      title += "<span style='font-size: 16px;'><br />How similar are explanations for closeby neighbours?</span>"
      dict_t = copy.deepcopy(self._style_dict["dict_title_stability"])
      dict_xaxis = copy.deepcopy(self._style_dict["dict_xaxis"])
      dict_yaxis = copy.deepcopy(self._style_dict["dict_yaxis"])
      dict_xaxis["text"] = "Normalized contribution values"
      dict_yaxis["text"] = ""
      dict_t["text"] = title
      fig.update_layout(
          template="none",
          title=dict_t,
          xaxis_title=dict_xaxis,
          yaxis_title=dict_yaxis,
          hovermode="closest",
          barmode="group",
          height=max(500, 11 * g_df.shape[0] * g_df.shape[1]),
          legend={"traceorder": "reversed"},
          xaxis={"side": "bottom"},
      )
  
      fig.update_yaxes(automargin=True)
      fig.update_xaxes(automargin=True)
  
      if file_name is not None:
          plot(fig, filename=file_name, auto_open=auto_open)
  
      return fig
  
imports: import warnings
  from numbers import Number
  import random
  import copy
  import math
  import numpy
  from scipy.optimize import fsolve
  import scipy.cluster.hierarchy
  import pandas
  from plotly import graph_objs
  import plotly.express
  from plotly.subplots import make_subplots
  from plotly.offline import plot
  from shapash.manipulation.select_lines import select_lines
  from shapash.manipulation.summarize import compute_features_import, project_feature_values_1d, compute_corr
  from shapash.utils.utils import add_line_break, truncate_str, compute_digit_number, add_text, maximum_difference_sort_value, compute_sorted_variables_interactions_list_indices, compute_top_correlations_features
  from shapash.webapp.utils.utils import round_to_k
  from shapash.style.style_utils import colors_loading, select_palette, define_style
label_desc: Use image node_id 29 for calling the SmartPlotter obj's underlying member method code with example usage: obj.local_neighbors_plot(index, max_features, file_name, auto_open) and returns: fig, unknown