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 Compacity_plot has the main objective of determining if a small subset of features         can be extracted to provide a simpler explanation of the model.         indeed, having too many features might negatively affect the model explainability and make it harder to undersand.
  The following two plots are proposed:
  * We identify the minimum number of required features (based on the top contribution values)         that well approximate the model, and thus, provide accurate explanations.
  In particular, the prediction with the chosen subset needs to be close enough (*see distance definition below*)         to the one obtained with all features.
  * Conversely, we determine how close we get to the output with all features by using only a subset of them.
  *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 2000
  force: bool, optional
      force == True, force the compute of stability values, by default False
  approx: float, optional
      How close we want to be from model with all features, by default 0.9 (=90%)
  nb_features: int, optional
      Number of features used, by default 5
  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
code: def compacity_plot(
      self,
      selection=None,
      max_points=2000,
      force=False,
      approx=0.9,
      nb_features=5,
      file_name=None,
      auto_open=False,
  ):
      """
          The Compacity_plot has the main objective of determining if a small subset of features \
          can be extracted to provide a simpler explanation of the model. \
          indeed, having too many features might negatively affect the model explainability and make it harder to undersand.
          The following two plots are proposed:
          * We identify the minimum number of required features (based on the top contribution values) \
          that well approximate the model, and thus, provide accurate explanations.
          In particular, the prediction with the chosen subset needs to be close enough (*see distance definition below*) \
          to the one obtained with all features.
          * Conversely, we determine how close we get to the output with all features by using only a subset of them.
          *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 2000
          force: bool, optional
              force == True, force the compute of stability values, by default False
          approx: float, optional
              How close we want to be from model with all features, by default 0.9 (=90%)
          nb_features: int, optional
              Number of features used, by default 5
          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
          """
      # 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_compacity is None)
              or self.last_compacity_selection
              or force
          ):
              self.explainer.compute_features_compacity(
                  list_ind, 1 - approx, nb_features
              )
          else:
              print("Computed values from previous call are used")
          self.last_compacity_selection = False
      elif isinstance(selection, list):
          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_compacity(
              selection, 1 - approx, nb_features
          )
          self.last_compacity_selection = True
      else:
          raise ValueError("Parameter selection must be a list")
  
      features_needed = self.explainer.features_compacity[
          "features_needed"
      ]
      distance_reached = self.explainer.features_compacity[
          "distance_reached"
      ]
  
      # Make plots
      fig = make_subplots(
          rows=1,
          cols=2,
          subplot_titles=[
              "Number of features required<br>to explain "
              + str(round(100 * approx))
              + "% of the model's output",
              "Percentage of the model output<br>explained by the "
              + str(nb_features)
              + " most important<br>features per instance",
          ],
          horizontal_spacing=0.2,
      )
  
      # Used as titles in make_subplots are considered annotations
      fig.update_annotations(
          font=self._style_dict["dict_title_compacity"]["font"]
      )
  
      # First plot: number of features required for a given approximation
      fig.add_trace(
          go.Histogram(
              x=features_needed,
              histnorm="percent",
              cumulative={"enabled": True},
              name="",
              hovertemplate="Top %{x:.0f} features explain at least "
              + str(round(100 * approx))
              + "%<br>of the model for %{y:.1f}% of the instances",
              hovertext="none",
              marker_color=self._style_dict[
                  "dict_compacity_bar_colors"
              ][1],
          ),
          row=1,
          col=1,
      )
  
      dict_xaxis = copy.deepcopy(self._style_dict["dict_xaxis"])
      dict_yaxis = copy.deepcopy(self._style_dict["dict_yaxis"])
      dict_xaxis["text"] = "Number of selected features"
      dict_yaxis[
          "text"
      ] = "Cumulative distribution over<br>dataset's instances (%)"
  
      fig.update_xaxes(title=dict_xaxis, row=1, col=1)
      fig.update_yaxes(title=dict_yaxis, row=1, col=1)
  
      # Second plot: approximation reached for a given number of features
      fig.add_trace(
          go.Histogram(
              x=100 * (1 - distance_reached),
              histnorm="percent",
              cumulative={"enabled": True, "direction": "decreasing"},
              name="",
              hovertemplate="Top "
              + str(nb_features)
              + " features explain at least "
              + "%{x:.0f}"
              + "%<br>of the model for %{y:.1f}% of the instances",
              marker_color=self._style_dict[
                  "dict_compacity_bar_colors"
              ][0],
          ),
          row=1,
          col=2,
      )
  
      dict_xaxis2 = copy.deepcopy(self._style_dict["dict_xaxis"])
      dict_yaxis2 = copy.deepcopy(self._style_dict["dict_yaxis"])
      dict_xaxis2[
          "text"
      ] = "Percentage of model output<br>explained (%)"
      dict_yaxis2[
          "text"
      ] = "Cumulative distribution over<br>dataset's instances (%)"
  
      fig.update_xaxes(title=dict_xaxis2, row=1, col=2)
      fig.update_yaxes(title=dict_yaxis2, row=1, col=2)
  
      title = "Compacity of explanations:"
      title += "<span style='font-size: 16px;'><br />How many variables are enough to produce accurate explanations?</span>"
      dict_t = copy.deepcopy(self._style_dict["dict_title_stability"])
      dict_t["text"] = title
  
      fig.update_layout(
          template="none",
          title=dict_t,
          title_y=0.8,
          hovermode="closest",
          margin={"t": 150},
          showlegend=False,
      )
  
      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 31 for calling the SmartPlotter obj's underlying member method code with example usage: obj.compacity_plot(selection, max_points, force, approx, nb_features, file_name, auto_open) and returns: fig