code: def plotly_plot_residuals(
      y,
      preds,
      vs_actual=False,
      target="",
      units="",
      residuals="difference",
      round=2,
      idxs=None,
      index_name="index",
  ):
      """generates a residual plot
  
      Args:
          y (np.array, pd.Series): Actual values
          preds (np.array, pd.Series): Predictions
          vs_actual (bool, optional): Put actual values (y) on the x-axis.
                      Defaults to False (i.e. preds on the x-axis)
          target (str, optional): name of the target variable. Defaults to ""
          units (str, optional): units of the axis. Defaults to "".
          residuals (str, {'difference', 'ratio', 'log-ratio'} optional):
                      How to calcualte residuals. Defaults to 'difference'.
          round (int, optional): [description]. Defaults to 2.
          idxs ([type], optional): [description]. Defaults to None.
          index_name (str): identifier for idxs. Defaults to "index".
  
      Returns:
          [type]: [description]
      """
      if idxs is not None:
          assert len(idxs) == len(preds)
          idxs = [str(idx) for idx in idxs]
      else:
          idxs = [str(i) for i in range(len(preds))]
  
      res = y - preds
      res_ratio = y / preds
  
      if residuals == "log-ratio":
          residuals_display = np.log(res_ratio)
          residuals_name = "residuals log ratio<br>(log(y/preds))"
      elif residuals == "ratio":
          residuals_display = res_ratio
          residuals_name = "residuals ratio<br>(y/preds)"
      elif residuals == "difference":
          residuals_display = res
          residuals_name = "residuals (y-preds)"
      else:
          raise ValueError(
              f"parameter residuals should be in ['difference', "
              f"'ratio', 'log-ratio'] but is equal to {residuals}!"
          )
  
      residuals_text = [
          f"{index_name}: {idx}<br>Observed: {actual:.{round}f}<br>Prediction: {pred:.{round}f}<br>Residual: {residual:.{round}f}"
          for idx, actual, pred, residual in zip(idxs, y, preds, res)
      ]
      trace0 = go.Scattergl(
          x=y if vs_actual else preds,
          y=residuals_display,
          mode="markers",
          name=residuals_name,
          text=residuals_text,
          hoverinfo="text",
      )
  
      trace1 = go.Scattergl(
          x=y if vs_actual else preds,
          y=np.ones(len(preds))
          if residuals == "ratio"
          else np.zeros(len(preds)),
          mode="lines",
          name=(f"Observed {target}" + f" ({units})" if units else "")
          if vs_actual
          else (f"Predicted {target}" + f" ({units})" if units else ""),
          hoverinfo="none",
      )
  
      data = [trace0, trace1]
  
      layout = go.Layout(
          title=f"Residuals vs {'observed' if vs_actual else 'predicted'} {target}",
          yaxis=dict(title=residuals_name),
          xaxis=dict(
              title=(
                  f"Observed {target}" + f" ({units})" if units else ""
              )
              if vs_actual
              else (
                  f"Predicted {target}" + f" ({units})" if units else ""
              )
          ),
          plot_bgcolor="#fff",
          hovermode="closest",
      )
  
      fig = go.Figure(data, layout)
      fig.update_layout(margin=dict(t=40, b=40, l=40, r=40))
      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 16 for calling a global function with example usage: plotly_plot_residuals(y, preds, vs_actual, target, units, residuals, round, idxs, index_name) and returns: fig