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 Stability_plot has the main objective of increasing confidence in contribution values,         and helping determine if we can trust an explanation.
  The idea behind local stability is the following : if instances are very similar,         then one would expect the explanations to be similar as well.
  Therefore, locally stable explanations are an important factor that help         build trust around a particular explanation method.
  The generated graphs can take multiple forms, but they all analyze         the same two aspects: for each feature we look at Amplitude vs. Variability.         in order terms, how important the feature is on average vs. how the feature impact         changes in the instance neighborhood.
  The average importance of the feature is the average SHAP value of the feature acros all considered instances
  The neighborhood is defined 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)
  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
  ----------
  selection: list
      Contains list of index, subset of the input DataFrame that we use for the compute of stability statistics
  max_points: int, optional
      Maximum number to plot in compacity plot, by default 500
  force: bool, optional
      force == True, force the compute of stability values, by default False
  distribution: str, optional
      Add distribution of variability for each feature, by default 'none'.
      The other values are 'boxplot' or 'violin' that specify the type of plot
  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
  -------
  If single instance:
      * plot -- Normalized contribution values of instance and neighbors
  If multiple instances:
      * if distribution == "none": Mean amplitude of each feature contribution vs. mean variability across neighbors
      * if distribution == "boxplot": Distribution of contributions of each feature in instances neighborhoods.
      Graph type is box plot
      * if distribution == "violin": Distribution of contributions of each feature in instances neighborhoods.
      Graph type is violin plot
code: def stability_plot(
      self,
      selection=None,
      max_points=500,
      force=False,
      max_features=10,
      distribution="none",
      file_name=None,
      auto_open=False,
  ):
      """
          The Stability_plot has the main objective of increasing confidence in contribution values, \
          and helping determine if we can trust an explanation.
          The idea behind local stability is the following : if instances are very similar, \
          then one would expect the explanations to be similar as well.
          Therefore, locally stable explanations are an important factor that help \
          build trust around a particular explanation method.
          The generated graphs can take multiple forms, but they all analyze \
          the same two aspects: for each feature we look at Amplitude vs. Variability. \
          in order terms, how important the feature is on average vs. how the feature impact \
          changes in the instance neighborhood.
          The average importance of the feature is the average SHAP value of the feature acros all considered instances
          The neighborhood is defined 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)
          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
          ----------
          selection: list
              Contains list of index, subset of the input DataFrame that we use for the compute of stability statistics
          max_points: int, optional
              Maximum number to plot in compacity plot, by default 500
          force: bool, optional
              force == True, force the compute of stability values, by default False
          distribution: str, optional
              Add distribution of variability for each feature, by default 'none'.
              The other values are 'boxplot' or 'violin' that specify the type of plot
          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
          -------
          If single instance:
              * plot -- Normalized contribution values of instance and neighbors
          If multiple instances:
              * if distribution == "none": Mean amplitude of each feature contribution vs. mean variability across neighbors
              * if distribution == "boxplot": Distribution of contributions of each feature in instances neighborhoods.
              Graph type is box plot
              * if distribution == "violin": Distribution of contributions of each feature in instances neighborhoods.
              Graph type is violin plot
          """
      # Sampling
      if selection is None:
          if self.explainer.x_init.shape[0] <= max_points:
              list_ind = self.explainer.x_init.index.tolist()
          else:
              list_ind = random.sample(
                  self.explainer.x_init.index.tolist(), max_points
              )
          # By default, don't compute calculation if it has already been done
          if (
              (self.explainer.features_stability is None)
              or self.last_stability_selection
              or force
          ):
              self.explainer.compute_features_stability(list_ind)
          else:
              print("Computed values from previous call are used")
          self.last_stability_selection = False
      elif isinstance(selection, list):
          if len(selection) == 1:
              raise ValueError("Selection must include multiple points")
          if len(selection) > max_points:
              print(
                  f"Size of selection is bigger than max_points (default: {max_points}).\
                        Computation time might be affected"
              )
          self.explainer.compute_features_stability(selection)
          self.last_stability_selection = True
      else:
          raise ValueError("Parameter selection must be a list")
  
      column_names = np.array(
          [
              self.explainer.features_dict.get(x)
              for x in self.explainer.x_init.columns
          ]
      )
  
      variability = self.explainer.features_stability["variability"]
      amplitude = self.explainer.features_stability["amplitude"]
  
      mean_variability = variability.mean(axis=0)
      mean_amplitude = amplitude.mean(axis=0)
  
      # Plot 1 : only show average variability on y-axis
      if distribution not in ["boxplot", "violin"]:
          fig = self.plot_amplitude_vs_stability(
              mean_variability,
              mean_amplitude,
              column_names,
              file_name,
              auto_open,
          )
  
      # Plot 2 : Show distribution of variability
      else:
          # If set, only keep features with the highest mean amplitude
          if max_features is not None:
              keep = mean_amplitude.argsort()[::-1][:max_features]
              keep = np.sort(keep)
  
              variability = variability[:, keep]
              mean_amplitude = mean_amplitude[keep]
              dataset = self.explainer.x_init.iloc[:, keep]
              column_names = column_names[keep]
  
          fig = self.plot_stability_distribution(
              variability,
              distribution,
              mean_amplitude,
              dataset,
              column_names,
              file_name,
              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 30 for calling the SmartPlotter obj's underlying member method code with example usage: obj.stability_plot(selection, max_points, force, max_features, distribution, file_name, auto_open) and returns: fig