You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			311 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			311 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
"""
 | 
						|
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]
 |