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: contribution_plot method diplays a Plotly scatter or violin plot of a selected feature.
  It represents the contribution of the selected feature to the predicted value.
  This plot allows the user to understand how the value of a feature affects a prediction
  Type of plot (Violin/scatter) is automatically selected. It depends on the feature
  to be analyzed, the type of use case (regression / classification) and the presence of
  predicted values attribute.
  A sample is taken if the number of points to be displayed is too large
  Using col parameter, shapash user can specify the column num, name or column label of
  the feature
  contribution_plot tutorial offers many examples (please check tutorial part of this doc)
  Parameters
  ----------
  col: String or Int
      Name, label name or column number of the column whose contributions we want to plot
  selection: list (optional)
      Contains list of index, subset of the input DataFrame that we want to plot
  label: integer or string (default -1)
      If the label is of string type, check if it can be changed to integer to select the
      good dataframe object.
  violin_maxf: int (optional, default: 10)
      maximum number modality to plot violin. If the feature specified with col argument
      has more modalities than violin_maxf, a scatter plot will be choose
  max_points: int (optional, default: 2000)
      maximum number to plot in contribution plot. if input dataset is bigger than max_points,
      a sample limits the number of points to plot.
      nb: you can also limit the number using 'selection' parameter.
  proba: bool (optional, default: True)
      use predict_proba to color plot (classification case)
  width : Int (default: 900)
      Plotly figure - layout width
  height : Int (default: 600)
      Plotly figure - layout height
  file_name: string (optional)
      File name to use to save the plotly bar chart. If None the bar chart will not be saved.
  auto_open: Boolean (optional)
      Indicate whether to open the bar plot or not.
  zoom: bool (default=False)
      graph is currently zoomed
  Returns
  -------
  Plotly Figure Object
  Example
  --------
  >>> xpl.plot.contribution_plot(0)
