class_docstr: Bridge pattern decoupling the application part from SmartExplainer and SmartPlotter.
  Attributes
  ----------
  explainer: object
      SmartExplainer instance to point to.
class_docstr_tok: ["Bridge","pattern","decoupling","the","application","part","from","SmartExplainer","and","SmartPlotter",".","Attributes","--","--","--","--","--","explainer",":","object","SmartExplainer","instance","to","point","to","."]
code: def callback_generator(self):
      app = self.app
  
      @app.callback(
          [
              Output("dataset", "data"),
              Output("dataset", "tooltip_data"),
              Output("dataset", "columns"),
              Output("filtered_subset_info", "children"),
              Output("filtered_subset_info", "color"),
          ],
          [
              Input("prediction_picking", "selectedData"),
              Input("modal", "is_open"),
              Input("apply_filter", "n_clicks"),
              Input("reset_dropdown_button", "n_clicks"),
              Input(
                  {"type": "del_dropdown_button", "index": ALL},
                  "n_clicks",
              ),
          ],
          [
              State("rows", "value"),
              State("name", "value"),
              State({"type": "var_dropdown", "index": ALL}, "value"),
              State({"type": "var_dropdown", "index": ALL}, "id"),
              State({"type": "dynamic-str", "index": ALL}, "value"),
              State({"type": "dynamic-str", "index": ALL}, "id"),
              State({"type": "dynamic-bool", "index": ALL}, "value"),
              State({"type": "dynamic-bool", "index": ALL}, "id"),
              State(
                  {"type": "dynamic-date", "index": ALL}, "start_date"
              ),
              State({"type": "dynamic-date", "index": ALL}, "end_date"),
              State({"type": "dynamic-date", "index": ALL}, "id"),
              State({"type": "lower", "index": ALL}, "value"),
              State({"type": "lower", "index": ALL}, "id"),
              State({"type": "upper", "index": ALL}, "value"),
          ],
      )
      def update_datatable(
          selected_data,
          is_open,
          nclicks_apply,
          nclicks_reset,
          nclicks_del,
          rows,
          name,
          val_feature,
          id_feature,
          val_str_modality,
          id_str_modality,
          val_bool_modality,
          id_bool_modality,
          start_date,
          end_date,
          id_date,
          val_lower_modality,
          id_lower_modality,
          val_upper_modality,
      ):
          """
          This function is used to update the datatable according to sorting,
          filtering and settings modifications.
          ------------------------------------------------------------------
          selected_data: selected data in prediction picking graph
          nclicks_apply: click on Apply Filter button
          nclicks_reset: click on Reset All Filter button
          nclicks_del: click on delete button
          rows: number of rows for subset
          name: name for features name
          val_feature: feature selected to filter
          id_feature: id of feature selected to filter
          val_str_modality: string modalities selected
          id_str_modality: id of string modalities selected
          val_bool_modality: boolean modalities selected
          id_bool_modality: id of boolean modalities selected
          start_date: start dates selected
          end_date: end dates selected
          id_date: id of dates selected
          val_lower_modality: lower values of numeric filter
          id_lower_modality: id of lower modalities of numeric filter
          val_upper_modality: upper values of numeric filter
          ------------------------------------------------------------------
          return
          data: available dataset
          tooltip_data: tooltip of the dataset
          columns: columns of the dataset
          filtered_subset_info: subset size
          filtered_subset_color: subset warning color
          """
          ctx = dash.callback_context
          df = self.round_dataframe
          columns = self.components["table"]["dataset"].columns
          filtered_subset_info = None
          filtered_subset_color = None
          if ctx.triggered[0]["prop_id"] == "modal.is_open":
              if is_open:
                  raise PreventUpdate
              else:
                  self.init_data(rows=rows)
                  if name == [1]:
                      columns = [
                          {"name": i, "id": i}
                          for i in self.special_cols
                      ] + [
                          {"name": self.features_dict[i], "id": i}
                          for i in self.dataframe.columns.drop(
                              self.special_cols
                          )
                      ]
                  df = self.round_dataframe
          elif (
              (
                  ctx.triggered[0]["prop_id"]
                  == "prediction_picking.selectedData"
              )
              and (selected_data is not None)
              and (len(selected_data) > 1)
          ):
              df = select_data_from_prediction_picking(
                  self.round_dataframe, selected_data
              )
          # If click on reset button
          elif (
              ctx.triggered[0]["prop_id"]
              == "reset_dropdown_button.n_clicks"
          ):
              df = self.round_dataframe
          # If click on Apply filter
          elif (
              (ctx.triggered[0]["prop_id"] == "apply_filter.n_clicks")
              | (
                  (
                      ctx.triggered[0]["prop_id"]
                      == "prediction_picking.selectedData"
                  )
                  and ((selected_data is None))
              )
              | (
                  (
                      ctx.triggered[0]["prop_id"]
                      == "prediction_picking.selectedData"
                  )
                  and (
                      selected_data is not None
                      and len(selected_data) == 1
                      and len(selected_data["points"]) != 0
                      and selected_data["points"][0]["curveNumber"] > 0
                  )
              )
          ):
              df = self.round_dataframe.copy()
              feature_id = [
                  id_feature[i]["index"] for i in range(len(id_feature))
              ]
              df = select_data_from_str_filters(
                  df,
                  feature_id,
                  id_str_modality,
                  val_feature,
                  val_str_modality,
              )
              df = select_data_from_bool_filters(
                  df,
                  feature_id,
                  id_bool_modality,
                  val_feature,
                  val_bool_modality,
              )
              df = select_data_from_numeric_filters(
                  df,
                  feature_id,
                  id_lower_modality,
                  val_feature,
                  val_lower_modality,
                  val_upper_modality,
              )
              df = select_data_from_date_filters(
                  df,
                  feature_id,
                  id_date,
                  val_feature,
                  start_date,
                  end_date,
              )
              filtered_subset_info = f"Subset length: {len(df)} ({int(round(100*len(df)/self.explainer.x_init.shape[0]))}%)"
              if len(df) == 0:
                  filtered_subset_color = "danger"
  
          elif None not in nclicks_del:
              df = self.round_dataframe
          else:
              raise dash.exceptions.PreventUpdate
          data = df.to_dict("records")
          tooltip_data = [
              {
                  column: {"value": str(value), "type": "text"}
                  for column, value in row.items()
              }
              for row in df.to_dict("index").values()
          ]
          return (
              data,
              tooltip_data,
              columns,
              filtered_subset_info,
              filtered_subset_color,
          )
  
      @app.callback(
          [
              Output("global_feature_importance", "figure"),
              Output("global_feature_importance", "clickData"),
              Output("clickdata-store", "data"),
          ],
          [
              Input("select_label", "value"),
              Input("dataset", "data"),
              Input("prediction_picking", "selectedData"),
              Input("apply_filter", "n_clicks"),
              Input("reset_dropdown_button", "n_clicks"),
              Input(
                  {"type": "del_dropdown_button", "index": ALL},
                  "n_clicks",
              ),
              Input("card_global_feature_importance", "n_clicks"),
              Input("bool_groups", "on"),
              Input("ember_global_feature_importance", "n_clicks"),
          ],
          [
              State("global_feature_importance", "clickData"),
              State("global_feature_importance", "figure"),
              State("features", "value"),
              State("clickdata-store", "data"),
          ],
      )
      def update_feature_importance(
          label,
          data,
          selected_data,
          apply_filters,
          reset_filter,
          nclicks_del,
          n_clicks,
          bool_group,
          click_zoom,
          clickData,
          figure,
          features,
          clickData_store,
      ):
          """
          update feature importance plot according label, click on graph,
          filters applied and subset selected in prediction picking graph.
          ------------------------------------------------------------
          label: label of data
          data: dataset
          selected_data : data selected on prediction picking graph
          apply_filters: click on apply filter button
          reset_filter: click on reset filter button
          nclicks_del: click on del button
          n_clicks: click on features importance card
          bool_group: display groups
          click_zoom: click on zoom button
          clickData: click on features importance graph
          figure: figure of Features Importance graph
          features: features value
          clickData_store: previous click on features importance graph
          -------------------------------------------------------------
          return
          figure of Features Importance graph
          click on Features Importance graph
          previous click on Features Importance graph
          """
          ctx = dash.callback_context
          # Zoom is False by Default. It becomes True if we click on it
          zoom_active = get_figure_zoom(click_zoom)
          selection = None
          list_index = self.list_index
          if clickData is not None and (
              ctx.triggered[0]["prop_id"]
              in [
                  "apply_filter.n_clicks",
                  "reset_dropdown_button.n_clicks",
                  "dataset.data",
              ]
              or (
                  "del_dropdown_button" in ctx.triggered[0]["prop_id"]
                  and None not in nclicks_del
              )
          ):
              clickData = update_click_data_on_subset_changes(clickData)
  
          selected_feature = (
              self.explainer.inv_features_dict.get(
                  get_feature_from_clicked_data(clickData)
              )
              if clickData
              else None
          )
  
          if self.explainer.features_groups and bool_group:
              if (
                  ctx.triggered[0]["prop_id"]
                  == "card_global_feature_importance.n_clicks"
              ):
                  # When we click twice on the same bar this will reset the graph
                  if clickData_store == clickData:
                      selected_feature = None
                  selected_feature = get_feature_from_features_groups(
                      selected_feature, self.explainer.features_groups
                  )
              elif (
                  ctx.triggered[0]["prop_id"]
                  == "ember_global_feature_importance.n_clicks"
              ):
                  selected_feature = get_feature_from_features_groups(
                      selected_feature, self.explainer.features_groups
                  )
              else:
                  selected_feature = None
  
          selection = get_indexes_from_datatable(data, list_index)
  
          group_name = get_group_name(
              selected_feature, self.explainer.features_groups
          )
  
          figure = self.explainer.plot.features_importance(
              max_features=features,
              selection=selection,
              label=label,
              group_name=group_name,
              display_groups=bool_group,
              zoom=zoom_active,
          )
          # Adjust graph with adding x axis title
          MyGraph.adjust_graph_static(
              figure, x_ax="Mean absolute Contribution"
          )
          figure.layout.clickmode = "event+select"
          if selected_feature:
              self.select_point(figure, clickData)
  
          # font size can be adapted to screen size
          nb_car = max(
              [
                  len(figure.data[0].y[i])
                  for i in range(len(figure.data[0].y))
              ]
          )
          figure.update_layout(
              yaxis=dict(
                  tickfont={"size": min(round(500 / nb_car), 12)}
              )
          )
          clickData_store = (
              clickData.copy() if clickData is not None else None
          )
          return figure, clickData, clickData_store
  
      @app.callback(
          Output(
              component_id="feature_selector",
              component_property="figure",
          ),
          [
              Input("global_feature_importance", "clickData"),
              Input("dataset", "data"),
              Input("select_label", "value"),
              Input("ember_feature_selector", "n_clicks"),
          ],
          [
              State("points", "value"),
              State("violin", "value"),
              State("global_feature_importance", "figure"),
          ],
      )
      def update_feature_selector(
          feature, data, label, click_zoom, points, violin, gfi_figure
      ):
          """
          Update feature plot according to label, data,
          selected feature on features importance graph,
          filters and settings modifications
          --------------------------------------------
          feature: click on feature importance graph
          data: dataset
          label: selected label
          click_zoom: click on zoom button
          points: points value in setting
          violin: violin value in setting
          gfi_figure: figure of Features Importance graph
          ---------------------------------------------
          return
          fs_figure: feature selector graph
          """
          # Zoom is False by Default. It becomes True if we click on it
          zoom_active = get_figure_zoom(click_zoom)
          subset = None
          list_index = self.list_index
          if feature is not None:
              selected_feature = get_feature_from_clicked_data(feature)
          else:
              selected_feature = self.selected_feature
  
          if (
              feature is not None
              and feature["points"][0]["curveNumber"] == 0
              and len(gfi_figure["data"]) == 2
          ):
              subset = get_indexes_from_datatable(data, list_index)
          else:
              subset = None
  
          fs_figure = self.explainer.plot.contribution_plot(
              col=selected_feature,
              selection=subset,
              label=label,
              violin_maxf=violin,
              max_points=points,
              zoom=zoom_active,
          )
  
          fs_figure["layout"].clickmode = "event+select"
          # Adjust graph with adding x and y axis titles
          MyGraph.adjust_graph_static(
              fs_figure,
              # x_ax=truncate_str(self.layout.selected_feature, 110),
              x_ax=truncate_str(selected_feature, 110),
              y_ax="Contribution",
          )
          return fs_figure
  
      @app.callback(
          [Output("index_id", "value"), Output("index_id", "n_submit")],
          [
              Input("feature_selector", "clickData"),
              Input("prediction_picking", "clickData"),
              Input("dataset", "active_cell"),
              Input("apply_filter", "n_clicks"),
              Input("reset_dropdown_button", "n_clicks"),
              Input(
                  {"type": "del_dropdown_button", "index": ALL},
                  "n_clicks",
              ),
          ],
          [
              State("dataset", "data"),
              State(
                  "index_id", "value"
              ),  # Get the current value of the index
          ],
      )
      def update_index_id(
          click_data,
          prediction_picking,
          cell,
          apply_filters,
          reset_filter,
          nclicks_del,
          data,
          current_index_id,
      ):
          """
          This function is used to update index value according to
          active cell, filters and click data on feature plot or on
          prediction picking graph.
          ----------------------------------------------------------------
          click_data: click on feature selector
          prediction_picking: click on prediction picking graph
          cell: selected sell on dataset
          apply_filters: click on Apply filter button
          reset_filter: click on reset filter button
          nclicks_del: click on del button
          data: dataset
          current_index_id: the current value of the index
          ----------------------------------------------------------------
          return
          selected index id
          boolean n_submit
          """
          ctx = dash.callback_context
          selected = None
          if (
              ctx.triggered[0]["prop_id"]
              == "feature_selector.clickData"
          ):
              selected = click_data["points"][0]["customdata"][1]
          elif (
              ctx.triggered[0]["prop_id"]
              == "prediction_picking.clickData"
          ):
              selected = prediction_picking["points"][0]["customdata"]
          elif ctx.triggered[0]["prop_id"] == "dataset.active_cell":
              selected = data[cell["row"]]["_index_"]
          elif (
              "del_dropdown_button" in ctx.triggered[0]["prop_id"]
          ) & (None in nclicks_del):
              selected = current_index_id
          return selected, True
  
      @app.callback(
          Output("threshold_label", "children"),
          [Input("threshold_id", "value")],
      )
      def update_threshold_label(value):
          """
          update threshold label
          """
          return f"Threshold: {value}"
  
      @app.callback(
          Output("max_contrib_label", "children"),
          [Input("max_contrib_id", "value")],
      )
      def update_max_contrib_label(value):
          """
          update max_contrib label
          """
          return f"Features to display: {value}"
  
      @app.callback(
          [
              Output("max_contrib_id", "value"),
              Output("max_contrib_id", "max"),
              Output("max_contrib_id", "marks"),
          ],
          [Input("modal", "is_open")],
          [
              State("features", "value"),
              State("max_contrib_id", "value"),
          ],
      )
      def update_max_contrib_id(is_open, features, value):
          """
          update max contrib component layout after settings modifications
          """
          ctx = dash.callback_context
          if ctx.triggered[0]["prop_id"] == "modal.is_open":
              if is_open:
                  raise PreventUpdate
              else:
                  value, max, marks = update_features_to_display(
                      features,
                      len(self.explainer.x_init.columns),
                      value,
                  )
                  return value, max, marks
  
      @app.callback(
          Output(
              component_id="detail_feature", component_property="figure"
          ),
          [
              Input("threshold_id", "value"),
              Input("max_contrib_id", "value"),
              Input("check_id_positive", "value"),
              Input("check_id_negative", "value"),
              Input("masked_contrib_id", "value"),
              Input("select_label", "value"),
              Input("validation", "n_clicks"),
              Input("bool_groups", "on"),
              Input("ember_detail_feature", "n_clicks"),
          ],
          [State("index_id", "value"), State("dataset", "data")],
      )
      def update_detail_feature(
          threshold,
          max_contrib,
          positive,
          negative,
          masked,
          label,
          validation_click,
          bool_group,
          click_zoom,
          index,
          data,
      ):
          """
          update local explanation plot according to app changes.
          -------------------------------------------------------
          threshold: threshold
          max_contrib: max contribution
          positive: boolean
          negative: boolean
          masked: feature(s) to mask
          label: label
          cell: selected cell
          click_data: click on feature selector graph
          prediction_picking: click on prediction picking graph
          validation_click: click on validation
          bool_group: boolean
          click_zoom: click on zoom button
          index: selected index
          data: the dataset
          --------------------------------------------------------
          return
          detail feature graph
          """
          # Zoom is False by Default. It becomes True if we click on it
          zoom_active = get_figure_zoom(click_zoom)
          selected = index
          if check_row(data, selected) is None:
              selected = None
          threshold = threshold if threshold != 0 else None
          sign = get_feature_contributions_sign_to_show(
              positive, negative
          )
          self.explainer.filter(
              threshold=threshold,
              features_to_hide=masked,
              positive=sign,
              max_contrib=max_contrib,
              display_groups=bool_group,
          )
          figure = self.explainer.plot.local_plot(
              index=selected,
              label=label,
              show_masked=True,
              yaxis_max_label=8,
              display_groups=bool_group,
              zoom=zoom_active,
          )
          if selected is not None:
              # Adjust graph with adding x axis titles
              MyGraph.adjust_graph_static(figure, x_ax="Contribution")
              # font size can be adapted to screen size
              list_yaxis = [
                  figure.data[i].y[0] for i in range(len(figure.data))
              ]
              # exclude new line with labels of y axis
              if list_yaxis != []:
                  list_yaxis = [
                      x.split("<br />")[0] for x in list_yaxis
                  ]
                  nb_car = max([len(x) for x in list_yaxis])
                  figure.update_layout(
                      yaxis=dict(
                          tickfont={
                              "size": min(round(500 / nb_car), 12)
                          }
                      )
                  )
          return figure
  
      @app.callback(
          Output("validation", "n_clicks"),
          [Input("index_id", "n_submit")],
      )
      def click_validation(n_submit):
          """
          submit index selection
          """
          if n_submit:
              return 1
          else:
              raise PreventUpdate
  
      @app.callback(
          Output("id_card", "style"),
          Output("id_card_body", "children"),
          Output("id_card_title_contrib", "children"),
          [
              Input("index_id", "n_submit"),
              Input("select_label", "value"),
              Input("select_id_card_sorting", "value"),
              Input("select_id_card_order", "value"),
          ],
          [
              State("dataset", "data"),
              State("index_id", "value"),
          ],
      )
      def update_id_card(n_submit, label, sort_by, order, data, index):
          """
          Update identity card and display button.
          Parameters
          ----------
          n_submit : boolean
          data : the dataset
          label : selected label for classification
          sort_by : identity card column to sort by, data column labels or contribution
          order : order to sort by, ascending or descending
          index : selected index
          Returns
          -------
          style to display button and children body for modal.
          """
          selected = check_row(data, index)
          title_contrib = "Contribution"
          if n_submit and selected is not None:
              selected_row = get_id_card_features(
                  data, selected, self.special_cols, self.features_dict
              )
              if self.explainer._case == "classification":
                  if label is None:
                      label = -1
                  (
                      label_num,
                      _,
                      label_value,
                  ) = self.explainer.check_label_name(label)
                  selected_contrib = get_id_card_contrib(
                      self.explainer.data,
                      index,
                      self.explainer.features_dict,
                      self.explainer.columns_dict,
                      label_num,
                  )
                  proba = self.explainer.plot.local_pred(
                      index, label_num
                  )
                  title_contrib = f"Contribution: {label_value} ({proba.round(2):.2f})"
                  (
                      _,
                      _,
                      predicted_label_value,
                  ) = self.explainer.check_label_name(
                      selected_row.loc["_predict_", "feature_value"]
                  )
                  selected_row.loc[
                      "_predict_", "feature_value"
                  ] = predicted_label_value
              else:
                  selected_contrib = get_id_card_contrib(
                      self.explainer.data,
                      index,
                      self.explainer.features_dict,
                      self.explainer.columns_dict,
                  )
  
              selected_data = create_id_card_data(
                  selected_row,
                  selected_contrib,
                  sort_by,
                  order,
                  self.special_cols,
                  self.explainer.additional_features_dict,
              )
  
              children = create_id_card_layout(
                  selected_data, self.explainer.additional_features_dict
              )
  
              return (
                  {
                      "display": "flex",
                      "margin-left": "auto",
                      "margin-right": 0,
                  },
                  children,
                  title_contrib,
              )
          else:
              return {"display": "none"}, [], title_contrib
  
      @app.callback(
          Output("modal_id_card", "is_open"),
          [
              Input("id_card", "n_clicks"),
              Input("close_id_card", "n_clicks"),
          ],
          [State("modal_id_card", "is_open")],
      )
      def toggle_modal_id_card(n1, n2, is_open):
          """
          Open and close identity card modal.
          Parameters
          ----------
          n1 : click on button to open
          n2 : click on button to close
          is_open : True if open else False
          Returns
          -------
          boolean True if open else False
          """
          if n1 or n2:
              return not is_open
          return is_open
  
      @app.callback(
          [
              Output("dataset", "style_data_conditional"),
              Output("dataset", "style_filter_conditional"),
              Output("dataset", "style_header_conditional"),
              Output("dataset", "style_cell_conditional"),
          ],
          [Input("validation", "n_clicks")],
          [State("dataset", "data"), State("index_id", "value")],
      )
      def datatable_layout(validation, data, index):
          ctx = dash.callback_context
          if (
              ctx.triggered[0]["prop_id"] == "validation.n_clicks"
              and validation is not None
          ):
              pass
          else:
              raise PreventUpdate
  
          style_data_conditional = [
              {
                  "if": {"row_index": "odd"},
                  "backgroundColor": "rgb(248, 248, 248)",
              },
              {
                  "if": {"state": "selected"},
                  "border": f"1px solid {self.color[0]}",
              },
          ]
          style_filter_conditional = []
          style_header_conditional = [
              {"if": {"column_id": c}, "fontWeight": "bold"}
              for c in self.special_cols
          ] + [
              {"if": {"column_id": c}, "font-style": "italic"}
              for c in self.dataframe
              if c in self.explainer.additional_features_dict
          ]
          style_cell_conditional = [
              {
                  "if": {"column_id": c},
                  "width": "70px",
                  "fontWeight": "bold",
              }
              for c in self.special_cols
          ]
  
          selected = check_row(data, index)
          if selected is not None:
              style_data_conditional += [
                  {
                      "if": {"row_index": selected},
                      "backgroundColor": self.color[0],
                  }
              ]
  
          return (
              style_data_conditional,
              style_filter_conditional,
              style_header_conditional,
              style_cell_conditional,
          )
  
      @app.callback(
          Output("prediction_picking", "figure"),
          Output("prediction_picking", "selectedData"),
          [
              Input("dataset", "data"),
              Input("apply_filter", "n_clicks"),
              Input("reset_dropdown_button", "n_clicks"),
              Input(
                  {"type": "del_dropdown_button", "index": ALL},
                  "n_clicks",
              ),
              Input("select_label", "value"),
              Input("modal", "is_open"),
              Input("ember_prediction_picking", "n_clicks"),
          ],
          [
              State("points", "value"),
              State("violin", "value"),
              State("prediction_picking", "selectedData"),
          ],
      )
      def update_prediction_picking(
          data,
          apply_filters,
          reset_filter,
          nclicks_del,
          label,
          is_open,
          click_zoom,
          points,
          violin,
          selectedData,
      ):
          """
          Update feature plot according to label, data,
          selected feature and settings modifications
          ------------------------------------------------
          data: the dataset
          apply_filters: click on apply filter button
          reset_filter: click on reset filter button
          nclicks_del: click on del button
          label: selected label
          is_open: modal
          click_zoom: click on zoom button
          points: number of points
          violin: number of violin plot
          -------------------------------------------------
          return
          prediction picking graph
          """
          ctx = dash.callback_context
          # Filter subset
          subset = None
          if (
              ctx.triggered[0]["prop_id"] == "apply_filter.n_clicks"
              or ctx.triggered[0]["prop_id"]
              == "reset_dropdown_button.n_clicks"
              or (
                  "del_dropdown_button" in ctx.triggered[0]["prop_id"]
                  and None not in nclicks_del
              )
          ):
              selectedData = None
          if (
              selectedData is not None
              and len(selectedData["points"]) > 0
          ):
              raise PreventUpdate
          else:
              subset = get_indexes_from_datatable(data)
  
          figure = self.explainer.plot.scatter_plot_prediction(
              selection=subset, max_points=points, label=label
          )
          if self.explainer.y_target is not None:
              figure["layout"].clickmode = "event+select"
              # Adjust graph with adding x and y axis titles
              MyGraph.adjust_graph_static(
                  figure, x_ax="True Values", y_ax="Predicted Values"
              )
  
          return figure, selectedData
  
      @app.callback(
          Output("modal_feature_importance", "is_open"),
          [
              Input("open_feature_importance", "n_clicks"),
              Input("close_feature_importance", "n_clicks"),
          ],
          [State("modal_feature_importance", "is_open")],
      )
      def toggle_modal_feature_importancet(n1, n2, is_open):
          """
          Function used to open and close modal explication when we click
          on "?" button on feature_importance graph
          ---------------------------------------------------------------
          n1: click on "?" button
          n2: click on close button in modal
          ---------------------------------------------------------------
          return modal
          """
          if n1 or n2:
              return not is_open
          return is_open
  
      @app.callback(
          Output("modal_feature_selector", "is_open"),
          [
              Input("open_feature_selector", "n_clicks"),
              Input("close_feature_selector", "n_clicks"),
          ],
          [State("modal_feature_selector", "is_open")],
      )
      def toggle_modal_feature_selector(n1, n2, is_open):
          """
          Function used to open and close modal explication when we click
          on "?" button on feature_selector graph
          ---------------------------------------------------------------
          n1: click on "?" button
          n2: click on close button in modal
          ---------------------------------------------------------------
          return modal
          """
          if n1 or n2:
              return not is_open
          return is_open
  
      @app.callback(
          Output("modal_detail_feature", "is_open"),
          [
              Input("open_detail_feature", "n_clicks"),
              Input("close_detail_feature", "n_clicks"),
          ],
          [State("modal_detail_feature", "is_open")],
      )
      def toggle_modal_detail_feature(n1, n2, is_open):
          """
          Function used to open and close modal explication when we click
          on "?" button on detail_feature graph
          ---------------------------------------------------------------
          n1: click on "?" button
          n2: click on close button in modal
          ---------------------------------------------------------------
          return modal
          """
          if n1 or n2:
              return not is_open
          return is_open
  
      @app.callback(
          Output("modal_prediction_picking", "is_open"),
          [
              Input("open_prediction_picking", "n_clicks"),
              Input("close_prediction_picking", "n_clicks"),
          ],
          [State("modal_prediction_picking", "is_open")],
      )
      def toggle_modal_prediction_picking(n1, n2, is_open):
          """
          Function used to open and close modal explication when we click
          on "?" button on prediction_picking graph
          ---------------------------------------------------------------
          n1: click on "?" button
          n2: click on close button in modal
          ---------------------------------------------------------------
          return modal
          """
          if n1 or n2:
              return not is_open
          return is_open
  
      @app.callback(
          Output("modal_filter", "is_open"),
          [
              Input("open_filter", "n_clicks"),
              Input("close_filter", "n_clicks"),
          ],
          [State("modal_filter", "is_open")],
      )
      def toggle_modal_filters(n1, n2, is_open):
          """
          Function used to open and close modal explication when we click
          on "?" button on Dataset Filters Tab
          ---------------------------------------------------------------
          n1: click on "?" button
          n2: click on close button in modal
          ---------------------------------------------------------------
          return modal
          """
          if n1 or n2:
              return not is_open
          return is_open
  
      # Add or remove plot blocs in the 'dropdowns_container'
      @app.callback(
          Output("dropdowns_container", "children"),
          [
              Input("add_dropdown_button", "n_clicks"),
              Input("reset_dropdown_button", "n_clicks"),
              Input(
                  {"type": "del_dropdown_button", "index": ALL},
                  "n_clicks",
              ),
          ],
          [
              State("dropdowns_container", "children"),
              State("name", "value"),
          ],
      )
      def layout_filter(
          n_clicks_add,
          n_clicks_rm,
          n_clicks_reset,
          currents_filters,
          name,
      ):
          """
          Function used to create filter blocs in the dropdowns_container.
          Each bloc will contains:
              -label
              -dropdown button to select feature to filter
              -div which will contains modalities
              -delete button
          ---------------------------------------------------------------
          n_clicks_add: click on add filter
          n_clicks_reset: click on reset filter button
          n_click_del: click on delete button
          children: information on dropdown container
          name: name for feature name
          ---------------------------------------------------------------
          return
              filter blocs
          """
          # Context and init handling (no action)
          ctx = dash.callback_context
          if not ctx.triggered:
              raise dash.exceptions.PreventUpdate
          button_id = ctx.triggered[0]["prop_id"].split(".")[0]
  
          options = get_feature_filter_options(
              self.dataframe, self.features_dict, self.special_cols
          )
  
          # Creation of a new graph
          if button_id == "add_dropdown_button":
              subset_filter = create_dropdown_feature_filter(
                  n_clicks_add, options
              )
              return currents_filters + [subset_filter]
          # Removal of all existing filters
          elif button_id == "reset_dropdown_button":
              return [
                  html.Div(
                      id={"type": "bloc_div", "index": 0}, children=[]
                  )
              ]
          # Removal of an existing filter
          else:
              filter_id_to_remove = eval(button_id)["index"]
              return [
                  gr
                  for gr in currents_filters
                  if gr["props"]["id"]["index"] != filter_id_to_remove
              ]
  
      @app.callback(
          Output("reset_dropdown_button", "disabled"),
          [
              Input("add_dropdown_button", "n_clicks"),
              Input("reset_dropdown_button", "n_clicks"),
              Input(
                  {"type": "del_dropdown_button", "index": ALL},
                  "n_clicks",
              ),
          ],
      )
      def update_disabled_reset_button(
          n_click_add, n_click_reset, n_click_del
      ):
          """
          Function used to disabled or not the reset filter button.
          This button is disabled if there is no filter added.
          ---------------------------------------------------------------
          n_click_add: click on add filter button
          n_click_reset: click on reset filter button
          n_click_del: click on delete button
          ---------------------------------------------------------------
          return disabled style
          """
          ctx = dash.callback_context
          if (
              ctx.triggered[0]["prop_id"]
              == "add_dropdown_button.n_clicks"
          ):
              disabled = False
          elif (
              ctx.triggered[0]["prop_id"]
              == "reset_dropdown_button.n_clicks"
          ):
              disabled = True
          elif None not in n_click_del:
              disabled = True
          else:
              disabled = False
          return disabled
  
      @app.callback(
          Output("apply_filter", "style"),
          Output("filtered_subset_info", "style"),
          [
              Input("add_dropdown_button", "n_clicks"),
              Input("reset_dropdown_button", "n_clicks"),
              Input(
                  {"type": "del_dropdown_button", "index": ALL},
                  "n_clicks",
              ),
          ],
      )
      def update_style_apply_filter_button(
          n_click_add, n_click_reset, n_click_del
      ):
          """
          Function used to display or not the apply filter button.
          This button is only display if almost one filter was added.
          ---------------------------------------------------------------
          n_click_add: click on add filter button
          n_click_reset: click on reset filter button
          n_click_del: click on delete button
          ---------------------------------------------------------------
          return style of apply filter button
          """
          ctx = dash.callback_context
          if (
              ctx.triggered[0]["prop_id"]
              == "add_dropdown_button.n_clicks"
          ):
              return {}, {"margin-left": "20px"}
          elif (
              ctx.triggered[0]["prop_id"]
              == "reset_dropdown_button.n_clicks"
          ):
              return {"display": "none"}, {"display": "none"}
          elif None not in n_click_del:
              return {"display": "none"}, {"display": "none"}
          else:
              return {}, {"margin-left": "20px"}
  
      @app.callback(
          Output(
              {"type": "dynamic-output-label", "index": MATCH},
              "children",
          ),
          Input({"type": "var_dropdown", "index": MATCH}, "value"),
      )
      def update_label_filter(value):
          """
          Function used to add label to the filters. Label is updated
          when value is not None
          ---------------------------------------------------------------
          value: value selected on the var dropdown button
          ---------------------------------------------------------------
          return label
          """
          if value is not None:
              return html.Label("Variable {} is filtered".format(value))
          else:
              return html.Label("Select variable to filter")
  
      @app.callback(
          Output(
              {"type": "dynamic-output", "index": MATCH}, "children"
          ),
          [
              Input({"type": "var_dropdown", "index": MATCH}, "value"),
              Input({"type": "var_dropdown", "index": MATCH}, "id"),
              Input("add_dropdown_button", "n_clicks"),
          ],
      )
      def display_output(value, id, add_click):
          """
          Function used to create modalities choices. Componenents are different
          according to the type of the selected variable.
          For string variable: component is a dropdown button
          For boolean variable: component is a RadioItems button
          For Integer variable that have less than 20 modalities: component
          is a dropdown button.
          For date variable: component is a DatePickerRange
          Else: components are lower and upper values
          ---------------------------------------------------------------
          value: value selected on the var dropdown button
          id: id of the var dropdown button
          add_click: click on add_dropdown_button
          ---------------------------------------------------------------
          return modalities components. If the component is new, value
          is empty by default.
          """
          # Context and init handling (no action)
          ctx = dash.callback_context
          if not ctx.triggered:
              raise PreventUpdate
          # No update last modalities values if we click on add button
          if (
              ctx.triggered[0]["prop_id"]
              == "add_dropdown_button.n_clicks"
          ):
              raise PreventUpdate
          # Creation on modalities dropdown button
          else:
              if value is not None:
                  new_element = create_filter_modalities_selection(
                      value, id, self.round_dataframe
                  )
              else:
                  new_element = html.Div()
              return new_element
  
