code: def get_df_from_scalarized_curve_series(
      experiment: Experiment,
      all_curve_series: Dict[Union[int, str], Dict[str, pd.Series]],
      metrics: Iterable[Metric],
      trial_idx_to_id: Dict[int, Union[int, str]],
      map_key: str,
  ) -> Optional[pd.DataFrame]:
      """Convert a `all_curve_series` dict (from `get_curves_from_ids`) into
      a dataframe. For each metric, we first get all curves represented in
      `coefficients` and then perform scalarization.
  
      Args:
          experiment: The experiment.
          all_curve_series: A dict containing curve data, as output from
              `get_curves_from_ids`.
          metrics: The metrics from which data is being fetched.
          trial_idx_to_id: A dict mapping trial index to ids.
          map_key: The progression key of the metric's MapKeyInfo.
  
      Returns:
          A dataframe containing curve data or None if no curve data could be found.
      """
      dfs = []
      complete_metrics_by_trial = {
          trial_idx: [] for trial_idx in trial_idx_to_id.keys()
      }
      for trial_idx, id_ in trial_idx_to_id.items():
          if id_ not in all_curve_series:
              logger.info(
                  f"Could not get curve data for id {id_}. Ignoring."
              )
              continue
          curve_series = all_curve_series[id_]
          for m in metrics:
              curve_dfs = []
              for (
                  curve_name
              ) in m.coefficients.keys():  # pyre-ignore[16]
                  if curve_name in curve_series:
                      curve_df = _get_single_curve(
                          curve_series=curve_series,
                          curve_name=curve_name,
                          map_key=map_key,
                          trial=experiment.trials[trial_idx],
                          cumulative_best=m.cumulative_best,  # pyre-ignore[16]
                          lower_is_better=m.lower_is_better,  # pyre-ignore[6]
                          smoothing_window=m.smoothing_window,  # pyre-ignore[16]
                      )
                      curve_dfs.append(curve_df)
                  else:
                      logger.info(
                          f"{curve_name} not present in curves from {id_}, so the "
                          f"scalarization for {m.name} cannot be computed. Returning "
                          "without this metric."
                      )
                      break
              if len(curve_dfs) == len(m.coefficients):
                  # only keep if all curves needed by the metric are available
                  dfs.extend(curve_dfs)
                  # mark metrics who have all underlying curves
                  complete_metrics_by_trial[trial_idx].append(m)
  
      if len(dfs) == 0:
          return None
  
      all_data_df = pd.concat(dfs, axis=0, ignore_index=True)
      sub_dfs = []
      # Do not create a common index across trials, only across the curves
      # involved in the scalarized metric.
      for trial_idx, dfi in all_data_df.groupby("trial_index"):
          # the `do_forward_fill = True` pads with the latest
          # observation to handle situations where learning curves
          # report different amounts of data.
          trial_curves = dfi["metric_name"].unique().tolist()
          dfs_mean, dfs_sem = align_partial_results(
              dfi,
              progr_key=map_key,
              metrics=trial_curves,
              do_forward_fill=True,
          )
          for metric in complete_metrics_by_trial[trial_idx]:
              sub_df = _get_scalarized_curve_metric_sub_df(
                  dfs_mean=dfs_mean,
                  dfs_sem=dfs_sem,
                  metric=metric,
                  trial=checked_cast(
                      Trial, experiment.trials[trial_idx]
                  ),
              )
              sub_dfs.append(sub_df)
      return pd.concat(sub_dfs, axis=0, ignore_index=True)
  
imports: from __future__ import annotations
  from abc import ABC, abstractmethod
  from logging import Logger
  from typing import Any, Dict, Iterable, Optional, Set, Union
  import numpy
  import pandas
  from ax.core.base_trial import BaseTrial
  from ax.core.batch_trial import BatchTrial
  from ax.core.experiment import Experiment
  from ax.core.map_data import MapData, MapKeyInfo
  from ax.core.map_metric import MapMetric
  from ax.core.metric import Metric, MetricFetchE, MetricFetchResult
  from ax.core.trial import Trial
  from ax.early_stopping.utils import align_partial_results
  from ax.exceptions.core import UnsupportedError
  from ax.utils.common.logger import get_logger
  from ax.utils.common.result import Err, Ok
  from ax.utils.common.typeutils import checked_cast
label_desc: Use image node_id 2 for calling a global function with example usage: get_df_from_scalarized_curve_series(experiment, all_curve_series, metrics, trial_idx_to_id, map_key) and returns: pd, None