forked from matplotlib/matplotlib
-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
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 setsrc('image', cmap=cmap.name)regardless of input type.
- Current: resolves
- Registry behavior: colormap registry indexes by registered name; colormap objects retain their original
.name. Thus, registered key andcmap.namecan 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):
- 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.
- 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'.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels