code: def plotly_contribution_plot(
      contrib_df,
      target="",
      model_output="raw",
      higher_is_better=True,
      include_base_value=True,
      include_prediction=True,
      orientation="vertical",
      round=2,
      units="",
  ):
      """Generate a shap contributions waterfall plot from a contrib_df dataframe
  
      Args:
          contrib_df (pd.DataFrame): contrib_df generated with get_contrib_df(...)
          target (str, optional): Target variable to be displayed. Defaults to "".
          model_output ({"raw", "logodds", "probability"}, optional): Kind of
              output of the model. Defaults to "raw".
          higher_is_better (bool, optional): Display increases in shap as green,
              decreases as red. Defaults to False.
          include_base_value (bool, optional): Include shap base value in the plot.
              Defaults to True.
          include_prediction (bool, optional): Include the final prediction in
              the plot. Defaults to True.
          orientation ({'vertical', 'horizontal'}, optional): Display the plot
              vertically or horizontally. Defaults to 'vertical'.
          round (int, optional): Round of floats. Defaults to 2.
          units (str, optional): Units of outcome variable.  Defaults to "".
  
      Returns:
          plotly fig:
      """
  
      if orientation not in ["vertical", "horizontal"]:
          raise ValueError(
              f"orientation should be in ['vertical', 'horizontal'], but you passed orientation={orientation}"
          )
      if model_output not in ["raw", "probability", "logodds"]:
          raise ValueError(
              f"model_output should be in ['raw', 'probability', 'logodds'], but you passed orientation={model_output}"
          )
  
      contrib_df = contrib_df.copy()
      try:
          base_value = contrib_df.query("col=='_BASE'")[
              "contribution"
          ].item()
      except:
          base_value = None
  
      if not include_base_value:
          contrib_df = contrib_df[contrib_df.col != "_BASE"]
      if not include_prediction:
          contrib_df = contrib_df[contrib_df.col != "_PREDICTION"]
      contrib_df = contrib_df.replace(
          {
              "_BASE": "Population<br>average",
              "_REST": "Other features combined",
              "_PREDICTION": "Final Prediction",
          }
      )
  
      multiplier = 100 if model_output == "probability" else 1
      contrib_df["base"] = np.round(
          multiplier * contrib_df["base"].astype(float), round
      )
      contrib_df["cumulative"] = np.round(
          multiplier * contrib_df["cumulative"].astype(float), round
      )
      contrib_df["contribution"] = np.round(
          multiplier * contrib_df["contribution"].astype(float), round
      )
  
      if not include_base_value:
          contrib_df = contrib_df[contrib_df.col != "_BASE"]
  
      longest_feature_name = contrib_df["col"].str.len().max()
  
      # prediction is the sum of all contributions:
      prediction = contrib_df["cumulative"].values[-1]
      cols = contrib_df["col"].values.tolist()
      values = contrib_df.value.tolist()
      bases = contrib_df.base.tolist()
      contribs = contrib_df.contribution.tolist()
  
      if "value" in contrib_df.columns:
          hover_text = [
              f"{col}={value}<BR>{'+' if contrib>0 else ''}{contrib} {units}"
              for col, value, contrib in zip(cols, values, contribs)
          ]
      else:
          hover_text = [
              f"{col}=?<BR>{'+' if contrib>0 else ''}{contrib} {units}"
              for col, contrib in zip(cols, contribs)
          ]
  
      green_fill, green_line = (
          "rgba(50, 200, 50, 1.0)",
          "rgba(40, 160, 50, 1.0)",
      )
      yellow_fill, yellow_line = (
          "rgba(230, 230, 30, 1.0)",
          "rgba(190, 190, 30, 1.0)",
      )
      blue_fill, blue_line = (
          "rgba(55, 128, 191, 0.7)",
          "rgba(55, 128, 191, 1.0)",
      )
      red_fill, red_line = (
          "rgba(219, 64, 82, 0.7)",
          "rgba(219, 64, 82, 1.0)",
      )
  
      fill_color_up = green_fill if higher_is_better else red_fill
      fill_color_down = red_fill if higher_is_better else green_fill
      line_color_up = green_line if higher_is_better else red_line
      line_color_down = red_line if higher_is_better else green_line
  
      fill_colors = [
          fill_color_up if y > 0 else fill_color_down for y in contribs
      ]
      line_colors = [
          line_color_up if y > 0 else line_color_down for y in contribs
      ]
      if include_base_value:
          fill_colors[0] = yellow_fill
          line_colors[0] = yellow_line
      if include_prediction:
          fill_colors[-1] = blue_fill
          line_colors[-1] = blue_line
  
      if orientation == "horizontal":
          cols = cols[::-1]
          values = values[::-1]
          contribs = contribs[::-1]
          bases = bases[::-1]
          fill_colors = fill_colors[::-1]
          line_colors = line_colors[::-1]
          hover_text = hover_text[::-1]
  
      # Base of each bar
      trace0 = go.Bar(
          x=bases if orientation == "horizontal" else cols,
          y=cols if orientation == "horizontal" else bases,
          hoverinfo="skip",
          name="",
          marker=dict(
              color="rgba(1,1,1, 0.0)",
          ),
          orientation="h" if orientation == "horizontal" else None,
      )
  
      # top of each bar (base + contribution)
      trace1 = go.Bar(
          x=contribs if orientation == "horizontal" else cols,
          y=cols if orientation == "horizontal" else contribs,
          text=hover_text,
          name="contribution",
          hoverinfo="text",
          marker=dict(
              # blue if positive contribution, red if negative
              color=fill_colors,
              line=dict(
                  color=line_colors,
                  width=2,
              ),
          ),
          orientation="h" if orientation == "horizontal" else None,
      )
  
      if model_output == "probability":
          title = (
              f"Contribution to prediction probability = {prediction}%"
          )
      elif model_output == "logodds":
          title = f"Contribution to prediction logodds = {prediction}"
      else:
          title = f"Contribution to prediction {target} = {prediction} {units}"
  
      data = [trace0, trace1]
      layout = go.Layout(
          height=600
          if orientation == "vertical"
          else 100 + 35 * len(cols),
          title=title,
          barmode="stack",
          plot_bgcolor="#fff",
          showlegend=False,
      )
  
      fig = go.Figure(data=data, layout=layout)
      if (
          model_output == "probability"
          and base_value is not None
          and base_value > 0.3
          and base_value < 0.7
      ):
          # stretch out probability axis to entire probability range (0-100)
          if orientation == "vertical":
              fig.update_yaxes(range=[0, 100])
          elif orientation == "horizontal":
              fig.update_xaxes(range=[0, 100])
  
      fig.update_layout(
          margin=go.layout.Margin(
              l=longest_feature_name * 7
              if orientation == "horizontal"
              else 40,
              r=40,
              b=40
              if orientation == "horizontal"
              else longest_feature_name * 6,
              t=40,
              pad=4,
          ),
          title_x=0.5,
      )
  
      if orientation == "vertical":
          fig.update_yaxes(
              title_text="Predicted "
              + ("%" if model_output == "probability" else units)
          )
      else:
          fig.update_xaxes(
              title_text="Predicted "
              + ("%" if model_output == "probability" else units)
          )
      return fig
  
imports: import warnings
  import numpy
  import pandas
  from pandas.api.types import is_numeric_dtype
  import plotly.graph_objs
  from plotly.subplots import make_subplots
  from sklearn.metrics import classification_report, confusion_matrix, precision_recall_curve, roc_curve, roc_auc_score, average_precision_score
  from .explainer_methods import matching_cols, safe_isinstance
label_desc: Use image node_id 2 for calling a global function with example usage: plotly_contribution_plot(contrib_df, target, model_output, higher_is_better, include_base_value, include_prediction, orientation, round, units) and returns: fig