code: def tile_fitted(
      model: ModelBridge,
      generator_runs_dict: TNullableGeneratorRunsDict = None,
      rel: bool = True,
      show_arm_details_on_hover: bool = False,
      show_CI: bool = True,
      arm_noun: str = "arm",
      metrics: Optional[List[str]] = None,
      fixed_features: Optional[ObservationFeatures] = None,
      data_selector: Optional[Callable[[Observation], bool]] = None,
      scalarized_metric_config: Optional[List[Dict[str, Any]]] = None,
      label_dict: Optional[Dict[str, str]] = None,
  ) -> AxPlotConfig:
      """Tile version of fitted outcome plots.
  
      Args:
          model: model to use for predictions.
          generator_runs_dict: a mapping from
              generator run name to generator run.
          rel: if True, use relative effects. Default is True.
          show_arm_details_on_hover: if True, display
              parameterizations of arms on hover. Default is False.
          show_CI: if True, render confidence intervals.
          arm_noun: noun to use instead of "arm" (e.g. group)
          metrics: List of metric names to restrict to when plotting.
          fixed_features: Fixed features to use when making model predictions.
          data_selector: Function for selecting observations for plotting.
          scalarized_metric_config: An optional list of dicts specifying how to aggregate
              multiple metrics into a single scalarized metric. For each dict, the key is
              the name of the new scalarized metric, and the value is a dictionary mapping
              each metric to its weight. e.g.
              {"name": "metric1:agg", "weight": {"metric1_c1": 0.5, "metric1_c2": 0.5}}.
          label_dict: A dictionary that maps the label to an alias to be used in the plot.
      """
      metrics = metrics or list(model.metric_names)
      nrows = int(np.ceil(len(metrics) / 2))
      ncols = min(len(metrics), 2)
  
      # make subplots (plot per row)
      if label_dict is None:
          subplot_titles = metrics
      else:
          subplot_titles = [
              label_dict.get(metric, metric) for metric in metrics
          ]
      fig = subplots.make_subplots(
          rows=nrows,
          cols=ncols,
          print_grid=False,
          shared_xaxes=False,
          shared_yaxes=False,
          subplot_titles=tuple(subplot_titles),
          horizontal_spacing=0.05,
          vertical_spacing=0.30 / nrows,
      )
  
      name_order_args: Dict[str, Any] = {}
      name_order_axes: Dict[str, Dict[str, Any]] = {}
      effect_order_args: Dict[str, Any] = {}
  
      for i, metric in enumerate(metrics):
          data = _single_metric_traces(
              model,
              metric,
              generator_runs_dict,
              rel,
              showlegend=i == 0,
              show_arm_details_on_hover=show_arm_details_on_hover,
              show_CI=show_CI,
              arm_noun=arm_noun,
              fixed_features=fixed_features,
              data_selector=data_selector,
              scalarized_metric_config=scalarized_metric_config,
          )
  
          # order arm name sorting arm numbers within batch
          names_by_arm = sorted(
              np.unique(np.concatenate([d["x"] for d in data])),
              key=lambda x: arm_name_to_tuple(x),
          )
  
          # get arm names sorted by effect size
          names_by_effect = list(
              OrderedDict.fromkeys(
                  np.concatenate([d["x"] for d in data])
                  .flatten()
                  .take(
                      np.argsort(
                          np.concatenate(
                              [d["y"] for d in data]
                          ).flatten()
                      )
                  )
              )
          )
  
          # options for ordering arms (x-axis)
          # Note that xaxes need to be references as xaxis, xaxis2, xaxis3, etc.
          # for the purposes of updatemenus argument (dropdown) in layout.
          # However, when setting the initial ordering layout, the keys should be
          # xaxis1, xaxis2, xaxis3, etc. Note the discrepancy for the initial
          # axis.
          label = "" if i == 0 else i + 1
          name_order_args[
              "xaxis{}.categoryorder".format(label)
          ] = "array"
          name_order_args[
              "xaxis{}.categoryarray".format(label)
          ] = names_by_arm
          effect_order_args[
              "xaxis{}.categoryorder".format(label)
          ] = "array"
          effect_order_args[
              "xaxis{}.categoryarray".format(label)
          ] = names_by_effect
          name_order_axes["xaxis{}".format(i + 1)] = {
              "categoryorder": "array",
              "categoryarray": names_by_arm,
              "type": "category",
          }
          name_order_axes["yaxis{}".format(i + 1)] = {
              "ticksuffix": "%" if rel else "",
              "zerolinecolor": "red",
          }
          for d in data:
              fig.append_trace(  # pyre-ignore[16]
                  d, int(np.floor(i / ncols)) + 1, i % ncols + 1
              )
  
      order_options = [
          {
              "args": [name_order_args],
              "label": "Name",
              "method": "relayout",
          },
          {
              "args": [effect_order_args],
              "label": "Effect Size",
              "method": "relayout",
          },
      ]
  
      # if odd number of plots, need to manually remove the last blank subplot
      # generated by `subplots.make_subplots`
      if len(metrics) % 2 == 1:
          fig["layout"].pop("xaxis{}".format(nrows * ncols))
          fig["layout"].pop("yaxis{}".format(nrows * ncols))
  
      # allocate 400 px per plot
      fig["layout"].update(
          margin={"t": 0},
          hovermode="closest",
          updatemenus=[
              {
                  "x": 0.15,
                  "y": 1 + 0.40 / nrows,
                  "buttons": order_options,
                  "xanchor": "left",
                  "yanchor": "middle",
              }
          ],
          font={"size": 10},
          width=650 if ncols == 1 else 950,
          height=300 * nrows,
          legend={
              "orientation": "h",
              "x": 0,
              "y": 1 + 0.20 / nrows,
              "xanchor": "left",
              "yanchor": "middle",
          },
          **name_order_axes,
      )
  
      # append dropdown annotations
      fig["layout"]["annotations"] = fig["layout"]["annotations"] + (
          {
              "x": 0.5,
              "y": 1 + 0.40 / nrows,
              "xref": "paper",
              "yref": "paper",
              "font": {"size": 14},
              "text": "Predicted Outcomes",
              "showarrow": False,
              "xanchor": "center",
              "yanchor": "middle",
          },
          {
              "x": 0.05,
              "y": 1 + 0.40 / nrows,
              "xref": "paper",
              "yref": "paper",
              "text": "Sort By",
              "showarrow": False,
              "xanchor": "left",
              "yanchor": "middle",
          },
      )
  
      fig = resize_subtitles(figure=fig, size=10)
      return AxPlotConfig(data=fig, plot_type=AxPlotTypes.GENERIC)
  
