Skip to content

plot_cv_results_scatter

yohou.plotting.model_selection.plot_cv_results_scatter(cv_results, param_name, scorer_name=None, *, higher_is_better=True, highlight_best=True, color_palette=None, show_legend=True, title=None, x_label=None, y_label=None, width=None, height=None, marker_size=10.0, marker_opacity=0.8, best_marker_size=16.0, best_marker_color='#dc2626', show_std=True)

Plot hyperparameter search results as a scatter plot.

Creates a scatter plot showing the relationship between a hyperparameter and the cross-validation score, with optional highlighting of the best result.

Parameters

Name Type Description Default
cv_results dict

The cv_results_ dictionary from GridSearchCV or RandomizedSearchCV. Must contain keys like param_{param_name} and mean_test_{scorer_name}.

required
param_name str

Name of the hyperparameter to plot on x-axis (without param_ prefix).

required
scorer_name str | None

Name of the scorer (without mean_test_ prefix). If None, auto-detects from available keys (uses first scorer found).

None
higher_is_better bool

Whether higher score values are better. When False, scores are negated for display so that metrics like neg_mean_squared_error appear as positive values. The best-point detection still operates on the original (un-negated) scores.

True
highlight_best bool

Whether to highlight the best parameter value.

True
color_palette list[str] | None

Custom color palette. If None, uses yohou palette.

None
show_legend bool

Whether to show the legend.

True
title str | None

Plot title. Defaults to "CV Results: {param_name}".

None
x_label str | None

X-axis label. Defaults to the parameter name.

None
y_label str | None

Y-axis label. Defaults to "Mean Test Score".

None
width int | None

Plot width in pixels.

None
height int | None

Plot height in pixels.

None
marker_size float

Size of the scatter markers.

10.0
marker_opacity float

Opacity of scatter markers.

0.8
best_marker_size float

Size of the best-result star marker.

16.0
best_marker_color str

Color of the best-result star marker.

"#dc2626"
show_std bool

Whether to show error bars (if std_test_{scorer} exists in cv_results).

True

Returns

Type Description
Figure

Plotly figure object.

Raises

Type Description
ValueError

If required keys are not found in cv_results.

Examples

>>> from yohou.plotting import plot_cv_results_scatter
>>> # Example cv_results_ structure from GridSearchCV
>>> cv_results = {
...     "param_alpha": [0.01, 0.1, 1.0, 10.0],
...     "mean_test_score": [-0.5, -0.3, -0.2, -0.4],
...     "std_test_score": [0.05, 0.03, 0.02, 0.06],
...     "rank_test_score": [3, 2, 1, 4],
... }
>>> fig = plot_cv_results_scatter(cv_results, param_name="alpha")
>>> len(fig.data) > 0
True

See Also

plot_splits : Plot cross-validation splits. GridSearchCV : Grid search with cross-validation. RandomizedSearchCV : Randomized search with cross-validation.

Source Code

