code: def test_plot_flexible_grouping_evaluation():
      """Tests plot_flexible_grouping_evaluation function"""
      df = gen_sliced_df(
          sample_size_dict={
              "a": 300,
              "b": 200,
              "c": 300,
              "d": 80,
              "e": 300,
          }
      )
      actual_col = "y"
      predicted_col = "y_hat"
      groupby_col = "x"
      groupby_col2 = "z"
      df = df[[actual_col, predicted_col, groupby_col, groupby_col2]]
      df[cst.TIME_COL] = pd.date_range(
          start="2020-01-01", periods=df.shape[0], freq="D"
      )
      end_index = math.floor(df.shape[0] * 0.8)
      forecast = UnivariateForecast(
          df,
          train_end_date=df[cst.TIME_COL][end_index],
          time_col=cst.TIME_COL,
          actual_col=actual_col,
          predicted_col=predicted_col,
          predicted_lower_col=None,
          predicted_upper_col=None,
          null_model_predicted_col=None,
      )
  
      # MSE and quantiles of squared error
      metric_col = "squared_err"
      map_func_dict = {
          metric_col: ElementwiseEvaluationMetricEnum.SquaredError.name
      }
      agg_kwargs = {
          f"Q{quantile}": pd.NamedAgg(
              column=metric_col,
              aggfunc=partial(np.nanquantile, q=quantile),
          )
          for quantile in [0.1, 0.9]
      }
      agg_kwargs.update(
          {"mean": pd.NamedAgg(column=metric_col, aggfunc=np.nanmean)}
      )
  
      # group by "dom", "auto-fill" styling
      fig = forecast.plot_flexible_grouping_evaluation(
          which="train",
          groupby_time_feature="dom",
          groupby_sliding_window_size=None,
          groupby_custom_column=None,
          map_func_dict=map_func_dict,
          agg_kwargs=agg_kwargs,
          extend_col_names=False,
          y_col_style_dict="auto-fill",
          default_color="rgba(0, 145, 202, 1.0)",
          xlabel=None,
          ylabel=metric_col,
          title=None,
          showlegend=True,
      )
  
      assert [fig.data[i].name for i in range(len(fig.data))] == [
          "Q0.1",
          "mean",
          "Q0.9",
      ]
      assert fig.layout.xaxis.title.text == "dom"
      assert fig.layout.yaxis.title.text == metric_col
      assert fig.layout.title.text == f"{metric_col} vs dom"
      assert fig.layout.title.x == 0.5
      assert fig.data[0].x.shape[0] == 31  # 31 unique days in month
      assert fig.data[1].line["color"] == "rgba(0, 145, 202, 1.0)"
      assert fig.data[1].fill == "tonexty"  # from auto-fill
      assert fig.layout.showlegend
  
      # group by sliding window, "auto" styling
      # provide default color, xlabel, hide legend
      fig = forecast.plot_flexible_grouping_evaluation(
          which="train",
          groupby_time_feature=None,
          groupby_sliding_window_size=7,
          groupby_custom_column=None,
          map_func_dict=map_func_dict,
          agg_kwargs=agg_kwargs,
          extend_col_names=False,
          y_col_style_dict="auto",
          default_color="rgba(145, 0, 202, 1.0)",
          xlabel="ts",
          ylabel=None,
          title=None,
          showlegend=False,
      )
  
      assert [fig.data[i].name for i in range(len(fig.data))] == [
          "Q0.1",
          "mean",
          "Q0.9",
      ]
      assert fig.layout.xaxis.title.text == "ts"
      assert fig.layout.yaxis.title.text is None
      assert fig.layout.title.text is None
      assert fig.layout.title.x == 0.5
      assert fig.data[0].x[0] == datetime.datetime(2020, 1, 1, 0, 0)
      assert fig.data[1].line["color"] == "rgba(145, 0, 202, 1.0)"
      assert fig.data[1].fill is None
      assert not fig.layout.showlegend
  
      # custom groups, "plotly" styling, provide ylabel, title
      fig = forecast.plot_flexible_grouping_evaluation(
          which="train",
          groupby_time_feature=None,
          groupby_sliding_window_size=None,
          groupby_custom_column=forecast.df_train["x"],
          map_func_dict=map_func_dict,
          agg_kwargs=agg_kwargs,
          extend_col_names=False,
          y_col_style_dict="plotly",
          default_color=None,
          xlabel=None,
          ylabel=metric_col,
          title="custom title",
          showlegend=True,
      )
  
      assert [fig.data[i].name for i in range(len(fig.data))] == [
          "Q0.1",
          "Q0.9",
          "mean",
      ]  # not sorted
      assert fig.layout.xaxis.title.text == "x"
      assert fig.layout.yaxis.title.text == metric_col
      assert fig.layout.title.text == "custom title"
      assert fig.layout.title.x == 0.5
      assert list(fig.data[0].x) == list("abcde")
      assert fig.data[0].line["color"] is None  # color is up to plotly
      assert fig.data[1].fill is None
      assert fig.layout.showlegend
  
      # test set, absolute percent error, custom `y_col_style_dict` styling
      metric_col = "squared_error"
      map_func_dict = {
          metric_col: ElementwiseEvaluationMetricEnum.AbsolutePercentError.name
      }
      agg_kwargs = {
          "median": pd.NamedAgg(
              column=metric_col, aggfunc=np.nanmedian
          ),
          "mean": pd.NamedAgg(column=metric_col, aggfunc=np.nanmean),
      }
      y_col_style_dict = {
          "median": {
              "mode": "lines+markers",
              "line": {"color": "rgba(202, 145, 0, 0.5)"},
          },
          "mean": {
              "mode": "lines+markers",
              "line": {"color": "rgba(0, 145, 202, 1.0)"},
          },
      }
      with pytest.warns(
          UserWarning, match="true_val is less than 1e-8"
      ):
          fig = forecast.plot_flexible_grouping_evaluation(
              which="test",
              groupby_time_feature="dow",
              groupby_sliding_window_size=None,
              groupby_custom_column=None,
              map_func_dict=map_func_dict,
              agg_kwargs=agg_kwargs,
              extend_col_names=False,
              y_col_style_dict=y_col_style_dict,
              xlabel="x value",
              ylabel="y value",
              title="error plot",
              showlegend=True,
          )
          assert [fig.data[i].name for i in range(len(fig.data))] == [
              "median",
              "mean",
          ]  # not sorted
          assert fig.layout.xaxis.title.text == "x value"
          assert fig.layout.yaxis.title.text == "y value"
          assert fig.layout.title.text == "error plot"
          assert fig.layout.title.x == 0.5
          assert len(fig.data[0].x) == 7
          assert fig.data[0].mode == "lines+markers"
          assert fig.data[1].mode == "lines+markers"
          assert (
              fig.data[0].line["color"]
              == y_col_style_dict["median"]["line"]["color"]
          )
          assert (
              fig.data[1].line["color"]
              == y_col_style_dict["mean"]["line"]["color"]
          )
          assert fig.data[1].fill is None
          assert fig.layout.showlegend
  
      # median actual vs forecast value by group
      agg_kwargs = {
          "y_median": pd.NamedAgg(column="y", aggfunc=np.nanmedian),
          "y_hat_median": pd.NamedAgg(
              column="y_hat", aggfunc=np.nanmedian
          ),
      }
      fig = forecast.plot_flexible_grouping_evaluation(
          which="train",
          groupby_time_feature="dow",
          groupby_sliding_window_size=None,
          groupby_custom_column=None,
          map_func_dict=None,
          agg_kwargs=agg_kwargs,
          extend_col_names=True,
          y_col_style_dict="plotly",
          xlabel=None,
          ylabel=forecast.ylabel,
          title="true vs actual by dow",
          showlegend=True,
      )
      assert [fig.data[i].name for i in range(len(fig.data))] == [
          "y_median",
          "y_hat_median",
      ]
      assert fig.layout.xaxis.title.text == "dow"
      assert fig.layout.yaxis.title.text == "y"
      assert fig.layout.title.text == "true vs actual by dow"
      assert fig.layout.title.x == 0.5
      assert len(fig.data[0].x) == 7
      assert fig.layout.showlegend
  
imports: import datetime
  import math
  import sys
  from functools import partial
  import numpy
  import pandas
  import pytest
  from pandas.testing import assert_frame_equal
  from pandas.testing import assert_series_equal
  from sklearn.pipeline import Pipeline
  from greykite.common import constants
  from greykite.common.evaluation import ElementwiseEvaluationMetricEnum
  from greykite.common.evaluation import EvaluationMetricEnum
  from greykite.common.python_utils import assert_equal
  from greykite.common.testing_utils import gen_sliced_df
  from greykite.framework.input.univariate_time_series import UnivariateTimeSeries
  from greykite.framework.output.univariate_forecast import UnivariateForecast
  from greykite.framework.pipeline.utils import get_forecast
  from greykite.sklearn.estimator.prophet_estimator import ProphetEstimator
  from greykite.sklearn.estimator.silverkite_estimator import SilverkiteEstimator
  from greykite.sklearn.estimator.testing_utils import params_component_breakdowns
label_desc: Use image node_id 16 for calling a global function with example usage: test_plot_flexible_grouping_evaluation() without return types