def METHOD_NAME(
    study: Study | Sequence[Study],
    target: Callable[[FrozenTrial], float] | None = None,
    target_name: str = "Objective Value",
) -> _EDFInfo:
    if isinstance(study, Study):
        studies = [study]
    else:
        studies = list(study)
    _check_plot_args(studies, target, target_name)
    if len(studies) == 0:
        _logger.warning("There are no studies.")
        return _EDFInfo(lines=[], x_values=np.array([]))
    if target is None:
        def _target(t: FrozenTrial) -> float:
            return cast(float, t.value)
        target = _target
    study_names = []
    all_values: list[np.ndarray] = []
    for study in studies:
        trials = _filter_nonfinite(
            study.get_trials(deepcopy=False, states=(TrialState.COMPLETE,)), target=target
        )
        values = np.array([target(trial) for trial in trials])
        all_values.append(values)
        study_names.append(study.study_name)
    if all(len(values) == 0 for values in all_values):
        _logger.warning("There are no complete trials.")
        return _EDFInfo(lines=[], x_values=np.array([]))
    min_x_value = np.min(np.concatenate(all_values))
    max_x_value = np.max(np.concatenate(all_values))
    x_values = np.linspace(min_x_value, max_x_value, NUM_SAMPLES_X_AXIS)
    edf_line_info_list = []
    for study_name, values in zip(study_names, all_values):
        y_values = np.sum(values[:, np.newaxis] <= x_values, axis=0) / values.size
        edf_line_info_list.append(_EDFLineInfo(study_name=study_name, y_values=y_values))
    return _EDFInfo(lines=edf_line_info_list, x_values=x_values)