code: def contribution_plot(
      self,
      col,
      selection=None,
      label=-1,
      violin_maxf=10,
      max_points=2000,
      proba=True,
      width=900,
      height=600,
      file_name=None,
      auto_open=False,
      zoom=False,
  ):
      """
      contribution_plot method diplays a Plotly scatter or violin plot of a selected feature.
      It represents the contribution of the selected feature to the predicted value.
      This plot allows the user to understand how the value of a feature affects a prediction
      Type of plot (Violin/scatter) is automatically selected. It depends on the feature
      to be analyzed, the type of use case (regression / classification) and the presence of
      predicted values attribute.
      A sample is taken if the number of points to be displayed is too large
      Using col parameter, shapash user can specify the column num, name or column label of
      the feature
      contribution_plot tutorial offers many examples (please check tutorial part of this doc)
      Parameters
      ----------
      col: String or Int
          Name, label name or column number of the column whose contributions we want to plot
      selection: list (optional)
          Contains list of index, subset of the input DataFrame that we want to plot
      label: integer or string (default -1)
          If the label is of string type, check if it can be changed to integer to select the
          good dataframe object.
      violin_maxf: int (optional, default: 10)
          maximum number modality to plot violin. If the feature specified with col argument
          has more modalities than violin_maxf, a scatter plot will be choose
      max_points: int (optional, default: 2000)
          maximum number to plot in contribution plot. if input dataset is bigger than max_points,
          a sample limits the number of points to plot.
          nb: you can also limit the number using 'selection' parameter.
      proba: bool (optional, default: True)
          use predict_proba to color plot (classification case)
      width : Int (default: 900)
          Plotly figure - layout width
      height : Int (default: 600)
          Plotly figure - layout height
      file_name: string (optional)
          File name to use to save the plotly bar chart. If None the bar chart will not be saved.
      auto_open: Boolean (optional)
          Indicate whether to open the bar plot or not.
      zoom: bool (default=False)
          graph is currently zoomed
      Returns
      -------
      Plotly Figure Object
      Example
      --------
      >>> xpl.plot.contribution_plot(0)
      """
  
      if self.explainer._case == "classification":
          label_num, _, label_value = self.explainer.check_label_name(
              label
          )
  
      if not isinstance(col, (str, int)):
          raise ValueError("parameter col must be string or int.")
      if hasattr(self.explainer, "inv_features_dict"):
          col = self.explainer.inv_features_dict.get(col, col)
      col_is_group = (
          self.explainer.features_groups
          and col in self.explainer.features_groups.keys()
      )
  
      # Case where col is a group of features
      if col_is_group:
          contributions = self.explainer.contributions_groups
          col_label = self.explainer.features_dict[col]
          col_name = self.explainer.features_groups[
              col
          ]  # Here col_name is actually a list of features
          col_value_count = self.explainer.features_desc[col]
      else:
          contributions = self.explainer.contributions
          col_id = self.explainer.check_features_name([col])[0]
          col_name = self.explainer.columns_dict[col_id]
          col_value_count = self.explainer.features_desc[col_name]
  
          if self.explainer.features_dict:
              col_label = self.explainer.features_dict[col_name]
          else:
              col_label = col_name
  
      list_ind, addnote = self.explainer.plot._subset_sampling(
          selection, max_points
      )
  
      col_value = None
      proba_values = None
      subtitle = None
      col_scale = None
  
      # Classification Case
      if self.explainer._case == "classification":
          subcontrib = contributions[label_num]
          if self.explainer.y_pred is not None:
              col_value = self.explainer._classes[label_num]
          subtitle = f"Response: <b>{label_value}</b>"
          # predict proba Color scale
          if proba and hasattr(self.explainer.model, "predict_proba"):
              if not hasattr(self.explainer, "proba_values"):
                  self.explainer.predict_proba()
              proba_values = self.explainer.proba_values.iloc[
                  :, [label_num]
              ]
              if not hasattr(self, "pred_colorscale"):
                  self.pred_colorscale = {}
              if label_num not in self.pred_colorscale:
                  self.pred_colorscale[
                      label_num
                  ] = self.tuning_colorscale(proba_values)
              col_scale = self.pred_colorscale[label_num]
              # Proba subset:
              proba_values = proba_values.loc[list_ind, :]
  
      # Regression Case - color scale
      elif self.explainer._case == "regression":
          subcontrib = contributions
          if self.explainer.y_pred is not None:
              if not hasattr(self, "pred_colorscale"):
                  self.pred_colorscale = self.tuning_colorscale(
                      self.explainer.y_pred
                  )
              col_scale = self.pred_colorscale
  
      # Subset
      if self.explainer.postprocessing_modifications:
          feature_values = self.explainer.x_contrib_plot.loc[
              list_ind, col_name
          ]
      else:
          feature_values = self.explainer.x_init.loc[list_ind, col_name]
  
      if col_is_group:
          feature_values = project_feature_values_1d(
              feature_values,
              col,
              self.explainer.x_init,
              self.explainer.x_encoded,
              self.explainer.preprocessing,
              features_dict=self.explainer.features_dict,
          )
          contrib = subcontrib.loc[list_ind, col].to_frame()
          if self.explainer.features_imp is None:
              self.explainer.compute_features_import()
          features_imp = (
              self.explainer.features_imp
              if isinstance(self.explainer.features_imp, pd.Series)
              else self.explainer.features_imp[0]
          )
          top_features_of_group = (
              features_imp.loc[self.explainer.features_groups[col]]
              .sort_values(ascending=False)[:4]
              .index
          )  # Displaying top 4 features
          metadata = {
              self.explainer.features_dict[
                  f_name
              ]: self.explainer.x_init[f_name]
              for f_name in top_features_of_group
          }
          text_group = (
              "Features values were projected on the x axis using t-SNE"
          )
          # if group don't show addnote, if not, it's too long
          # if addnote is not None:
          #    addnote = add_text([addnote, text_group], sep=' - ')
          # else:
          addnote = text_group
      else:
          contrib = subcontrib.loc[list_ind, col_name].to_frame()
          metadata = None
      feature_values = feature_values.to_frame()
  
      if self.explainer.y_pred is not None:
          y_pred = self.explainer.y_pred.loc[list_ind]
          # Add labels if exist
          if (
              self.explainer._case == "classification"
              and self.explainer.label_dict is not None
          ):
              y_pred = y_pred.applymap(
                  lambda x: self.explainer.label_dict[x]
              )
              col_value = self.explainer.label_dict[col_value]
          # round predict
          elif self.explainer._case == "regression":
              if self.round_digit is None:
                  self.tuning_round_digit()
              y_pred = y_pred.applymap(
                  lambda x: round(x, self.round_digit)
              )
      else:
          y_pred = None
  
      # selecting the best plot : Scatter, Violin?
      if col_value_count > violin_maxf:
          fig = self.plot_scatter(
              feature_values,
              contrib,
              col_label,
              y_pred,
              proba_values,
              col_value,
              col_scale,
              metadata,
              addnote,
              subtitle,
              width,
              height,
              file_name,
              auto_open,
              zoom,
          )
      else:
          fig = self.plot_violin(
              feature_values,
              contrib,
              col_label,
              y_pred,
              proba_values,
              col_value,
              col_scale,
              addnote,
              subtitle,
              width,
              height,
              file_name,
              auto_open,
              zoom,
          )
  
      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 15 for calling the SmartPlotter obj's underlying member method code with example usage: obj.contribution_plot(col, selection, label, violin_maxf, max_points, proba, width, height, file_name, auto_open, zoom) and returns: fig