Thanks to visit codestin.com
Credit goes to github.com

Skip to content

FIX: Regression in DecisionBoundaryDisplay.from_estimator with colors and plot_method='contour' #31553

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

jshn9515
Copy link

Reference Issues/PRs

Fixes: #31546

Summary

This PR addresses bugs introduced in PR #29797. It restores the previous behavior when plot_method='contour' is specified and improves the handling of colors, cmap, and multiclass_colors arguments in DecisionBoundaryDisplay.from_estimator.

Problem

Currently, passing the colors keyword argument to DecisionBoundaryDisplay.from_estimator raises a ValueError, as both cmap and colors are set simultaneously. Additionally, when plot_method='contour' is used, the decision boundary is no longer displayed; instead, a surface plot of the class predictions is drawn, which deviates from the intended behavior.

Solution

This PR introduces the following enhancements to clarify and handle these scenarios:

  • When multiclass_colors is None:
    • Both colors and cmap are specified -> raise a ValueError
    • Only cmap is specified -> determine whether the colormap is continuous or discrete and convert it to RGBA accordingly
    • Only colors is specified -> convert to RGBA
    • Nither cmap nor colors is specified -> use the default colormap
  • When multiclass_colors is not None:
    • If either cmap or colors is specified -> issue a warning and only use multiclass_colors
    • If multiclass_colors is a string -> treat it as a colormap name and convert it to RGBA depending on whether it's continuous or discrete
    • If multiclass_colors is a list -> convert it directly to RGBA
  • Plot method behavior:

Copy link

github-actions bot commented Jun 16, 2025

✔️ Linting Passed

All linting checks passed. Your pull request is in excellent shape! ☀️

Generated for commit: 7ca868f. Link to the linter CI: here

Copy link
Member

@adrinjalali adrinjalali left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. A few observations:

  • The places which are not tested (complaining codecov) need to be tested.
  • The diff is hard to review, and it seems certain logic is removed from the new code, which should be there? Please comment on how things have changed and if any, why logic is removed.

Comment on lines +227 to +228
"Cannot specify both 'cmap' and 'colors' in kwargs. "
"Please use only one of them."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't one deprecated upstream? We should recommend the new way.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion!
To clarify: matplotlib hasn't deprecated either cmap or colors — both are still valid and serve different purposes.
That said, I agree it's better to recommend cmap as the preferred option, especially for continuous or gradient-based plots. I’ll update the error message accordingly to reflect that.

@jshn9515
Copy link
Author

Thanks for the feedback! I understand that the diff is quite large and thus harder to review. After attempting to resolve the conflicts between colors, cmap, and multiclass_colors, the logic became complicated. As a result, I had to rewrite the original structure, which unfortunately made the diff harder to follow.

And to clarify: matplotlib hasn't deprecated either cmap or colors — both are still valid and serve different purposes. That said, I agree it's better to recommend cmap as the preferred option, especially for continuous or gradient-based plots.

Below is a breakdown of the changes for clarity:

Original Logic

if (
    isinstance(self.multiclass_colors, str)
    or self.multiclass_colors is None
):
    ...
    if cmap == "tab10" and n_responses <= 10:
        colors = ...
    elif cmap == "tab20" and n_responses <= 20:
        colors = ...
    else:
        colors = ...
elif isinstance(self.multiclass_colors, str):
    colors = ...
else:  # self.multiclass_colors is a list
    colors = ...
  • The elif isinstance(self.multiclass_colors, str) is redundant, since that condition is already covered by the first if. I removed it to simplify the structure.
  • There was no check for the case when users pass in a continuous colormap (LinearSegmentedColormap), which lacks the .colors attribute. Attempting to access colors from such a colormap would raise an error. This code was originally assuming ListedColormap.
  • The original implementation didn’t properly handle conflicts when users specify both cmap/colors and multiclass_colors. Since colors and cmap are passed directly to Matplotlib, while multiclass_colors is handled by scikit-learn, some combinations could lead to ambiguity or silent failures.

Updated Logic (New Version):

if self.multiclass_colors is None:
    if "cmap" in kwargs and "colors" in kwargs:
        raise ValueError(...)
    if "cmap" in kwargs:
        ...
    elif "colors" in kwargs:
        ...
    else:
        ...
else:
    if "cmap" in kwargs:
        warnings.warn(...)  # 'cmap' will be ignored
    if "colors" in kwargs:
        warnings.warn(...)  # 'colors' will be ignored
    if isinstance(self.multiclass_colors, str):
        ...
    elif isinstance(self.multiclass_colors, list):
        ...
    else:
        raise ValueError(...)

This new structure separates the logic into two clear branches:

  • When multiclass_colors is not set, it handles cmap and colors mutually exclusively and safely.
  • When multiclass_colors is set, it explicitly ignores any cmap or colors in kwargs and processes multiclass_colors accordingly.

This design avoids ambiguity, enforces correct usage, and adds necessary warnings and error handling.

Contour-specific Fix

The actual fix related to the contour plotting method is limited to lines 267 to 271, specifically in the following section:

if plot_method == "contour":
    # Plot only argmax map for contour
    class_map = self.response.argmax(axis=2)
    self.surface_ = plot_func(
        self.xx0, self.xx1, class_map, colors=colors, **kwargs
    )

Regarding tests – I will add appropriate test cases to ensure the new logic is properly covered and behaves as expected in all scenarios.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Regression in DecisionBoundaryDisplay.from_estimator with colors and plot_method='contour' after upgrading to v1.7.0
2 participants