code: def get_observed_pareto_frontiers(
      experiment: Experiment,
      data: Optional[Data] = None,
      rel: Optional[bool] = None,
      arm_names: Optional[List[str]] = None,
  ) -> List[ParetoFrontierResults]:
      """
      Find all Pareto points from an experiment.
  
      Uses only values as observed in the data; no modeling is involved. Makes no
      assumption about the search space or types of parameters. If "data" is provided will
      use that, otherwise will use all data already attached to the experiment.
  
      Uses all arms present in data; does not filter according to experiment
      search space. If arm_names is specified, will filter to just those arm whose names
      are given in the list.
  
      Assumes experiment has a multiobjective optimization config from which the
      objectives and outcome constraints will be extracted.
  
      Will generate a ParetoFrontierResults for every pair of metrics in the experiment's
      multiobjective optimization config.
  
      Args:
          experiment: The experiment.
          data: Data to use for computing Pareto frontier. If not provided, will lookup
              data from experiment.
          rel: Relativize results wrt experiment status quo. If None, then rel will be
              taken for each objective separately from its own objective threshold.
              `rel` must be specified if there are missing objective thresholds.
          arm_names: If provided, computes Pareto frontier only from among the provided
              list of arm names, plus status quo if set on experiment.
  
      Returns: ParetoFrontierResults that can be used with interact_pareto_frontier.
      """
      if data is None:
          data = experiment.lookup_data()
      if experiment.optimization_config is None:
          raise ValueError(
              "Experiment must have an optimization config"
          )
      if arm_names is not None:
          if (
              experiment.status_quo is not None
              and experiment.status_quo.name not in arm_names
          ):
              # Make sure status quo is always included, for derelativization
              arm_names.append(experiment.status_quo.name)
          data = Data(data.df[data.df["arm_name"].isin(arm_names)])
      mb = get_tensor_converter_model(experiment=experiment, data=data)
      pareto_observations = observed_pareto_frontier(modelbridge=mb)
      # Convert to ParetoFrontierResults
      objective_metric_names = {
          metric.name
          for metric in experiment.optimization_config.objective.metrics  # pyre-ignore
      }
      obj_metr_list = sorted(objective_metric_names)
      pfr_means = {name: [] for name in obj_metr_list}
      pfr_sems = {name: [] for name in obj_metr_list}
  
      for obs in pareto_observations:
          for i, name in enumerate(obs.data.metric_names):
              if name in objective_metric_names:
                  pfr_means[name].append(obs.data.means[i])
                  pfr_sems[name].append(
                      np.sqrt(obs.data.covariance[i, i])
                  )
  
      # Get objective thresholds
      rel_objth = {}
      objective_thresholds = {}
      if (
          experiment.optimization_config.objective_thresholds
          is not None
      ):  # pyre-ignore
          for (
              objth
          ) in experiment.optimization_config.objective_thresholds:
              rel_objth[objth.metric.name] = objth.relative
              objective_thresholds[objth.metric.name] = objth.bound
  
      # Identify which metrics should be relativized
      if rel in [True, False]:
          metric_is_rel = {name: rel for name in pfr_means}
      else:
          if len(rel_objth) != len(pfr_means):
              raise UserInputError(
                  "At least one objective is missing an objective threshold. "
                  "`rel` must be specified as True or False when there are missing "
                  "objective thresholds."
              )
          # Default to however the threshold is specified
          metric_is_rel = rel_objth
  
      # Compute SQ values
      sq_means, sq_sems = _extract_sq_data(experiment, data)
  
      # Relativize data and thresholds as needed
      for name in pfr_means:
          if metric_is_rel[name]:
              pfr_means[name], pfr_sems[name] = _relativize_values(
                  means=pfr_means[name],
                  sq_mean=sq_means[name],
                  sems=pfr_sems[name],
                  sq_sem=sq_sems[name],
              )
              if name in objective_thresholds and not rel_objth[name]:
                  # Metric is rel but obj th is not.
                  # Need to relativize the objective threshold
                  objective_thresholds[name] = _relativize_values(
                      means=[objective_thresholds[name]],
                      sq_mean=sq_means[name],
                      sems=[np.nan],
                      sq_sem=np.nan,
                  )[0][0]
          elif name in objective_thresholds and rel_objth[name]:
              # Metric is not rel but obj th is, so need to derelativize obj th
              objective_thresholds[name] = (
                  1 + objective_thresholds[name] / 100.0
              ) * sq_means[name]
  
      absolute_metrics = [
          name for name, val in metric_is_rel.items() if not val
      ]
      # Construct ParetoFrontResults for each pair
      pfr_list = []
      param_dicts = [
          obs.features.parameters for obs in pareto_observations
      ]
      pfr_arm_names = [obs.arm_name for obs in pareto_observations]
  
      for metric_a, metric_b in combinations(obj_metr_list, 2):
          pfr_list.append(
              ParetoFrontierResults(
                  param_dicts=param_dicts,
                  means=pfr_means,
                  sems=pfr_sems,
                  primary_metric=metric_a,
                  secondary_metric=metric_b,
                  absolute_metrics=absolute_metrics,
                  objective_thresholds=objective_thresholds,
                  arm_names=pfr_arm_names,
              )
          )
      return pfr_list
  
imports: import copy
  from copy import deepcopy
  from itertools import combinations
  from logging import Logger
  from typing import cast, Dict, List, NamedTuple, Optional, Tuple, Union
  import numpy
  import torch
  from ax.core.batch_trial import BatchTrial
  from ax.core.data import Data
  from ax.core.experiment import Experiment
  from ax.core.metric import Metric
  from ax.core.objective import ScalarizedObjective
  from ax.core.observation import ObservationFeatures
  from ax.core.optimization_config import MultiObjectiveOptimizationConfig, OptimizationConfig
  from ax.core.outcome_constraint import ComparisonOp, ObjectiveThreshold, OutcomeConstraint
  from ax.core.search_space import RobustSearchSpace, SearchSpace
  from ax.core.types import TParameterization
  from ax.exceptions.core import AxError, UnsupportedError, UserInputError
  from ax.modelbridge.modelbridge_utils import _get_modelbridge_training_data, get_pareto_frontier_and_configs, observed_pareto_frontier
  from ax.modelbridge.registry import Models
  from ax.modelbridge.torch import TorchModelBridge
  from ax.modelbridge.transforms.search_space_to_float import SearchSpaceToFloat
  from ax.models.torch.posterior_mean import get_PosteriorMean
  from ax.models.torch_base import TorchModel
  from ax.utils.common.logger import get_logger
  from ax.utils.stats.statstools import relativize
  from botorch.utils.multi_objective import is_non_dominated
  from botorch.utils.multi_objective.hypervolume import infer_reference_point
label_desc: Use image node_id 4 for calling a global function with example usage: get_observed_pareto_frontiers(experiment, data, rel, arm_names) and returns: pfr_list