code: def _get_pareto_front_info(
      study: Study,
      target_names: list[str] | None = None,
      include_dominated_trials: bool = True,
      axis_order: list[int] | None = None,
      constraints_func: Callable[[FrozenTrial], Sequence[float]]
      | None = None,
      targets: Callable[[FrozenTrial], Sequence[float]] | None = None,
  ) -> _ParetoFrontInfo:
      if axis_order is not None:
          warnings.warn(
              "`axis_order` has been deprecated in v3.0.0. "
              "This feature will be removed in v5.0.0. "
              "See https://github.com/optuna/optuna/releases/tag/v3.0.0.",
              FutureWarning,
          )
  
      if targets is not None and axis_order is not None:
          raise ValueError(
              "Using both `targets` and `axis_order` is not supported. "
              "Use either `targets` or `axis_order`."
          )
  
      if constraints_func is not None:
          warnings.warn(
              "``constraints_func`` argument is an experimental feature."
              " The interface can change in the future.",
              ExperimentalWarning,
          )
          feasible_trials = []
          infeasible_trials = []
          for trial in study.get_trials(
              deepcopy=False, states=(TrialState.COMPLETE,)
          ):
              if all(map(lambda x: x <= 0.0, constraints_func(trial))):
                  feasible_trials.append(trial)
              else:
                  infeasible_trials.append(trial)
          best_trials = _get_pareto_front_trials_by_trials(
              feasible_trials, study.directions
          )
          if include_dominated_trials:
              non_best_trials = _get_non_pareto_front_trials(
                  feasible_trials, best_trials
              )
          else:
              non_best_trials = []
  
          if len(best_trials) == 0:
              _logger.warning(
                  "Your study does not have any completed and feasible trials."
              )
      else:
          all_trials = study.get_trials(
              deepcopy=False, states=(TrialState.COMPLETE,)
          )
          best_trials = _get_pareto_front_trials_by_trials(
              all_trials, study.directions
          )
          if len(best_trials) == 0:
              _logger.warning(
                  "Your study does not have any completed trials."
              )
  
          if include_dominated_trials:
              non_best_trials = _get_non_pareto_front_trials(
                  all_trials, best_trials
              )
          else:
              non_best_trials = []
          infeasible_trials = []
  
      _targets = targets
      if _targets is None:
          if len(study.directions) in (2, 3):
              _targets = _targets_default
          else:
              raise ValueError(
                  "`plot_pareto_front` function only supports 2 or 3 objective"
                  " studies when using `targets` is `None`. Please use `targets`"
                  " if your objective studies have more than 3 objectives."
              )
  
      def _make_trials_with_values(
          trials: list[FrozenTrial],
          targets: Callable[[FrozenTrial], Sequence[float]],
      ) -> list[tuple[FrozenTrial, list[float]]]:
          target_values = [targets(trial) for trial in trials]
          for v in target_values:
              if not isinstance(v, Sequence):
                  raise ValueError(
                      "`targets` should return a sequence of target values."
                      " your `targets` returns {}".format(type(v))
                  )
          return [
              (trial, list(v))
              for trial, v in zip(trials, target_values)
          ]
  
      best_trials_with_values = _make_trials_with_values(
          best_trials, _targets
      )
      non_best_trials_with_values = _make_trials_with_values(
          non_best_trials, _targets
      )
      infeasible_trials_with_values = _make_trials_with_values(
          infeasible_trials, _targets
      )
  
      def _infer_n_targets(
          trials_with_values: Sequence[
              tuple[FrozenTrial, Sequence[float]]
          ]
      ) -> int | None:
          if len(trials_with_values) > 0:
              return len(trials_with_values[0][1])
          return None
  
      # Check for `non_best_trials_with_values` can be skipped, because if `best_trials_with_values`
      # is empty, then `non_best_trials_with_values` will also be empty.
      n_targets = _infer_n_targets(
          best_trials_with_values
      ) or _infer_n_targets(infeasible_trials_with_values)
      if n_targets is None:
          if target_names is not None:
              n_targets = len(target_names)
          elif targets is None:
              n_targets = len(study.directions)
          else:
              raise ValueError(
                  "If `targets` is specified for empty studies, `target_names` must be specified."
              )
  
      if n_targets not in (2, 3):
          raise ValueError(
              "`plot_pareto_front` function only supports 2 or 3 targets."
              " you used {} targets now.".format(n_targets)
          )
  
      if target_names is None:
          metric_names = study.metric_names
          if metric_names is None:
              target_names = [
                  f"Objective {i}" for i in range(n_targets)
              ]
          else:
              target_names = metric_names
      elif len(target_names) != n_targets:
          raise ValueError(
              f"The length of `target_names` is supposed to be {n_targets}."
          )
  
      if axis_order is None:
          axis_order = list(range(n_targets))
      else:
          if len(axis_order) != n_targets:
              raise ValueError(
                  f"Size of `axis_order` {axis_order}. Expect: {n_targets}, "
                  f"Actual: {len(axis_order)}."
              )
          if len(set(axis_order)) != n_targets:
              raise ValueError(
                  f"Elements of given `axis_order` {axis_order} are not unique!."
              )
          if max(axis_order) > n_targets - 1:
              raise ValueError(
                  f"Given `axis_order` {axis_order} contains invalid index {max(axis_order)} "
                  f"higher than {n_targets - 1}."
              )
          if min(axis_order) < 0:
              raise ValueError(
                  f"Given `axis_order` {axis_order} contains invalid index {min(axis_order)} "
                  "lower than 0."
              )
  
      return _ParetoFrontInfo(
          n_targets=n_targets,
          target_names=target_names,
          best_trials_with_values=best_trials_with_values,
          non_best_trials_with_values=non_best_trials_with_values,
          infeasible_trials_with_values=infeasible_trials_with_values,
          axis_order=axis_order,
          include_dominated_trials=include_dominated_trials,
          has_constraints_func=constraints_func is not None,
      )
  
imports: from __future__ import annotations
  from collections.abc import Callable
  from collections.abc import Sequence
  from typing import Any
  from typing import NamedTuple
  import warnings
  import optuna
  from optuna.exceptions import ExperimentalWarning
  from optuna.study import Study
  from optuna.study._multi_objective import _get_pareto_front_trials_by_trials
  from optuna.trial import FrozenTrial
  from optuna.trial import TrialState
  from optuna.visualization._plotly_imports import _imports
  from optuna.visualization._utils import _make_hovertext
label_desc: Use image node_id 3 for calling a global function with example usage: _get_pareto_front_info(study, target_names, include_dominated_trials, axis_order, constraints_func, targets) and returns: _ParetoFrontInfo, unknown, None, len