diff --git a/doc/users/next_whats_new/strnorm.rst b/doc/users/next_whats_new/strnorm.rst new file mode 100644 index 000000000000..42be191f2d55 --- /dev/null +++ b/doc/users/next_whats_new/strnorm.rst @@ -0,0 +1,6 @@ +Setting norms with strings +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Norms can now be set (e.g. on images) using the string name of the +corresponding scale, e.g. ``imshow(array, norm="log")``. Note that in that +case, it is permissible to also pass *vmin* and *vmax*, as a new Norm instance +will be created under the hood. diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 2aeab71e169a..d8c891e5c84d 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -4322,6 +4322,7 @@ def invalid_shape_exception(csize, xsize): "edgecolors", "c", "facecolor", "facecolors", "color"], label_namer="y") + @_docstring.interpd def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, *, edgecolors=None, plotnonfinite=False, **kwargs): @@ -4368,21 +4369,17 @@ def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None, See :mod:`matplotlib.markers` for more information about marker styles. - cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` - A `.Colormap` instance or registered colormap name. *cmap* is only - used if *c* is an array of floats. + %(cmap_doc)s - norm : `~matplotlib.colors.Normalize`, default: None - If *c* is an array of floats, *norm* is used to scale the color - data, *c*, in the range 0 to 1, in order to map into the colormap - *cmap*. - If *None*, use the default `.colors.Normalize`. + This parameter is ignored if *c* is RGB(A). - vmin, vmax : float, default: None - *vmin* and *vmax* are used in conjunction with the default norm to - map the color array *c* to the colormap *cmap*. If None, the - respective min and max of the color array is used. - It is an error to use *vmin*/*vmax* when *norm* is given. + %(norm_doc)s + + This parameter is ignored if *c* is RGB(A). + + %(vmin_vmax_doc)s + + This parameter is ignored if *c* is RGB(A). alpha : float, default: None The alpha blending value, between 0 (transparent) and 1 (opaque). @@ -4655,21 +4652,11 @@ def hexbin(self, x, y, C=None, gridsize=100, bins=None, Other Parameters ---------------- - cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` - The Colormap instance or registered colormap name used to map - the bin values to colors. - - norm : `~matplotlib.colors.Normalize`, optional - The Normalize instance scales the bin values to the canonical - colormap range [0, 1] for mapping to colors. By default, the data - range is mapped to the colorbar range using linear scaling. - - vmin, vmax : float, default: None - The colorbar range. If *None*, suitable min/max values are - automatically chosen by the `.Normalize` instance (defaults to - the respective min/max values of the bins in case of the default - linear scaling). - It is an error to use *vmin*/*vmax* when *norm* is given. + %(cmap_doc)s + + %(norm_doc)s + + %(vmin_vmax_doc)s alpha : float between 0 and 1, optional The alpha blending value, between 0 (transparent) and 1 (opaque). @@ -5295,8 +5282,13 @@ def fill_betweenx(self, y, x1, x2=0, where=None, replace_names=["y", "x1", "x2", "where"]) #### plotting z(x, y): imshow, pcolor and relatives, contour + + # Once this deprecation elapses, also move vmin, vmax right after norm, to + # match the signature of other methods returning ScalarMappables and keep + # the documentation for *norm*, *vmax* and *vmin* together. @_api.make_keyword_only("3.5", "aspect") @_preprocess_data() + @_docstring.interpd def imshow(self, X, cmap=None, norm=None, aspect=None, interpolation=None, alpha=None, vmin=None, vmax=None, origin=None, extent=None, *, @@ -5335,15 +5327,17 @@ def imshow(self, X, cmap=None, norm=None, aspect=None, Out-of-range RGB(A) values are clipped. - cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` - The Colormap instance or registered colormap name used to map - scalar data to colors. This parameter is ignored for RGB(A) data. + %(cmap_doc)s + + This parameter is ignored if *X* is RGB(A). - norm : `~matplotlib.colors.Normalize`, optional - The `.Normalize` instance used to scale scalar data to the [0, 1] - range before mapping to colors using *cmap*. By default, a linear - scaling mapping the lowest value to 0 and the highest to 1 is used. - This parameter is ignored for RGB(A) data. + %(norm_doc)s + + This parameter is ignored if *X* is RGB(A). + + %(vmin_vmax_doc)s + + This parameter is ignored if *X* is RGB(A). aspect : {'equal', 'auto'} or float, default: :rc:`image.aspect` The aspect ratio of the Axes. This parameter is particularly @@ -5403,13 +5397,6 @@ def imshow(self, X, cmap=None, norm=None, aspect=None, If *alpha* is an array, the alpha blending values are applied pixel by pixel, and *alpha* must have the same shape as *X*. - vmin, vmax : float, optional - When using scalar data and no explicit *norm*, *vmin* and *vmax* - define the data range that the colormap covers. By default, - the colormap covers the complete value range of the supplied - data. It is an error to use *vmin*/*vmax* when *norm* is given. - When using RGB(A) data, parameters *vmin*/*vmax* are ignored. - origin : {'upper', 'lower'}, default: :rc:`image.origin` Place the [0, 0] index of the array in the upper left or lower left corner of the Axes. The convention (the default) 'upper' is @@ -5673,7 +5660,8 @@ def pcolor(self, *args, shading=None, alpha=None, norm=None, cmap=None, Parameters ---------- C : 2D array-like - The color-mapped values. + The color-mapped values. Color-mapping is controlled by *cmap*, + *norm*, *vmin*, and *vmax*. X, Y : array-like, optional The coordinates of the corners of quadrilaterals of a pcolormesh:: @@ -5720,21 +5708,11 @@ def pcolor(self, *args, shading=None, alpha=None, norm=None, cmap=None, See :doc:`/gallery/images_contours_and_fields/pcolormesh_grids` for more description. - cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` - A Colormap instance or registered colormap name. The colormap - maps the *C* values to colors. + %(cmap_doc)s - norm : `~matplotlib.colors.Normalize`, optional - The Normalize instance scales the data values to the canonical - colormap range [0, 1] for mapping to colors. By default, the data - range is mapped to the colorbar range using linear scaling. + %(norm_doc)s - vmin, vmax : float, default: None - The colorbar range. If *None*, suitable min/max values are - automatically chosen by the `.Normalize` instance (defaults to - the respective min/max values of *C* in case of the default linear - scaling). - It is an error to use *vmin*/*vmax* when *norm* is given. + %(vmin_vmax_doc)s edgecolors : {'none', None, 'face', color, color sequence}, optional The color of the edges. Defaults to 'none'. Possible values: @@ -5915,7 +5893,8 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None, Parameters ---------- C : 2D array-like - The color-mapped values. + The color-mapped values. Color-mapping is controlled by *cmap*, + *norm*, *vmin*, and *vmax*. X, Y : array-like, optional The coordinates of the corners of quadrilaterals of a pcolormesh:: @@ -5946,21 +5925,11 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None, expanded as needed into the appropriate 2D arrays, making a rectangular grid. - cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` - A Colormap instance or registered colormap name. The colormap - maps the *C* values to colors. + %(cmap_doc)s - norm : `~matplotlib.colors.Normalize`, optional - The Normalize instance scales the data values to the canonical - colormap range [0, 1] for mapping to colors. By default, the data - range is mapped to the colorbar range using linear scaling. + %(norm_doc)s - vmin, vmax : float, default: None - The colorbar range. If *None*, suitable min/max values are - automatically chosen by the `.Normalize` instance (defaults to - the respective min/max values of *C* in case of the default linear - scaling). - It is an error to use *vmin*/*vmax* when *norm* is given. + %(vmin_vmax_doc)s edgecolors : {'none', None, 'face', color, color sequence}, optional The color of the edges. Defaults to 'none'. Possible values: @@ -6150,8 +6119,8 @@ def pcolorfast(self, *args, alpha=None, norm=None, cmap=None, vmin=None, C : array-like The image data. Supported array shapes are: - - (M, N): an image with scalar data. The data is visualized - using a colormap. + - (M, N): an image with scalar data. Color-mapping is controlled + by *cmap*, *norm*, *vmin*, and *vmax*. - (M, N, 3): an image with RGB values (0-1 float or 0-255 int). - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int), i.e. including transparency. @@ -6194,21 +6163,17 @@ def pcolorfast(self, *args, alpha=None, norm=None, cmap=None, vmin=None, These arguments can only be passed positionally. - cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` - A Colormap instance or registered colormap name. The colormap - maps the *C* values to colors. + %(cmap_doc)s + + This parameter is ignored if *C* is RGB(A). + + %(norm_doc)s + + This parameter is ignored if *C* is RGB(A). - norm : `~matplotlib.colors.Normalize`, optional - The Normalize instance scales the data values to the canonical - colormap range [0, 1] for mapping to colors. By default, the data - range is mapped to the colorbar range using linear scaling. + %(vmin_vmax_doc)s - vmin, vmax : float, default: None - The colorbar range. If *None*, suitable min/max values are - automatically chosen by the `.Normalize` instance (defaults to - the respective min/max values of *C* in case of the default linear - scaling). - It is an error to use *vmin*/*vmax* when *norm* is given. + This parameter is ignored if *C* is RGB(A). alpha : float, default: None The alpha blending value, between 0 (transparent) and 1 (opaque). @@ -6963,16 +6928,11 @@ def hist2d(self, x, y, bins=10, range=None, density=False, weights=None, Other Parameters ---------------- - cmap : Colormap or str, optional - A `.colors.Colormap` instance. If not set, use rc settings. + %(cmap_doc)s - norm : Normalize, optional - A `.colors.Normalize` instance is used to - scale luminance data to ``[0, 1]``. If not set, defaults to - `.colors.Normalize()`. + %(norm_doc)s - vmin/vmax : None or scalar, optional - Arguments passed to the `~.colors.Normalize` instance. + %(vmin_vmax_doc)s alpha : ``0 <= scalar <= 1`` or ``None``, optional The alpha blending value. diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index 0ae8f7533ea1..2e6741add7ea 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -16,12 +16,13 @@ """ from collections.abc import Mapping +import functools import numpy as np from numpy import ma import matplotlib as mpl -from matplotlib import _api, colors, cbook +from matplotlib import _api, colors, cbook, scale from matplotlib._cm import datad from matplotlib._cm_listed import cmaps as cmaps_listed @@ -308,6 +309,34 @@ def unregister_cmap(name): return cmap +def _auto_norm_from_scale(scale_cls): + """ + Automatically generate a norm class from *scale_cls*. + + This differs from `.colors.make_norm_from_scale` in the following points: + + - This function is not a class decorator, but directly returns a norm class + (as if decorating `.Normalize`). + - The scale is automatically constructed with ``nonpositive="mask"``, if it + supports such a parameter, to work around the difference in defaults + between standard scales (which use "clip") and norms (which use "mask"). + + Note that ``make_norm_from_scale`` caches the generated norm classes + (not the instances) and reuses them for later calls. For example, + ``type(_auto_norm_from_scale("log")) == LogNorm``. + """ + # Actually try to construct an instance, to verify whether + # ``nonpositive="mask"`` is supported. + try: + norm = colors.make_norm_from_scale( + functools.partial(scale_cls, nonpositive="mask"))( + colors.Normalize)() + except TypeError: + norm = colors.make_norm_from_scale(scale_cls)( + colors.Normalize)() + return type(norm) + + class ScalarMappable: """ A mixin class to map scalar data to RGBA. @@ -318,12 +347,13 @@ class ScalarMappable: def __init__(self, norm=None, cmap=None): """ - Parameters ---------- - norm : `matplotlib.colors.Normalize` (or subclass thereof) + norm : `.Normalize` (or subclass thereof) or str or None The normalizing object which scales data, typically into the interval ``[0, 1]``. + If a `str`, a `.Normalize` subclass is dynamically generated based + on the scale with the corresponding name. If *None*, *norm* defaults to a *colors.Normalize* object which initializes its scaling based on the first data processed. cmap : str or `~matplotlib.colors.Colormap` @@ -353,11 +383,11 @@ def _scale_norm(self, norm, vmin, vmax): """ if vmin is not None or vmax is not None: self.set_clim(vmin, vmax) - if norm is not None: + if isinstance(norm, colors.Normalize): raise ValueError( - "Passing parameters norm and vmin/vmax simultaneously is " - "not supported. Please pass vmin/vmax directly to the " - "norm when creating it.") + "Passing a Normalize instance simultaneously with " + "vmin/vmax is not supported. Please pass vmin/vmax " + "directly to the norm when creating it.") # always resolve the autoscaling so we have concrete limits # rather than deferring to draw time. @@ -531,9 +561,18 @@ def norm(self): @norm.setter def norm(self, norm): - _api.check_isinstance((colors.Normalize, None), norm=norm) + _api.check_isinstance((colors.Normalize, str, None), norm=norm) if norm is None: norm = colors.Normalize() + elif isinstance(norm, str): + try: + scale_cls = scale._scale_mapping[norm] + except KeyError: + raise ValueError( + "Invalid norm str name; the following values are " + "supported: {}".format(", ".join(scale._scale_mapping)) + ) from None + norm = _auto_norm_from_scale(scale_cls)() if norm is self.norm: # We aren't updating anything @@ -555,7 +594,7 @@ def set_norm(self, norm): Parameters ---------- - norm : `.Normalize` or None + norm : `.Normalize` or str or None Notes ----- @@ -594,3 +633,33 @@ def changed(self): """ self.callbacks.process('changed', self) self.stale = True + + +# The docstrings here must be generic enough to apply to all relevant methods. +mpl._docstring.interpd.update( + cmap_doc="""\ +cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + The Colormap instance or registered colormap name used to map scalar data + to colors.""", + norm_doc="""\ +norm : str or `~matplotlib.colors.Normalize`, optional + The normalization method used to scale scalar data to the [0, 1] range + before mapping to colors using *cmap*. By default, a linear scaling is + used, mapping the lowest value to 0 and the highest to 1. + + If given, this can be one of the following: + + - An instance of `.Normalize` or one of its subclasses + (see :doc:`/tutorials/colors/colormapnorms`). + - A scale name, i.e. one of "linear", "log", "symlog", "logit", etc. For a + list of available scales, call `matplotlib.scale.get_scale_names()`. + In that case, a suitable `.Normalize` subclass is dynamically generated + and instantiated.""", + vmin_vmax_doc="""\ +vmin, vmax : float, optional + When using scalar data and no explicit *norm*, *vmin* and *vmax* define + the data range that the colormap covers. By default, the colormap covers + the complete value range of the supplied data. It is an error to use + *vmin*/*vmax* when a *norm* instance is given (but using a `str` *norm* + name together with *vmin*/*vmax* is acceptable).""", +) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 851fec9fffb9..8bafb92f3c2e 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -131,13 +131,9 @@ def __init__(self, offset_transform : `~.Transform`, default: `.IdentityTransform` A single transform which will be applied to each *offsets* vector before it is used. - norm : `~.colors.Normalize`, optional - Forwarded to `.ScalarMappable`. The default of - ``None`` means that the first draw call will set ``vmin`` and - ``vmax`` using the minimum and maximum values of the data. - cmap : `~.colors.Colormap`, optional - Forwarded to `.ScalarMappable`. The default of - ``None`` will result in :rc:`image.cmap` being used. + cmap, norm + Data normalization and colormapping parameters. See + `.ScalarMappable` for a detailed description. hatch : str, optional Hatching pattern to use in filled paths, if any. Valid strings are ['/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*']. See diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 043e9b3642ba..2a537b6c9b7b 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -1598,21 +1598,37 @@ class norm_cls(Normalize): if base_norm_cls is None: return functools.partial(make_norm_from_scale, scale_cls, init=init) + if isinstance(scale_cls, functools.partial): + scale_args = scale_cls.args + scale_kwargs_items = tuple(scale_cls.keywords.items()) + scale_cls = scale_cls.func + else: + scale_args = scale_kwargs_items = () + if init is None: def init(vmin=None, vmax=None, clip=False): pass return _make_norm_from_scale( - scale_cls, base_norm_cls, inspect.signature(init)) + scale_cls, scale_args, scale_kwargs_items, + base_norm_cls, inspect.signature(init)) @functools.lru_cache(None) -def _make_norm_from_scale(scale_cls, base_norm_cls, bound_init_signature): +def _make_norm_from_scale( + scale_cls, scale_args, scale_kwargs_items, + base_norm_cls, bound_init_signature, +): """ Helper for `make_norm_from_scale`. - This function is split out so that it takes a signature object as third - argument (as signatures are picklable, contrary to arbitrary lambdas); - caching is also used so that different unpickles reuse the same class. + This function is split out to enable caching (in particular so that + different unpickles reuse the same class). In order to do so, + + - ``functools.partial`` *scale_cls* is expanded into ``func, args, kwargs`` + to allow memoizing returned norms (partial instances always compare + unequal, but we can check identity based on ``func, args, kwargs``; + - *init* is replaced by *init_signature*, as signatures are picklable, + unlike to arbitrary lambdas. """ class Norm(base_norm_cls): @@ -1631,7 +1647,8 @@ def __reduce__(self): except (ImportError, AttributeError): pass return (_picklable_norm_constructor, - (scale_cls, base_norm_cls, bound_init_signature), + (scale_cls, scale_args, scale_kwargs_items, + base_norm_cls, bound_init_signature), vars(self)) def __init__(self, *args, **kwargs): @@ -1639,7 +1656,9 @@ def __init__(self, *args, **kwargs): ba.apply_defaults() super().__init__( **{k: ba.arguments.pop(k) for k in ["vmin", "vmax", "clip"]}) - self._scale = scale_cls(axis=None, **ba.arguments) + self._scale = functools.partial( + scale_cls, *scale_args, **dict(scale_kwargs_items))( + axis=None, **ba.arguments) self._trf = self._scale.get_transform() __init__.__signature__ = bound_init_signature.replace(parameters=[ @@ -1693,12 +1712,12 @@ def autoscale_None(self, A): in_trf_domain = np.extract(np.isfinite(self._trf.transform(A)), A) return super().autoscale_None(in_trf_domain) - Norm.__name__ = ( - f"{scale_cls.__name__}Norm" if base_norm_cls is Normalize - else base_norm_cls.__name__) - Norm.__qualname__ = ( - f"{scale_cls.__qualname__}Norm" if base_norm_cls is Normalize - else base_norm_cls.__qualname__) + if base_norm_cls is Normalize: + Norm.__name__ = f"{scale_cls.__name__}Norm" + Norm.__qualname__ = f"{scale_cls.__qualname__}Norm" + else: + Norm.__name__ = base_norm_cls.__name__ + Norm.__qualname__ = base_norm_cls.__qualname__ Norm.__module__ = base_norm_cls.__module__ Norm.__doc__ = base_norm_cls.__doc__ @@ -1746,9 +1765,10 @@ def forward(values: array-like) -> array-like """ -@make_norm_from_scale(functools.partial(scale.LogScale, nonpositive="mask")) -class LogNorm(Normalize): - """Normalize a given value to the 0-1 range on a log scale.""" +LogNorm = make_norm_from_scale( + functools.partial(scale.LogScale, nonpositive="mask"))(Normalize) +LogNorm.__name__ = LogNorm.__qualname__ = "LogNorm" +LogNorm.__doc__ = "Normalize a given value to the 0-1 range on a log scale." @make_norm_from_scale( diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index 34f07e1a96b1..7f66aaa44a3d 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -1592,7 +1592,8 @@ def _initialize_x_y(self, z): ``X = range(N)``, ``Y = range(M)``. Z : (M, N) array-like - The height values over which the contour is drawn. + The height values over which the contour is drawn. Color-mapping is + controlled by *cmap*, *norm*, *vmin*, and *vmax*. levels : int or array-like, optional Determines the number and positions of the contour lines / regions. @@ -1635,21 +1636,20 @@ def _initialize_x_y(self, z): alpha : float, default: 1 The alpha blending value, between 0 (transparent) and 1 (opaque). -cmap : str or `.Colormap`, default: :rc:`image.cmap` - A `.Colormap` instance or registered colormap name. The colormap - maps the level values to colors. +%(cmap_doc)s - If both *colors* and *cmap* are given, an error is raised. + This parameter is ignored if *colors* is set. -norm : `~matplotlib.colors.Normalize`, optional - If a colormap is used, the `.Normalize` instance scales the level - values to the canonical colormap range [0, 1] for mapping to - colors. If not given, the default linear scaling is used. +%(norm_doc)s -vmin, vmax : float, optional - If not *None*, either or both of these values will be supplied to - the `.Normalize` instance, overriding the default color scaling - based on *levels*. + This parameter is ignored if *colors* is set. + +%(vmin_vmax_doc)s + + If *vmin* or *vmax* are not given, the default color scaling is based on + *levels*. + + This parameter is ignored if *colors* is set. origin : {*None*, 'upper', 'lower', 'image'}, default: None Determines the orientation and exact position of *Z* by specifying @@ -1805,4 +1805,4 @@ def _initialize_x_y(self, z): `_ algorithm to compute contour locations. More information can be found in `ContourPy documentation `_. -""") +""" % _docstring.interpd.params) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 853ef4604682..096e84ae4bf9 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -2724,6 +2724,7 @@ def set_canvas(self, canvas): """ self.canvas = canvas + @_docstring.interpd def figimage(self, X, xo=0, yo=0, alpha=None, norm=None, cmap=None, vmin=None, vmax=None, origin=None, resize=False, **kwargs): """ @@ -2737,9 +2738,11 @@ def figimage(self, X, xo=0, yo=0, alpha=None, norm=None, cmap=None, X The image data. This is an array of one of the following shapes: - - MxN: luminance (grayscale) values - - MxNx3: RGB values - - MxNx4: RGBA values + - (M, N): an image with scalar data. Color-mapping is controlled + by *cmap*, *norm*, *vmin*, and *vmax*. + - (M, N, 3): an image with RGB values (0-1 float or 0-255 int). + - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int), + i.e. including transparency. xo, yo : int The *x*/*y* image offset in pixels. @@ -2747,16 +2750,17 @@ def figimage(self, X, xo=0, yo=0, alpha=None, norm=None, cmap=None, alpha : None or float The alpha blending value. - norm : `matplotlib.colors.Normalize` - A `.Normalize` instance to map the luminance to the - interval [0, 1]. + %(cmap_doc)s - cmap : str or `matplotlib.colors.Colormap`, default: :rc:`image.cmap` - The colormap to use. + This parameter is ignored if *X* is RGB(A). - vmin, vmax : float - If *norm* is not given, these values set the data limits for the - colormap. + %(norm_doc)s + + This parameter is ignored if *X* is RGB(A). + + %(vmin_vmax_doc)s + + This parameter is ignored if *X* is RGB(A). origin : {'upper', 'lower'}, default: :rc:`image.origin` Indicates where the [0, 0] index of the array is in the upper left diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index ca1c7f2fa9c0..6401b64dc248 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -865,7 +865,7 @@ class AxesImage(_ImageBase): cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` The Colormap instance or registered colormap name used to map scalar data to colors. - norm : `~matplotlib.colors.Normalize` + norm : str or `~matplotlib.colors.Normalize` Maps luminance to 0-1. interpolation : str, default: :rc:`image.interpolation` Supported values are 'none', 'antialiased', 'nearest', 'bilinear', @@ -1216,7 +1216,7 @@ def __init__(self, ax, cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` The Colormap instance or registered colormap name used to map scalar data to colors. - norm : `~matplotlib.colors.Normalize` + norm : str or `~matplotlib.colors.Normalize` Maps luminance to 0-1. **kwargs : `.Artist` properties """ diff --git a/lib/matplotlib/streamplot.py b/lib/matplotlib/streamplot.py index 8db2f7d9d74f..31ad96044a1e 100644 --- a/lib/matplotlib/streamplot.py +++ b/lib/matplotlib/streamplot.py @@ -46,12 +46,10 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None, The streamline color. If given an array, its values are converted to colors using *cmap* and *norm*. The array must have the same shape as *u* and *v*. - cmap : `~matplotlib.colors.Colormap` - Colormap used to plot streamlines and arrows. This is only used if - *color* is an array. - norm : `~matplotlib.colors.Normalize` - Normalize object used to scale luminance data to 0, 1. If ``None``, - stretch (min, max) to (0, 1). This is only used if *color* is an array. + cmap, norm + Data normalization and colormapping parameters for *color*; only used + if *color* is an array of floats. See `~.Axes.imshow` for a detailed + description. arrowsize : float Scaling factor for the arrow size. arrowstyle : str diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index d3869ad9d256..b058fbd2577a 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -995,8 +995,8 @@ def test_imshow_norm_vminvmax(): a = [[1, 2], [3, 4]] ax = plt.axes() with pytest.raises(ValueError, - match="Passing parameters norm and vmin/vmax " - "simultaneously is not supported."): + match="Passing a Normalize instance simultaneously " + "with vmin/vmax is not supported."): ax.imshow(a, norm=mcolors.Normalize(-10, 10), vmin=0, vmax=5) @@ -2444,8 +2444,8 @@ def test_scatter_norm_vminvmax(self): x = [1, 2, 3] ax = plt.axes() with pytest.raises(ValueError, - match="Passing parameters norm and vmin/vmax " - "simultaneously is not supported."): + match="Passing a Normalize instance simultaneously " + "with vmin/vmax is not supported."): ax.scatter(x, x, c=x, norm=mcolors.Normalize(-10, 10), vmin=0, vmax=5) diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 79740e02363c..88c41229caa8 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -1410,3 +1410,25 @@ def test_large_image(fig_test, fig_ref, dim, size, msg, origin): extent=(0, 1, 0, 1), interpolation='none', origin=origin) + + +@check_figures_equal(extensions=["png"]) +def test_str_norms(fig_test, fig_ref): + t = np.random.rand(10, 10) * .8 + .1 # between 0 and 1 + axts = fig_test.subplots(1, 5) + axts[0].imshow(t, norm="log") + axts[1].imshow(t, norm="log", vmin=.2) + axts[2].imshow(t, norm="symlog") + axts[3].imshow(t, norm="symlog", vmin=.3, vmax=.7) + axts[4].imshow(t, norm="logit", vmin=.3, vmax=.7) + axrs = fig_ref.subplots(1, 5) + axrs[0].imshow(t, norm=colors.LogNorm()) + axrs[1].imshow(t, norm=colors.LogNorm(vmin=.2)) + # same linthresh as SymmetricalLogScale's default. + axrs[2].imshow(t, norm=colors.SymLogNorm(linthresh=2)) + axrs[3].imshow(t, norm=colors.SymLogNorm(linthresh=2, vmin=.3, vmax=.7)) + axrs[4].imshow(t, norm="logit", clim=(.3, .7)) + + assert type(axts[0].images[0].norm) == colors.LogNorm # Exactly that class + with pytest.raises(ValueError): + axts[0].imshow(t, norm="foobar") diff --git a/lib/matplotlib/tri/tricontour.py b/lib/matplotlib/tri/tricontour.py index 567c436e4a4c..56784bfab92f 100644 --- a/lib/matplotlib/tri/tricontour.py +++ b/lib/matplotlib/tri/tricontour.py @@ -82,12 +82,12 @@ def _contour_args(self, args, kwargs): _docstring.interpd.update(_tricontour_doc=""" -Draw contour %(type)s on an unstructured triangular grid. +Draw contour %%(type)s on an unstructured triangular grid. Call signatures:: - %(func)s(triangulation, Z, [levels], ...) - %(func)s(x, y, Z, [levels], *, [triangles=triangles], [mask=mask], ...) + %%(func)s(triangulation, Z, [levels], ...) + %%(func)s(x, y, Z, [levels], *, [triangles=triangles], [mask=mask], ...) The triangular grid can be specified either by passing a `.Triangulation` object as the first parameter, or by passing the points *x*, *y* and @@ -96,7 +96,7 @@ def _contour_args(self, args, kwargs): *triangles* are given, the triangulation is calculated on the fly. It is possible to pass *triangles* positionally, i.e. -``%(func)s(x, y, triangles, Z, ...)``. However, this is discouraged. For more +``%%(func)s(x, y, triangles, Z, ...)``. However, this is discouraged. For more clarity, pass *triangles* via keyword argument. Parameters @@ -109,7 +109,8 @@ def _contour_args(self, args, kwargs): This is mutually exclusive with specifying *triangulation*. Z : array-like - The height values over which the contour is drawn. + The height values over which the contour is drawn. Color-mapping is + controlled by *cmap*, *norm*, *vmin*, and *vmax*. levels : int or array-like, optional Determines the number and positions of the contour lines / regions. @@ -128,7 +129,7 @@ def _contour_args(self, args, kwargs): Other Parameters ---------------- colors : color string or sequence of colors, optional - The colors of the levels, i.e., the contour %(type)s. + The colors of the levels, i.e., the contour %%(type)s. The sequence is cycled for the levels in ascending order. If the sequence is shorter than the number of levels, it's repeated. @@ -143,21 +144,20 @@ def _contour_args(self, args, kwargs): alpha : float, default: 1 The alpha blending value, between 0 (transparent) and 1 (opaque). -cmap : str or `.Colormap`, default: :rc:`image.cmap` - A `.Colormap` instance or registered colormap name. The colormap maps the - level values to colors. +%(cmap_doc)s - If both *colors* and *cmap* are given, an error is raised. + This parameter is ignored if *colors* is set. -norm : `~matplotlib.colors.Normalize`, optional - If a colormap is used, the `.Normalize` instance scales the level values to - the canonical colormap range [0, 1] for mapping to colors. If not given, - the default linear scaling is used. +%(norm_doc)s -vmin, vmax : float, optional - If not *None*, either or both of these values will be supplied to - the `.Normalize` instance, overriding the default color scaling - based on *levels*. + This parameter is ignored if *colors* is set. + +%(vmin_vmax_doc)s + + If *vmin* or *vmax* are not given, the default color scaling is based on + *levels*. + + This parameter is ignored if *colors* is set. origin : {*None*, 'upper', 'lower', 'image'}, default: None Determines the orientation and exact position of *Z* by specifying the @@ -184,7 +184,7 @@ def _contour_args(self, args, kwargs): Defaults to `~.ticker.MaxNLocator`. extend : {'neither', 'both', 'min', 'max'}, default: 'neither' - Determines the ``%(func)s``-coloring of values that are outside the + Determines the ``%%(func)s``-coloring of values that are outside the *levels* range. If 'neither', values outside the *levels* range are not colored. If 'min', @@ -212,7 +212,7 @@ def _contour_args(self, args, kwargs): antialiased : bool, optional Enable antialiasing, overriding the defaults. For filled contours, the default is *True*. For line contours, - it is taken from :rc:`lines.antialiased`.""") + it is taken from :rc:`lines.antialiased`.""" % _docstring.interpd.params) @_docstring.Substitution(func='tricontour', type='lines')