Skip to content

Fix pyplot.set_cmap rcParams mismatch when registered name differs from colormap.name (swev-id: matplotlib__matplotlib-25479) #58

@rowan-stein

Description

@rowan-stein

Task ID: 279

User request / bug report:
Confusing (broken?) colormap name handling

Example:

from matplotlib import cm
from matplotlib.colors import LinearSegmentedColormap
import matplotlib.pyplot as plt
import matplotlib
matplotlib.__version__
'1.4.3.'

my_cmap_data = [[1.5e-03, 4.7e-04, 1.4e-02],
                [2.3e-03, 1.3e-03, 1.8e-02],
                [3.3e-03, 2.3e-03, 2.4e-02]]
my_cmap = LinearSegmentedColormap.from_list('some_cmap_name', my_cmap_data)
cm.register_cmap(name='my_cmap_name', cmap=my_cmap)

plt.set_cmap('my_cmap_name')
plt.imshow([[1, 1], [2, 2]])

Observed error (excerpt):

ValueError: Colormap some_cmap_name is not recognized. Possible values include ..., my_cmap_name, ...

This happens because plt.set_cmap('my_cmap_name') ends up writing rcParams['image.cmap'] = 'some_cmap_name' (the colormap object's internal name) instead of the registered key my_cmap_name. Later, ScalarMappable resolves the default colormap via rcParams as a registry key, which fails when the internal name wasn't registered.

Research and specification (by Emerson Gray):

  • Location: lib/matplotlib/pyplot.py: set_cmap(cmap)
    • Current: resolves cmap = get_cmap(cmap) and sets rc('image', cmap=cmap.name) regardless of input type.
  • Registry behavior: colormap registry indexes by registered name; colormap objects retain their original .name. Thus, registered key and cmap.name can differ.

Specification (minimal, safe fix):

  • In pyplot.set_cmap:
    • Resolve the input via get_cmap for validation.
    • If input is a str (registered name), set rc('image', cmap=<input string>) so rcParams stores the registry key.
    • If input is a Colormap object, keep current behavior and set rc('image', cmap=resolved.name).
    • Apply the colormap to the current image as today (pass either the string or the resolved object; both are accepted by ScalarMappable.set_cmap).
  • No changes to registry internals or public signatures.

Tests to add (lib/matplotlib/tests/test_pyplot.py):

  1. test_set_cmap_uses_registered_key_for_rcparams
    • Create LinearSegmentedColormap with name 'some_cmap_name'.
    • Register as 'my_cmap_name' via matplotlib.colormaps.register(..., name='my_cmap_name', force=True).
    • plt.set_cmap('my_cmap_name').
    • Assert mpl.rcParams['image.cmap'] == 'my_cmap_name'.
    • plt.imshow(...) should not raise.
  2. test_set_cmap_colormap_object_rcparams_name_passthrough
    • Create a colormap object with name 'unregistered_internal_name' (and optionally also register under a different key).
    • plt.set_cmap(colormap_obj).
    • Assert mpl.rcParams['image.cmap'] == 'unregistered_internal_name' (preserves current behavior for object inputs).

Reproduction steps and current failure (on current branch):

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap

lsc = LinearSegmentedColormap.from_list('some_cmap_name', ['black', 'white'])
mpl.colormaps.register(lsc, name='my_cmap_name', force=True)
plt.set_cmap('my_cmap_name')
plt.imshow(np.arange(4).reshape(2,2))

Trace excerpt pre-fix:

ValueError: 'some_cmap_name' is not a valid value for cmap; supported values are ... 'my_cmap_name', ...
  at cm._ensure_cmap -> check_in_list(sorted(_colormaps), cmap=cmap)

Expected behavior after fix:

  • No exception; rcParams['image.cmap'] == 'my_cmap_name'; imshow renders using the registered colormap (whose object.name may remain 'some_cmap_name').

Scope and constraints:

  • Base branch: matplotlib__matplotlib-25479 (do not modify base directly; create a feature branch and PR against it).
  • CI: Do not manually trigger CI in this task.
  • PR title must include token: 'swev-id: matplotlib__matplotlib-25479'.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions