Source code for optuna.visualization.matplotlib._param_importances

from __future__ import annotations

from typing import TYPE_CHECKING

import numpy as np

from optuna._experimental import experimental_func
from optuna.logging import get_logger
from optuna.visualization._param_importances import _get_importances_infos
from optuna.visualization._param_importances import _ImportancesInfo
from optuna.visualization.matplotlib._matplotlib_imports import _imports


if TYPE_CHECKING:
    from collections.abc import Callable

    from optuna.importance._base import BaseImportanceEvaluator
    from optuna.study import Study
    from optuna.trial import FrozenTrial


if _imports.is_successful():
    from optuna.visualization.matplotlib._matplotlib_imports import Axes
    from optuna.visualization.matplotlib._matplotlib_imports import Figure
    from optuna.visualization.matplotlib._matplotlib_imports import plt


_logger = get_logger(__name__)


AXES_PADDING_RATIO = 1.05


[docs] @experimental_func("2.2.0") def plot_param_importances( study: Study, evaluator: BaseImportanceEvaluator | None = None, params: list[str] | None = None, *, target: Callable[[FrozenTrial], float] | None = None, target_name: str = "Objective Value", ) -> "Axes": """Plot hyperparameter importances (:class:`~optuna.importance.PedAnovaImportanceEvaluator` by default) with Matplotlib. .. seealso:: Please refer to :func:`optuna.visualization.plot_param_importances` for an example. Args: study: An optimized study. evaluator: An importance evaluator object that specifies which algorithm to base the importance assessment on. Defaults to :class:`~optuna.importance.PedAnovaImportanceEvaluator`. For details on this evaluator, please refer to the following papers: - `PED-ANOVA: Efficiently Quantifying Hyperparameter Importance in Arbitrary Subspaces <https://arxiv.org/abs/2304.10255>`__ (IJCAI 2023) - `Conditional PED-ANOVA: Hyperparameter Importance in Hierarchical & Dynamic Search Spaces <https://arxiv.org/abs/2601.20800>`__ (KDD 2026) When using this evaluator in your project, please consider citing both papers. params: A list of names of parameters to assess. If :obj:`None`, :class:`~optuna.importance.PedAnovaImportanceEvaluator` assesses all parameters that appear in completed trials, including conditional parameters, while other evaluators assess parameters present in all completed trials. If specified, only the specified parameters are assessed. When using :class:`~optuna.importance.PedAnovaImportanceEvaluator`, each specified parameter must appear in at least one completed trial. When using other evaluators, at least one completed trial must contain all specified parameters. target: A function that returns the value used to evaluate and display importances. If :obj:`None`, objective values are used for single-objective optimization. For multi-objective optimization, all objectives will be plotted if ``target`` is :obj:`None`. Specify ``target``, for example ``target=lambda t: t.values[0]``, to plot importances for a specific objective. target_name: Target's name to display on the axis label. Names set via :meth:`~optuna.study.Study.set_metric_names` will be used if ``target`` is :obj:`None`, overriding this argument. Returns: A :class:`matplotlib.axes.Axes` object. """ _imports.check() importances_infos = _get_importances_infos(study, evaluator, params, target, target_name) return _get_importances_plot(importances_infos)
def _get_importances_plot(infos: tuple[_ImportancesInfo, ...]) -> "Axes": # Set up the graph style. plt.style.use("ggplot") # Use ggplot style sheet for similar outputs to plotly. fig, ax = plt.subplots() ax.set_title("Hyperparameter Importances", loc="left") ax.set_xlabel("Hyperparameter Importance") ax.set_ylabel("Hyperparameter") height = 0.8 / len(infos) # Default height split between objectives. for objective_id, info in enumerate(infos): param_names = info.param_names pos = np.arange(len(param_names)) offset = height * objective_id importance_values = info.importance_values if not importance_values: continue # Draw horizontal bars. ax.barh( pos + offset, importance_values, height=height, align="center", label=info.target_name, color=plt.get_cmap("tab20c")(objective_id), ) _set_bar_labels(info, fig, ax, offset) ax.set_yticks(pos + offset / 2, param_names) ax.legend(loc="best") return ax def _set_bar_labels(info: _ImportancesInfo, fig: "Figure", ax: "Axes", offset: float) -> None: # Figure canvas does not necessarily have a get_renderer. assert hasattr(fig.canvas, "get_renderer") renderer = fig.canvas.get_renderer() for idx, (val, label) in enumerate(zip(info.importance_values, info.importance_labels)): text = ax.text(val, idx + offset, label, va="center") # Sometimes horizontal axis needs to be re-scaled # to avoid text going over plot area. bbox = text.get_window_extent(renderer) bbox = bbox.transformed(ax.transData.inverted()) _, plot_xmax = ax.get_xlim() bbox_xmax = bbox.xmax if bbox_xmax > plot_xmax: ax.set_xlim(xmax=AXES_PADDING_RATIO * bbox_xmax)