class_docstr: Interface for heuristics that halt trials early, typically based on early
  results from that trial.
docstr: Validity checks and returns the `MapData` used for early stopping that
  is associated with `metric_names`. This function also handles normalizing
  progressions.
docstr_tok: ["Validity","checks","and","returns","the","`","MapData","`","used","for","early","stopping","that","is","associated","with","`","metric_names","`",".","This","function","also","handles","normalizing","progressions","."]
code: def _check_validity_and_get_data(
      self, experiment: Experiment, metric_names: List[str]
  ) -> Optional[MapData]:
      """Validity checks and returns the `MapData` used for early stopping that
      is associated with `metric_names`. This function also handles normalizing
      progressions.
      """
      data = experiment.lookup_data()
      if data.df.empty:
          logger.info(
              f"{self.__class__.__name__} received empty data. "
              "Not stopping any trials."
          )
          return None
      for metric_name in metric_names:
          if metric_name not in set(data.df["metric_name"]):
              logger.info(
                  f"{self.__class__.__name__} did not receive data "
                  "from the objective metric. Not stopping any trials."
              )
              return None
  
      if not isinstance(data, MapData):
          logger.info(
              f"{self.__class__.__name__} expects MapData, but the "
              f"data attached to experiment is of type {type(data)}. "
              "Not stopping any trials."
          )
          return None
  
      data = checked_cast(MapData, data)
      map_keys = data.map_keys
      if len(list(map_keys)) > 1:
          logger.info(
              f"{self.__class__.__name__} expects MapData with a single "
              "map key, but the data attached to the experiment has multiple: "
              f"{data.map_keys}. Not stopping any trials."
          )
          return None
      map_df = data.map_df
      # keep only relevant metrics
      map_df = map_df[map_df["metric_name"].isin(metric_names)].copy()
      if self.normalize_progressions:
          for map_key in map_keys:
              values = map_df[map_key].astype(float)
              map_df[map_key] = values / values.abs().max()
      return MapData(
          df=map_df,
          map_key_infos=data.map_key_infos,
          description=data.description,
      )
  
imports: import logging
  from abc import ABC, abstractmethod
  from dataclasses import dataclass
  from logging import Logger
  from typing import Any, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Type
  import numpy
  import pandas
  from ax.core.base_trial import TrialStatus
  from ax.core.data import Data
  from ax.core.experiment import Experiment
  from ax.core.map_data import MapData
  from ax.core.objective import MultiObjective
  from ax.modelbridge.map_torch import MapTorchModelBridge
  from ax.modelbridge.modelbridge_utils import _unpack_observations, observation_data_to_array, observation_features_to_array
  from ax.modelbridge.registry import Cont_X_trans, Y_trans
  from ax.modelbridge.transforms.base import Transform
  from ax.modelbridge.transforms.map_unit_x import MapUnitX
  from ax.models.torch_base import TorchModel
  from ax.utils.common.base import Base
  from ax.utils.common.logger import get_logger
  from ax.utils.common.typeutils import checked_cast, not_none
label_desc: Use image node_id 3 for calling the BaseEarlyStoppingStrategy obj's underlying member method code with example usage: obj._check_validity_and_get_data(experiment, metric_names) and returns: MapData, None, None, None, None