text: from typing import Any, Dict, List
  
  import datetime
  
  import pandas as pd
  import plotly.express as px
  import plotly.figure_factory as ff
  import plotly.graph_objects as go
  import streamlit as st
  from fbprophet import Prophet
  from fbprophet.plot import plot_plotly
  from plotly.subplots import make_subplots
  from streamlit_prophet.lib.evaluation.metrics import get_perf_metrics
  from streamlit_prophet.lib.evaluation.preparation import get_evaluation_df
  from streamlit_prophet.lib.exposition.expanders import (
      display_expander,
      display_expanders_performance,
  )
  from streamlit_prophet.lib.exposition.preparation import get_forecast_components, prepare_waterfall
  from streamlit_prophet.lib.inputs.dates import input_waterfall_dates
  from streamlit_prophet.lib.utils.misc import reverse_list
  
  
  def plot_overview(
      make_future_forecast: bool,
      use_cv: bool,
      models: Dict[Any, Any],
      forecasts: Dict[Any, Any],
      target_col: str,
      cleaning: Dict[Any, Any],
      readme: Dict[Any, Any],
      report: List[Dict[str, Any]],
  ) -> List[Dict[str, Any]]:
      """Plots a graph with predictions and actual values, with explanations.
  
      Parameters
      ----------
      make_future_forecast : bool
          Whether or not a forecast is made on future dates.
      use_cv : bool
          Whether or not cross-validation is used.
      models : Dict
          Dictionary containing a model fitted on evaluation data and another model fitted on the whole dataset.
      forecasts : Dict
          Dictionary containing evaluation forecasts and future forecasts if a future forecast is made.
      target_col : str
          Name of target column.
      cleaning : Dict
          Cleaning specifications.
      readme : Dict
          Dictionary containing explanations about the graph.
      report: List[Dict[str, Any]]
          List of all report components.
      """
      display_expander(readme, "overview", "More info on this plot")
      bool_param = False if cleaning["log_transform"] else True
      if make_future_forecast:
          model = models["future"]
          forecast = forecasts["future"]
      elif use_cv:
          model = models["eval"]
          forecast = forecasts["cv_with_hist"]
      else:
          model = models["eval"]
          forecast = forecasts["eval"]
      fig = plot_plotly(
          model,
          forecast,
          ylabel=target_col,
          changepoints=bool_param,
          trend=bool_param,
          uncertainty=bool_param,
      )
      st.plotly_chart(fig)
      report.append({"object": fig, "name": "overview", "type": "plot"})
      return report
  
  
  def plot_performance(
      use_cv: bool,
      target_col: str,
      datasets: Dict[Any, Any],
      forecasts: Dict[Any, Any],
      dates: Dict[Any, Any],
      eval: Dict[Any, Any],
      resampling: Dict[Any, Any],
      config: Dict[Any, Any],
      readme: Dict[Any, Any],
      report: List[Dict[str, Any]],
  ) -> List[Dict[str, Any]]:
      """Plots several graphs showing model performance, with explanations.
  
      Parameters
      ----------
      use_cv : bool
          Whether or not cross-validation is used.
      target_col : str
          Name of target column.
      datasets : Dict
          Dictionary containing evaluation dataset.
      forecasts : Dict
          Dictionary containing evaluation forecasts.
      dates : Dict
          Dictionary containing evaluation dates.
      eval : Dict
          Evaluation specifications (metrics, evaluation set, granularity).
      resampling : Dict
          Resampling specifications (granularity, dataset frequency).
      config : Dict
          Cleaning specifications.
      readme : Dict
          Dictionary containing explanations about the graphs.
      report: List[Dict[str, Any]]
          List of all report components.
      """
      style = config["style"]
      evaluation_df = get_evaluation_df(datasets, forecasts, dates, eval, use_cv)
      metrics_df, metrics_dict = get_perf_metrics(
          evaluation_df, eval, dates, resampling, use_cv, config
      )
      st.write("## Performance metrics")
      display_expanders_performance(use_cv, dates, resampling, style, readme)
      display_expander(readme, "helper_metrics", "How to evaluate my model?", True)
      st.write("### Global performance")
      report = display_global_metrics(evaluation_df, eval, dates, resampling, use_cv, config, report)
      st.write("### Deep dive")
      report = plot_detailed_metrics(metrics_df, metrics_dict, eval, use_cv, style, report)
      st.write("## Error analysis")
      display_expander(readme, "helper_errors", "How to troubleshoot forecasting errors?", True)
      fig1 = plot_forecasts_vs_truth(evaluation_df, target_col, use_cv, style)
      fig2 = plot_truth_vs_actual_scatter(evaluation_df, use_cv, style)
      fig3 = plot_residuals_distrib(evaluation_df, use_cv, style)
      st.plotly_chart(fig1)
      st.plotly_chart(fig2)
      st.plotly_chart(fig3)
      report.append({"object": fig1, "name": "eval_forecast_vs_truth_line", "type": "plot"})
      report.append({"object": fig2, "name": "eval_forecast_vs_truth_scatter", "type": "plot"})
      report.append({"object": fig3, "name": "eval_residuals_distribution", "type": "plot"})
      report.append({"object": evaluation_df, "name": "eval_data", "type": "dataset"})
      report.append(
          {"object": metrics_df.reset_index(), "name": "eval_detailed_performance", "type": "dataset"}
      )
      return report
  
  
  def plot_components(
      use_cv: bool,
      make_future_forecast: bool,
      target_col: str,
      models: Dict[Any, Any],
      forecasts: Dict[Any, Any],
      cleaning: Dict[Any, Any],
      resampling: Dict[Any, Any],
      config: Dict[Any, Any],
      readme: Dict[Any, Any],
      df: pd.DataFrame,
      report: List[Dict[str, Any]],
  ) -> List[Dict[str, Any]]:
      """Plots a graph showing the different components of prediction, with explanations.
  
      Parameters
      ----------
      use_cv : bool
          Whether or not cross-validation is used.
      make_future_forecast : bool
          Whether or not a future forecast is made.
      target_col : str
          Name of target column.
      models : Dict
          Dictionary containing a model fitted on evaluation data.
      forecasts : Dict
          Dictionary containing evaluation forecasts.
      cleaning : Dict
          Cleaning specifications.
      resampling : Dict
          Resampling specifications (granularity, dataset frequency).
      config : Dict
          Cleaning specifications.
      readme : Dict
          Dictionary containing explanations about the graph.
      df: pd.DataFrame
          Dataframe containing the ground truth.
      report: List[Dict[str, Any]]
          List of all report components.
      """
      style = config["style"]
      st.write("## Global impact")
      display_expander(readme, "components", "More info on this plot")
      if make_future_forecast:
          forecast_df = forecasts["future"].copy()
          model = models["future"]
      elif use_cv:
          forecast_df = forecasts["cv_with_hist"].copy()
          forecast_df = forecast_df.loc[forecast_df["ds"] < forecasts["cv"].ds.min()]
          model = models["eval"]
      else:
          forecast_df = forecasts["eval"].copy()
          model = models["eval"]
      fig1 = make_separate_components_plot(
          model, forecast_df, target_col, cleaning, resampling, style
      )
      st.plotly_chart(fig1)
  
      st.write("## Local impact")
      display_expander(readme, "waterfall", "More info on this plot", True)
      start_date, end_date = input_waterfall_dates(forecast_df, resampling)
      fig2 = make_waterfall_components_plot(
          model, forecast_df, start_date, end_date, target_col, cleaning, resampling, style, df
      )
      st.plotly_chart(fig2)
  
      report.append({"object": fig1, "name": "global_components", "type": "plot"})
      report.append({"object": fig2, "name": "local_components", "type": "plot"})
      report.append({"object": df, "name": "model_input_data", "type": "dataset"})
  
      return report
  
  
  def plot_future(
      models: Dict[Any, Any],
      forecasts: Dict[Any, Any],
      dates: Dict[Any, Any],
      target_col: str,
      cleaning: Dict[Any, Any],
      readme: Dict[Any, Any],
      report: List[Dict[str, Any]],
  ) -> List[Dict[str, Any]]:
      """Plots a graph with predictions for future dates, with explanations.
  
      Parameters
      ----------
      models : Dict
          Dictionary containing a model fitted on the whole dataset.
      forecasts : Dict
          Dictionary containing future forecast.
      dates : Dict
          Dictionary containing future forecast dates.
      target_col : str
          Name of target column.
      cleaning : Dict
          Cleaning specifications.
      readme : Dict
          Dictionary containing explanations about the graph.
      report: List[Dict[str, Any]]
          List of all report components.
      """
      display_expander(readme, "future", "More info on this plot")
      bool_param = False if cleaning["log_transform"] else True
      fig = plot_plotly(
          models["future"],
          forecasts["future"],
          ylabel=target_col,
          changepoints=bool_param,
          trend=bool_param,
          uncertainty=bool_param,
      )
      fig.update_layout(xaxis_range=[dates["forecast_start_date"], dates["forecast_end_date"]])
      st.plotly_chart(fig)
      report.append({"object": fig, "name": "future_forecast", "type": "plot"})
      report.append({"object": forecasts["future"], "name": "future_forecast", "type": "dataset"})
      return report
  
  
  def plot_forecasts_vs_truth(
      eval_df: pd.DataFrame, target_col: str, use_cv: bool, style: Dict[Any, Any]
  ) -> go.Figure:
      """Creates a plotly line plot showing forecasts and actual values on evaluation period.
  
      Parameters
      ----------
      eval_df : pd.DataFrame
          Evaluation dataframe.
      target_col : str
          Name of target column.
      use_cv : bool
          Whether or not cross-validation is used.
      style : Dict
          Style specifications for the graph (colors).
  
      Returns
      -------
      go.Figure
          Plotly line plot showing forecasts and actual values on evaluation period.
      """
      if use_cv:
          colors = reverse_list(style["colors"], eval_df["Fold"].nunique())
          fig = px.line(
              eval_df,
              x="ds",
              y="forecast",
              color="Fold",
              color_discrete_sequence=colors,
          )
          fig.add_trace(
              go.Scatter(
                  x=eval_df["ds"],
                  y=eval_df["truth"],
                  name="Truth",
                  mode="lines",
                  line={"color": style["color_axis"], "dash": "dot", "width": 1.5},
              )
          )
      else:
          fig = px.line(
              eval_df,
              x="ds",
              y=["truth", "forecast"],
              color_discrete_sequence=style["colors"][1:],
              hover_data={"variable": True, "value": ":.4f", "ds": False},
          )
      fig.update_xaxes(
          rangeslider_visible=True,
          rangeselector=dict(
              buttons=list(
                  [
                      dict(count=7, label="1w", step="day", stepmode="backward"),
                      dict(count=1, label="1m", step="month", stepmode="backward"),
                      dict(count=3, label="3m", step="month", stepmode="backward"),
                      dict(count=6, label="6m", step="month", stepmode="backward"),
                      dict(count=1, label="YTD", step="year", stepmode="todate"),
                      dict(count=1, label="1y", step="year", stepmode="backward"),
                      dict(step="all"),
                  ]
              )
          ),
      )
      fig.update_layout(
          yaxis_title=target_col,
          legend_title_text="",
          height=500,
          width=800,
          title_text="Forecast vs Truth",
          title_x=0.5,
          title_y=1,
          hovermode="x unified",
      )
      return fig
  
  
  def plot_truth_vs_actual_scatter(
      eval_df: pd.DataFrame, use_cv: bool, style: Dict[Any, Any]
  ) -> go.Figure:
      """Creates a plotly scatter plot showing forecasts and actual values on evaluation period.
  
      Parameters
      ----------
      eval_df : pd.DataFrame
          Evaluation dataframe.
      use_cv : bool
          Whether or not cross-validation is used.
      style : Dict
          Style specifications for the graph (colors).
  
      Returns
      -------
      go.Figure
          Plotly scatter plot showing forecasts and actual values on evaluation period.
      """
      eval_df["date"] = eval_df["ds"].map(lambda x: x.strftime("%A %b %d %Y"))
      if use_cv:
          colors = reverse_list(style["colors"], eval_df["Fold"].nunique())
          fig = px.scatter(
              eval_df,
              x="truth",
              y="forecast",
              color="Fold",
              opacity=0.5,
              color_discrete_sequence=colors,
              hover_data={"date": True, "truth": ":.4f", "forecast": ":.4f"},
          )
      else:
          fig = px.scatter(
              eval_df,
              x="truth",
              y="forecast",
              opacity=0.5,
              color_discrete_sequence=style["colors"][2:],
              hover_data={"date": True, "truth": ":.4f", "forecast": ":.4f"},
          )
      fig.add_trace(
          go.Scatter(
              x=eval_df["truth"],
              y=eval_df["truth"],
              name="optimal",
              mode="lines",
              line=dict(color=style["color_axis"], width=1.5),
          )
      )
      fig.update_layout(
          xaxis_title="Truth", yaxis_title="Forecast", legend_title_text="", height=450, width=800
      )
      return fig
  
  
  def plot_residuals_distrib(eval_df: pd.DataFrame, use_cv: bool, style: Dict[Any, Any]) -> go.Figure:
      """Creates a plotly distribution plot showing distribution of residuals on evaluation period.
  
      Parameters
      ----------
      eval_df : pd.DataFrame
          Evaluation dataframe.
      use_cv : bool
          Whether or not cross-validation is used.
      style : Dict
          Style specifications for the graph (colors).
  
      Returns
      -------
      go.Figure
          Plotly distribution plot showing distribution of residuals on evaluation period.
      """
      eval_df["residuals"] = eval_df["forecast"] - eval_df["truth"]
      if len(eval_df) >= 10:
          x_min, x_max = eval_df["residuals"].quantile(0.005), eval_df["residuals"].quantile(0.995)
      else:
          x_min, x_max = eval_df["residuals"].min(), eval_df["residuals"].max()
      if use_cv:
          labels = sorted(eval_df["Fold"].unique(), reverse=True)
          residuals = [eval_df.loc[eval_df["Fold"] == fold, "residuals"] for fold in labels]
          residuals = [x[x.between(x_min, x_max)] for x in residuals]
      else:
          labels = [""]
          residuals_series = pd.Series(eval_df["residuals"])
          residuals = [residuals_series[residuals_series.between(x_min, x_max)]]
      colors = (
          reverse_list(style["colors"], eval_df["Fold"].nunique()) if use_cv else [style["colors"][2]]
      )
      fig = ff.create_distplot(residuals, labels, show_hist=False, colors=colors)
      fig.update_layout(
          title_text="Distribution of errors",
          title_x=0.5,
          title_y=0.85,
          xaxis_title="Error (Forecast - Truth)",
          showlegend=True if use_cv else False,
          xaxis_zeroline=True,
          xaxis_zerolinecolor=style["color_axis"],
          xaxis_zerolinewidth=1,
          yaxis_zeroline=True,
          yaxis_zerolinecolor=style["color_axis"],
          yaxis_zerolinewidth=1,
          yaxis_rangemode="tozero",
          height=500,
          width=800,
      )
      return fig
  
  
  def plot_detailed_metrics(
      metrics_df: pd.DataFrame,
      perf: Dict[Any, Any],
      eval: Dict[Any, Any],
      use_cv: bool,
      style: Dict[Any, Any],
      report: List[Dict[str, Any]],
  ) -> List[Dict[str, Any]]:
      """Displays a dataframe or plots graphs showing model performance on selected metrics.
  
      Parameters
      ----------
      metrics_df : pd.DataFrame
          Dataframe containing model performance on different metrics at the desired granularity.
      perf : Dict
          Dictionary containing model performance on different metrics at the desired granularity.
      eval : Dict
          Evaluation specifications (evaluation set, selected metrics, granularity).
      use_cv : bool
          Whether or not cross-validation is used.
      style : Dict
          Style specifications for the graph (colors).
      report: List[Dict[str, Any]]
          List of all report components.
      """
      metrics = [metric for metric in perf.keys() if perf[metric][eval["granularity"]].nunique() > 1]
      if len(metrics) > 0:
          fig = make_subplots(
              rows=len(metrics) // 2 + len(metrics) % 2, cols=2, subplot_titles=metrics
          )
          for i, metric in enumerate(metrics):
              colors = (
                  style["colors"]
                  if use_cv
                  else [style["colors"][i % len(style["colors"])]]
                  * perf[metric][eval["granularity"]].nunique()
              )
              fig_metric = go.Bar(
                  x=perf[metric][eval["granularity"]], y=perf[metric][metric], marker_color=colors
              )
              fig.append_trace(fig_metric, row=i // 2 + 1, col=i % 2 + 1)
          fig.update_layout(
              height=300 * (len(metrics) // 2 + len(metrics) % 2),
              width=1000,
              showlegend=False,
          )
          st.plotly_chart(fig)
          report.append({"object": fig, "name": "eval_detailed_performance", "type": "plot"})
      else:
          st.dataframe(metrics_df)
      return report
  
  
  def make_separate_components_plot(
      model: Prophet,
      forecast_df: pd.DataFrame,
      target_col: str,
      cleaning: Dict[Any, Any],
      resampling: Dict[Any, Any],
      style: Dict[Any, Any],
  ) -> go.Figure:
      """Creates plotly area charts with the components of the prediction, each one on its own subplot.
  
      Parameters
      ----------
      model : Prophet
          Fitted model.
      forecast_df : pd.DataFrame
          Predictions of Prophet model.
      target_col : str
          Name of target column.
      cleaning : Dict
          Cleaning specifications.
      resampling : Dict
          Resampling specifications (granularity, dataset frequency).
      style : Dict
          Style specifications for the graph (colors).
  
      Returns
      -------
      go.Figure
          Plotly area charts with the components of the prediction, each one on its own subplot.
      """
      components = get_forecast_components(model, forecast_df)
      features = components.columns
      n_features = len(components.columns)
      fig = make_subplots(rows=n_features, cols=1, subplot_titles=features)
      for i, col in enumerate(features):
          if col == "daily":
              hours = forecast_df["ds"].groupby(forecast_df.ds.dt.hour).last()
              values = forecast_df.loc[forecast_df.ds.isin(hours), ("ds", col)]
              values = values.iloc[values.ds.dt.hour.values.argsort()]  # sort by hour order
              y = values[col]
              x = values.ds.map(lambda h: h.strftime("%H:%M"))
          elif col == "weekly":
              days = forecast_df["ds"].groupby(forecast_df.ds.dt.dayofweek).last()
              values = forecast_df.loc[forecast_df.ds.isin(days), ("ds", col)]
              values = values.iloc[
                  values.ds.dt.dayofweek.values.argsort()
              ]  # sort by day of week order
              y = values[col]
              x = values.ds.dt.day_name()
          elif col == "monthly":
              days = forecast_df["ds"].groupby(forecast_df.ds.dt.day).last()
              values = forecast_df.loc[forecast_df.ds.isin(days), ("ds", col)]
              values = values.iloc[values.ds.dt.day.values.argsort()]  # sort by day of month order
              y = values[col]
              x = values.ds.dt.day
          elif col == "yearly":
              year = forecast_df["ds"].max().year - 1
              days = pd.date_range(start=f"{year}-01-01", end=f"{year}-12-31")
              y = forecast_df.loc[forecast_df["ds"].isin(days), col]
              x = days.dayofyear
          else:
              x = components.index
              y = components[col]
          fig.append_trace(
              go.Scatter(
                  x=x,
                  y=y,
                  fill="tozeroy",
                  name=col,
                  mode="lines",
                  line=dict(color=style["colors"][i % len(style["colors"])]),
              ),
              row=i + 1,
              col=1,
          )
  
          y_label = f"log {target_col}" if cleaning["log_transform"] else target_col
          fig.update_yaxes(title_text=f"{y_label} / {resampling['freq']}", row=i + 1, col=1)
          fig.update_xaxes(showgrid=False)
          if col == "yearly":
              fig["layout"][f"xaxis{i + 1}"].update(
                  tickmode="array",
                  tickvals=[1, 61, 122, 183, 244, 305],
                  ticktext=["Jan", "Mar", "May", "Jul", "Sep", "Nov"],
              )
      fig.update_layout(height=200 * n_features if n_features > 1 else 300, width=800)
      return fig
  
  
  def make_waterfall_components_plot(
      model: Prophet,
      forecast_df: pd.DataFrame,
      start_date: datetime.date,
      end_date: datetime.date,
      target_col: str,
      cleaning: Dict[Any, Any],
      resampling: Dict[Any, Any],
      style: Dict[Any, Any],
      df: pd.DataFrame,
  ) -> go.Figure:
      """Creates a waterfall chart with the components of the prediction.
  
      Parameters
      ----------
      model : Prophet
          Fitted model.
      forecast_df : pd.DataFrame
          Predictions of Prophet model.
      start_date : datetime.date
          Start date for components computation.
      end_date : datetime.date
          End date for components computation.
      target_col : str
          Name of target column.
      cleaning : Dict
          Cleaning specifications.
      resampling : Dict
          Resampling specifications (granularity, dataset frequency).
      style : Dict
          Style specifications for the graph (colors).
      df: pd.DataFrame
          Dataframe containing the ground truth.
  
      Returns
      -------
      go.Figure
          Waterfall chart with the components of prediction.
      """
      N_digits = style["waterfall_digits"]
      components = get_forecast_components(model, forecast_df, True).reset_index()
      waterfall = prepare_waterfall(components, start_date, end_date)
      truth = df.loc[
          (df["ds"] >= pd.to_datetime(start_date)) & (df["ds"] < pd.to_datetime(end_date)), "y"
      ].mean(axis=0)
      fig = go.Figure(
          go.Waterfall(
              orientation="v",
              measure=["relative"] * (len(waterfall) - 1) + ["total"],
              x=[x.capitalize() for x in list(waterfall.index)[:-1] + ["Forecast (Truth)"]],
              y=list(waterfall.values),
              textposition="auto",
              text=[
                  "+" + str(round(x, N_digits)) if x > 0 else "" + str(round(x, N_digits))
                  for x in list(waterfall.values)[:-1]
              ]
              + [f"{round(waterfall.values[-1], N_digits)} ({round(truth, N_digits)})"],
              decreasing={"marker": {"color": style["colors"][1]}},
              increasing={"marker": {"color": style["colors"][0]}},
              totals={"marker": {"color": style["colors"][2]}},
          )
      )
      y_label = f"log {target_col}" if cleaning["log_transform"] else target_col
      fig.update_yaxes(title_text=f"{y_label} / {resampling['freq']}")
      fig.update_layout(
          title=f"Forecast decomposition "
          f"(from {start_date.strftime('%Y-%m-%d')} to {end_date.strftime('%Y-%m-%d')})",
          title_x=0.2,
          width=800,
      )
      return fig
  
  
  def display_global_metrics(
      evaluation_df: pd.DataFrame,
      eval: Dict[Any, Any],
      dates: Dict[Any, Any],
      resampling: Dict[Any, Any],
      use_cv: bool,
      config: Dict[Any, Any],
      report: List[Dict[str, Any]],
  ) -> List[Dict[str, Any]]:
      """Displays all global metrics.
  
      Parameters
      ----------
      evaluation_df : pd.DataFrame
          Evaluation dataframe.
      eval : Dict
          Evaluation specifications.
      dates : Dict
          Dictionary containing all dates information.
      resampling : Dict
          Resampling specifications.
      use_cv : bool
          Whether or note cross-validation is used.
      config : Dict
          Lib configuration dictionary.
      report: List[Dict[str, Any]]
          List of all report components.
      """
      eval_all = {
          "granularity": "cutoff" if use_cv else "Global",
          "metrics": ["RMSE", "MAPE", "MAE", "MSE", "SMAPE"],
          "get_perf_on_agg_forecast": eval["get_perf_on_agg_forecast"],
      }
      metrics_df, _ = get_perf_metrics(evaluation_df, eval_all, dates, resampling, use_cv, config)
      if use_cv:
          st.dataframe(metrics_df)
      else:
          col1, col2, col3, col4, col5 = st.columns(5)
          col1.markdown(
              f"<p style='color: {config['style']['colors'][1]}; "
              f"font-weight: bold; font-size: 20px;'> {eval_all['metrics'][0]}</p>",
              unsafe_allow_html=True,
          )
          col1.write(metrics_df.loc["Global", eval_all["metrics"][0]])
          col2.markdown(
              f"<p style='color: {config['style']['colors'][1]}; "
              f"font-weight: bold; font-size: 20px;'> {eval_all['metrics'][1]}</p>",
              unsafe_allow_html=True,
          )
          col2.write(metrics_df.loc["Global", eval_all["metrics"][1]])
          col3.markdown(
              f"<p style='color: {config['style']['colors'][1]}; "
              f"font-weight: bold; font-size: 20px;'> {eval_all['metrics'][2]}</p>",
              unsafe_allow_html=True,
          )
          col3.write(metrics_df.loc["Global", eval_all["metrics"][2]])
          col4.markdown(
              f"<p style='color: {config['style']['colors'][1]}; "
              f"font-weight: bold; font-size: 20px;'> {eval_all['metrics'][3]}</p>",
              unsafe_allow_html=True,
          )
          col4.write(metrics_df.loc["Global", eval_all["metrics"][3]])
          col5.markdown(
              f"<p style='color: {config['style']['colors'][1]}; "
              f"font-weight: bold; font-size: 20px;'> {eval_all['metrics'][4]}</p>",
              unsafe_allow_html=True,
          )
          col5.write(metrics_df.loc["Global", eval_all["metrics"][4]])
          report.append(
              {
                  "object": metrics_df.loc["Global"].reset_index(),
                  "name": "eval_global_performance",
                  "type": "dataset",
              }
          )
      return report
  