imports: import numbers
  import warnings
  from collections import OrderedDict
  from logging import Logger
  from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Union
  import numpy
  import plotly.graph_objs
  from ax.core.data import Data
  from ax.core.experiment import Experiment
  from ax.core.observation import Observation, ObservationFeatures
  from ax.modelbridge.base import ModelBridge
  from ax.modelbridge.registry import Models
  from ax.plot.base import AxPlotConfig, AxPlotTypes, CI_OPACITY, DECIMALS, PlotInSampleArm, PlotMetric, PlotOutOfSampleArm, Z
  from ax.plot.color import BLUE_SCALE, COLORS, DISCRETE_COLOR_SCALE, rgba
  from ax.plot.helper import _format_CI, _format_dict, _wrap_metric, arm_name_to_sort_key, arm_name_to_tuple, get_plot_data, infer_is_relative, resize_subtitles, TNullableGeneratorRunsDict
  from ax.utils.common.logger import get_logger
  from ax.utils.common.typeutils import checked_cast_optional
  from ax.utils.stats.statstools import relativize
  from plotly import subplots
label_desc: Use image node_id 11 for calling a global function with example usage: tile_fitted(model, generator_runs_dict, rel, show_arm_details_on_hover, show_CI, arm_noun, metrics, fixed_features, data_selector, scalarized_metric_config, label_dict) and returns: AxPlotConfig