| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- """
- Builtin colormaps, colormap handling utilities, and the `ScalarMappable` mixin.
- .. seealso::
- :doc:`/gallery/color/colormap_reference` for a list of builtin colormaps.
- :ref:`colormap-manipulation` for examples of how to make
- colormaps.
- :ref:`colormaps` an in-depth discussion of choosing
- colormaps.
- :ref:`colormapnorms` for more details about data normalization.
- """
- from collections.abc import Mapping
- import matplotlib as mpl
- from matplotlib import _api, colors
- # TODO make this warn on access
- from matplotlib.colorizer import _ScalarMappable as ScalarMappable # noqa
- from matplotlib._cm import datad
- from matplotlib._cm_listed import cmaps as cmaps_listed
- from matplotlib._cm_multivar import cmap_families as multivar_cmaps
- from matplotlib._cm_bivar import cmaps as bivar_cmaps
- _LUTSIZE = mpl.rcParams['image.lut']
- def _gen_cmap_registry():
- """
- Generate a dict mapping standard colormap names to standard colormaps, as
- well as the reversed colormaps.
- """
- cmap_d = {**cmaps_listed}
- for name, spec in datad.items():
- cmap_d[name] = ( # Precache the cmaps at a fixed lutsize..
- colors.LinearSegmentedColormap(name, spec, _LUTSIZE)
- if 'red' in spec else
- colors.ListedColormap(spec['listed'], name)
- if 'listed' in spec else
- colors.LinearSegmentedColormap.from_list(name, spec, _LUTSIZE))
- # Register colormap aliases for gray and grey.
- aliases = {
- # alias -> original name
- 'grey': 'gray',
- 'gist_grey': 'gist_gray',
- 'gist_yerg': 'gist_yarg',
- 'Grays': 'Greys',
- }
- for alias, original_name in aliases.items():
- cmap = cmap_d[original_name].copy()
- cmap.name = alias
- cmap_d[alias] = cmap
- # Generate reversed cmaps.
- for cmap in list(cmap_d.values()):
- rmap = cmap.reversed()
- cmap_d[rmap.name] = rmap
- return cmap_d
- class ColormapRegistry(Mapping):
- r"""
- Container for colormaps that are known to Matplotlib by name.
- The universal registry instance is `matplotlib.colormaps`. There should be
- no need for users to instantiate `.ColormapRegistry` themselves.
- Read access uses a dict-like interface mapping names to `.Colormap`\s::
- import matplotlib as mpl
- cmap = mpl.colormaps['viridis']
- Returned `.Colormap`\s are copies, so that their modification does not
- change the global definition of the colormap.
- Additional colormaps can be added via `.ColormapRegistry.register`::
- mpl.colormaps.register(my_colormap)
- To get a list of all registered colormaps, you can do::
- from matplotlib import colormaps
- list(colormaps)
- """
- def __init__(self, cmaps):
- self._cmaps = cmaps
- self._builtin_cmaps = tuple(cmaps)
- def __getitem__(self, item):
- try:
- return self._cmaps[item].copy()
- except KeyError:
- raise KeyError(f"{item!r} is not a known colormap name") from None
- def __iter__(self):
- return iter(self._cmaps)
- def __len__(self):
- return len(self._cmaps)
- def __str__(self):
- return ('ColormapRegistry; available colormaps:\n' +
- ', '.join(f"'{name}'" for name in self))
- def __call__(self):
- """
- Return a list of the registered colormap names.
- This exists only for backward-compatibility in `.pyplot` which had a
- ``plt.colormaps()`` method. The recommended way to get this list is
- now ``list(colormaps)``.
- """
- return list(self)
- def register(self, cmap, *, name=None, force=False):
- """
- Register a new colormap.
- The colormap name can then be used as a string argument to any ``cmap``
- parameter in Matplotlib. It is also available in ``pyplot.get_cmap``.
- The colormap registry stores a copy of the given colormap, so that
- future changes to the original colormap instance do not affect the
- registered colormap. Think of this as the registry taking a snapshot
- of the colormap at registration.
- Parameters
- ----------
- cmap : matplotlib.colors.Colormap
- The colormap to register.
- name : str, optional
- The name for the colormap. If not given, ``cmap.name`` is used.
- force : bool, default: False
- If False, a ValueError is raised if trying to overwrite an already
- registered name. True supports overwriting registered colormaps
- other than the builtin colormaps.
- """
- _api.check_isinstance(colors.Colormap, cmap=cmap)
- name = name or cmap.name
- if name in self:
- if not force:
- # don't allow registering an already existing cmap
- # unless explicitly asked to
- raise ValueError(
- f'A colormap named "{name}" is already registered.')
- elif name in self._builtin_cmaps:
- # We don't allow overriding a builtin.
- raise ValueError("Re-registering the builtin cmap "
- f"{name!r} is not allowed.")
- # Warn that we are updating an already existing colormap
- _api.warn_external(f"Overwriting the cmap {name!r} "
- "that was already in the registry.")
- self._cmaps[name] = cmap.copy()
- # Someone may set the extremes of a builtin colormap and want to register it
- # with a different name for future lookups. The object would still have the
- # builtin name, so we should update it to the registered name
- if self._cmaps[name].name != name:
- self._cmaps[name].name = name
- def unregister(self, name):
- """
- Remove a colormap from the registry.
- You cannot remove built-in colormaps.
- If the named colormap is not registered, returns with no error, raises
- if you try to de-register a default colormap.
- .. warning::
- Colormap names are currently a shared namespace that may be used
- by multiple packages. Use `unregister` only if you know you
- have registered that name before. In particular, do not
- unregister just in case to clean the name before registering a
- new colormap.
- Parameters
- ----------
- name : str
- The name of the colormap to be removed.
- Raises
- ------
- ValueError
- If you try to remove a default built-in colormap.
- """
- if name in self._builtin_cmaps:
- raise ValueError(f"cannot unregister {name!r} which is a builtin "
- "colormap.")
- self._cmaps.pop(name, None)
- def get_cmap(self, cmap):
- """
- Return a color map specified through *cmap*.
- Parameters
- ----------
- cmap : str or `~matplotlib.colors.Colormap` or None
- - if a `.Colormap`, return it
- - if a string, look it up in ``mpl.colormaps``
- - if None, return the Colormap defined in :rc:`image.cmap`
- Returns
- -------
- Colormap
- """
- # get the default color map
- if cmap is None:
- return self[mpl.rcParams["image.cmap"]]
- # if the user passed in a Colormap, simply return it
- if isinstance(cmap, colors.Colormap):
- return cmap
- if isinstance(cmap, str):
- _api.check_in_list(sorted(_colormaps), cmap=cmap)
- # otherwise, it must be a string so look it up
- return self[cmap]
- raise TypeError(
- 'get_cmap expects None or an instance of a str or Colormap . ' +
- f'you passed {cmap!r} of type {type(cmap)}'
- )
- # public access to the colormaps should be via `matplotlib.colormaps`. For now,
- # we still create the registry here, but that should stay an implementation
- # detail.
- _colormaps = ColormapRegistry(_gen_cmap_registry())
- globals().update(_colormaps)
- _multivar_colormaps = ColormapRegistry(multivar_cmaps)
- _bivar_colormaps = ColormapRegistry(bivar_cmaps)
- # This is an exact copy of pyplot.get_cmap(). It was removed in 3.9, but apparently
- # caused more user trouble than expected. Re-added for 3.9.1 and extended the
- # deprecation period for two additional minor releases.
- @_api.deprecated(
- '3.7',
- removal='3.11',
- alternative="``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap()``"
- " or ``pyplot.get_cmap()``"
- )
- def get_cmap(name=None, lut=None):
- """
- Get a colormap instance, defaulting to rc values if *name* is None.
- Parameters
- ----------
- name : `~matplotlib.colors.Colormap` or str or None, default: None
- If a `.Colormap` instance, it will be returned. Otherwise, the name of
- a colormap known to Matplotlib, which will be resampled by *lut*. The
- default, None, means :rc:`image.cmap`.
- lut : int or None, default: None
- If *name* is not already a Colormap instance and *lut* is not None, the
- colormap will be resampled to have *lut* entries in the lookup table.
- Returns
- -------
- Colormap
- """
- if name is None:
- name = mpl.rcParams['image.cmap']
- if isinstance(name, colors.Colormap):
- return name
- _api.check_in_list(sorted(_colormaps), name=name)
- if lut is None:
- return _colormaps[name]
- else:
- return _colormaps[name].resampled(lut)
- def _ensure_cmap(cmap):
- """
- Ensure that we have a `.Colormap` object.
- For internal use to preserve type stability of errors.
- Parameters
- ----------
- cmap : None, str, Colormap
- - if a `Colormap`, return it
- - if a string, look it up in mpl.colormaps
- - if None, look up the default color map in mpl.colormaps
- Returns
- -------
- Colormap
- """
- if isinstance(cmap, colors.Colormap):
- return cmap
- cmap_name = cmap if cmap is not None else mpl.rcParams["image.cmap"]
- # use check_in_list to ensure type stability of the exception raised by
- # the internal usage of this (ValueError vs KeyError)
- if cmap_name not in _colormaps:
- _api.check_in_list(sorted(_colormaps), cmap=cmap_name)
- return mpl.colormaps[cmap_name]
|