Show/Hide source
def plot_cv_results_scatter(
    cv_results: dict,
    param_name: str,
    scorer_name: str | None = None,
    *,
    higher_is_better: bool = True,
    highlight_best: bool = True,
    color_palette: list[str] | None = None,
    show_legend: bool = True,
    title: str | None = None,
    x_label: str | None = None,
    y_label: str | None = None,
    width: int | None = None,
    height: int | None = None,
    marker_size: float = 10.0,
    marker_opacity: float = 0.8,
    best_marker_size: float = 16.0,
    best_marker_color: str = "#dc2626",
    show_std: bool = True,
) -> go.Figure:
    """
    Plot hyperparameter search results as a scatter plot.

    Creates a scatter plot showing the relationship between a hyperparameter
    and the cross-validation score, with optional highlighting of the best result.

    Parameters
    ----------
    cv_results : dict
        The cv_results_ dictionary from GridSearchCV or RandomizedSearchCV.
        Must contain keys like `param_{param_name}` and `mean_test_{scorer_name}`.
    param_name : str
        Name of the hyperparameter to plot on x-axis (without `param_` prefix).
    scorer_name : str | None, default=None
        Name of the scorer (without `mean_test_` prefix). If None, auto-detects
        from available keys (uses first scorer found).
    higher_is_better : bool, default=True
        Whether higher score values are better. When False, scores are negated
        for display so that metrics like ``neg_mean_squared_error`` appear as
        positive values. The best-point detection still operates on the
        original (un-negated) scores.
    highlight_best : bool, default=True
        Whether to highlight the best parameter value.
    color_palette : list[str] | None, default=None
        Custom color palette. If None, uses yohou palette.
    show_legend : bool, default=True
        Whether to show the legend.
    title : str | None, default=None
        Plot title. Defaults to "CV Results: {param_name}".
    x_label : str | None, default=None
        X-axis label. Defaults to the parameter name.
    y_label : str | None, default=None
        Y-axis label. Defaults to "Mean Test Score".
    width : int | None, default=None
        Plot width in pixels.
    height : int | None, default=None
        Plot height in pixels.
    marker_size : float, default=10.0
        Size of the scatter markers.
    marker_opacity : float, default=0.8
        Opacity of scatter markers.
    best_marker_size : float, default=16.0
        Size of the best-result star marker.
    best_marker_color : str, default="#dc2626"
        Color of the best-result star marker.
    show_std : bool, default=True
        Whether to show error bars (if std_test_{scorer} exists in cv_results).

    Returns
    -------
    go.Figure
        Plotly figure object.

    Raises
    ------
    ValueError
        If required keys are not found in cv_results.

    Examples
    --------
    >>> from yohou.plotting import plot_cv_results_scatter

    >>> # Example cv_results_ structure from GridSearchCV
    >>> cv_results = {
    ...     "param_alpha": [0.01, 0.1, 1.0, 10.0],
    ...     "mean_test_score": [-0.5, -0.3, -0.2, -0.4],
    ...     "std_test_score": [0.05, 0.03, 0.02, 0.06],
    ...     "rank_test_score": [3, 2, 1, 4],
    ... }

    >>> fig = plot_cv_results_scatter(cv_results, param_name="alpha")
    >>> len(fig.data) > 0
    True

    See Also
    --------
    [`plot_splits`][yohou.plotting.plot_splits] : Plot cross-validation splits.
    `GridSearchCV` : Grid search with cross-validation.
    `RandomizedSearchCV` : Randomized search with cross-validation.
    """
    # Construct key names
    param_key = f"param_{param_name}"
    validate_plotting_params(width=width, height=height)

    # Auto-detect scorer name if not provided
    if scorer_name is None:
        # Look for mean_test_* keys
        mean_test_keys = [k for k in cv_results if k.startswith("mean_test_")]
        scorer_name = mean_test_keys[0].replace("mean_test_", "") if mean_test_keys else "score"

    mean_key = f"mean_test_{scorer_name}"
    std_key = f"std_test_{scorer_name}"
    rank_key = f"rank_test_{scorer_name}"

    # Validate required keys
    if param_key not in cv_results:
        msg = f"Parameter key '{param_key}' not found in cv_results. Available keys: {list(cv_results.keys())}"
        raise ValueError(msg)

    if mean_key not in cv_results:
        msg = f"Mean score key '{mean_key}' not found in cv_results. Available keys: {list(cv_results.keys())}"
        raise ValueError(msg)

    # Get data
    param_values = cv_results[param_key]
    mean_scores_raw = cv_results[mean_key]
    std_scores = cv_results.get(std_key)
    ranks = cv_results.get(rank_key)

    # Negate scores for display when higher_is_better=False
    sign = 1 if higher_is_better else -1
    mean_scores = [s * sign for s in mean_scores_raw]

    # Get styling params
    show_std_effective = show_std and std_scores is not None

    # Get colors
    if color_palette is None:
        color_palette = resolve_color_palette(None, 2)

    # Create figure
    fig = go.Figure()

    # Find best index (use raw scores for ranking)
    best_idx = None
    if highlight_best and ranks is not None:
        best_idx = list(ranks).index(1)
    elif highlight_best:
        # Fall back to finding max raw score (before negation)
        best_idx = list(mean_scores_raw).index(max(mean_scores_raw))

    # Add scatter trace with optional error bars
    error_y = None
    if show_std_effective:
        error_y = {
            "type": "data",
            "array": std_scores,
            "visible": True,
            "color": color_palette[0],
        }

    fig.add_trace(
        go.Scatter(
            x=param_values,
            y=mean_scores,
            mode="markers",
            marker={
                "size": marker_size,
                "color": color_palette[0],
                "opacity": marker_opacity,
            },
            error_y=error_y,
            name="CV Score",
            hovertemplate=f"{param_name}: %{{x}}<br>Score: %{{y:.4f}}<extra></extra>",
        )
    )

    # Highlight best point
    if highlight_best and best_idx is not None:
        fig.add_trace(
            go.Scatter(
                x=[param_values[best_idx]],
                y=[mean_scores[best_idx]],
                mode="markers",
                marker={
                    "size": best_marker_size,
                    "color": best_marker_color,
                    "symbol": "star",
                    "line": {"width": 2, "color": "#ffffff"},
                },
                name="Best",
                hovertemplate=f"Best<br>{param_name}: %{{x}}<br>Score: %{{y:.4f}}<extra></extra>",
            )
        )

    # Set default labels
    title_default = title or f"CV Results: {param_name}"
    x_label_default = x_label or param_name
    y_label_default = y_label or "Mean Test Score"

    fig = apply_default_layout(
        fig,
        title=title_default,
        x_label=x_label_default,
        y_label=y_label_default,
        width=width,
        height=height,
    )
    fig.update_layout(showlegend=show_legend)

    return fig

Tutorials

The following example notebooks use this component:

  • How to Run Hyperparameter Search


    Evaluation-Search

    Tune forecaster hyperparameters with GridSearchCV and RandomizedSearchCV using temporal cross-validation splitters and result scatter visualisation.

    View · Open in marimo

  • Reduction Forecasting Walkthrough


    Getting-Started

    Walk through the full fit/predict/evaluate cycle with PointReductionForecaster, cross-validation, and grid search on a real dataset.

    View · Open in marimo

  • Quickstart


    Quickstart

    Comprehensive end-to-end tour of yohou beyond the Getting Started tutorials, covering data loading, baseline forecasting, preprocessing pipelines, decomposition, cross-validation search, and interval prediction.

    View · Open in marimo

  • How to Visualize Model Selection Results


    Visualization

    Visualise CV fold geometry with expanding and sliding window splitters and hyperparameter search results with plot_splits and plot_cv_results_scatter.

    View · Open in marimo