imports: import copy
  import dash
  from dash import dash_table
  import dash_daq
  from dash import no_update
  from dash.exceptions import PreventUpdate
  import dash_bootstrap_components
  from dash import dcc
  from dash import html
  from dash import MATCH, ALL
  from dash.dependencies import Output, Input, State
  from flask import Flask
  import pandas
  import plotly.graph_objs
  import random
  import re
  from math import log10
  from shapash.webapp.utils.utils import check_row, get_index_type, round_to_k
  from shapash.webapp.utils.MyGraph import MyGraph
  from shapash.utils.utils import truncate_str
  from shapash.webapp.utils.explanations import Explanations
  from shapash.webapp.utils.callbacks import select_data_from_prediction_picking, select_data_from_str_filters, select_data_from_bool_filters, select_data_from_numeric_filters, select_data_from_date_filters, get_feature_from_clicked_data, get_feature_from_features_groups, get_group_name, get_indexes_from_datatable, update_click_data_on_subset_changes, get_figure_zoom, get_feature_contributions_sign_to_show, update_features_to_display, get_id_card_features, get_id_card_contrib, create_id_card_data, create_id_card_layout, get_feature_filter_options, create_dropdown_feature_filter, create_filter_modalities_selection
label_desc: Use image node_id 12 for calling the SmartApp obj's underlying member method code with example usage: obj.callback_generator() and returns: data,  tooltip_data,  columns,  filtered_subset_info,  filtered_subset_color, figure,  clickData,  clickData_store, fs_figure, selected,  True, str, value, str, value, figure, is_open, style_data_conditional,  style_filter_conditional,  style_header_conditional,  style_cell_conditional, figure,  selectedData, is_open, is_open, is_open, is_open, is_open, disabled, int, dict,  children,  title_contrib, dict,  list,  title_contrib, unknown, unknown, unknown, unknown, unknown, unknown, unknown, dict,  dict, html, html, new_element, value,  max,  marks, list, unknown, dict,  dict, dict,  dict, dict,  dict