271 lines
10 KiB
Python
271 lines
10 KiB
Python
import numpy as np
|
|
|
|
from matplotlib import _docstring
|
|
from matplotlib.contour import ContourSet
|
|
from matplotlib.tri._triangulation import Triangulation
|
|
|
|
|
|
@_docstring.dedent_interpd
|
|
class TriContourSet(ContourSet):
|
|
"""
|
|
Create and store a set of contour lines or filled regions for
|
|
a triangular grid.
|
|
|
|
This class is typically not instantiated directly by the user but by
|
|
`~.Axes.tricontour` and `~.Axes.tricontourf`.
|
|
|
|
%(contour_set_attributes)s
|
|
"""
|
|
def __init__(self, ax, *args, **kwargs):
|
|
"""
|
|
Draw triangular grid contour lines or filled regions,
|
|
depending on whether keyword arg *filled* is False
|
|
(default) or True.
|
|
|
|
The first argument of the initializer must be an `~.axes.Axes`
|
|
object. The remaining arguments and keyword arguments
|
|
are described in the docstring of `~.Axes.tricontour`.
|
|
"""
|
|
super().__init__(ax, *args, **kwargs)
|
|
|
|
def _process_args(self, *args, **kwargs):
|
|
"""
|
|
Process args and kwargs.
|
|
"""
|
|
if isinstance(args[0], TriContourSet):
|
|
C = args[0]._contour_generator
|
|
if self.levels is None:
|
|
self.levels = args[0].levels
|
|
self.zmin = args[0].zmin
|
|
self.zmax = args[0].zmax
|
|
self._mins = args[0]._mins
|
|
self._maxs = args[0]._maxs
|
|
else:
|
|
from matplotlib import _tri
|
|
tri, z = self._contour_args(args, kwargs)
|
|
C = _tri.TriContourGenerator(tri.get_cpp_triangulation(), z)
|
|
self._mins = [tri.x.min(), tri.y.min()]
|
|
self._maxs = [tri.x.max(), tri.y.max()]
|
|
|
|
self._contour_generator = C
|
|
return kwargs
|
|
|
|
def _contour_args(self, args, kwargs):
|
|
tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args,
|
|
**kwargs)
|
|
z, *args = args
|
|
z = np.ma.asarray(z)
|
|
if z.shape != tri.x.shape:
|
|
raise ValueError('z array must have same length as triangulation x'
|
|
' and y arrays')
|
|
|
|
# z values must be finite, only need to check points that are included
|
|
# in the triangulation.
|
|
z_check = z[np.unique(tri.get_masked_triangles())]
|
|
if np.ma.is_masked(z_check):
|
|
raise ValueError('z must not contain masked points within the '
|
|
'triangulation')
|
|
if not np.isfinite(z_check).all():
|
|
raise ValueError('z array must not contain non-finite values '
|
|
'within the triangulation')
|
|
|
|
z = np.ma.masked_invalid(z, copy=False)
|
|
self.zmax = float(z_check.max())
|
|
self.zmin = float(z_check.min())
|
|
if self.logscale and self.zmin <= 0:
|
|
func = 'contourf' if self.filled else 'contour'
|
|
raise ValueError(f'Cannot {func} log of negative values.')
|
|
self._process_contour_level_args(args, z.dtype)
|
|
return (tri, z)
|
|
|
|
|
|
_docstring.interpd.update(_tricontour_doc="""
|
|
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], ...)
|
|
|
|
The triangular grid can be specified either by passing a `.Triangulation`
|
|
object as the first parameter, or by passing the points *x*, *y* and
|
|
optionally the *triangles* and a *mask*. See `.Triangulation` for an
|
|
explanation of these parameters. If neither of *triangulation* or
|
|
*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
|
|
clarity, pass *triangles* via keyword argument.
|
|
|
|
Parameters
|
|
----------
|
|
triangulation : `.Triangulation`, optional
|
|
An already created triangular grid.
|
|
|
|
x, y, triangles, mask
|
|
Parameters defining the triangular grid. See `.Triangulation`.
|
|
This is mutually exclusive with specifying *triangulation*.
|
|
|
|
z : array-like
|
|
The height values over which the contour is drawn. Color-mapping is
|
|
controlled by *cmap*, *norm*, *vmin*, and *vmax*.
|
|
|
|
.. note::
|
|
All values in *z* must be finite. Hence, nan and inf values must
|
|
either be removed or `~.Triangulation.set_mask` be used.
|
|
|
|
levels : int or array-like, optional
|
|
Determines the number and positions of the contour lines / regions.
|
|
|
|
If an int *n*, use `~matplotlib.ticker.MaxNLocator`, which tries to
|
|
automatically choose no more than *n+1* "nice" contour levels between
|
|
between minimum and maximum numeric values of *Z*.
|
|
|
|
If array-like, draw contour lines at the specified levels. The values must
|
|
be in increasing order.
|
|
|
|
Returns
|
|
-------
|
|
`~matplotlib.tri.TriContourSet`
|
|
|
|
Other Parameters
|
|
----------------
|
|
colors : :mpltype:`color` or list of :mpltype:`color`, optional
|
|
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 is repeated.
|
|
|
|
As a shortcut, single color strings may be used in place of one-element
|
|
lists, i.e. ``'red'`` instead of ``['red']`` to color all levels with the
|
|
same color. This shortcut does only work for color strings, not for other
|
|
ways of specifying colors.
|
|
|
|
By default (value *None*), the colormap specified by *cmap* will be used.
|
|
|
|
alpha : float, default: 1
|
|
The alpha blending value, between 0 (transparent) and 1 (opaque).
|
|
|
|
%(cmap_doc)s
|
|
|
|
This parameter is ignored if *colors* is set.
|
|
|
|
%(norm_doc)s
|
|
|
|
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
|
|
position of ``z[0, 0]``. This is only relevant, if *X*, *Y* are not given.
|
|
|
|
- *None*: ``z[0, 0]`` is at X=0, Y=0 in the lower left corner.
|
|
- 'lower': ``z[0, 0]`` is at X=0.5, Y=0.5 in the lower left corner.
|
|
- 'upper': ``z[0, 0]`` is at X=N+0.5, Y=0.5 in the upper left corner.
|
|
- 'image': Use the value from :rc:`image.origin`.
|
|
|
|
extent : (x0, x1, y0, y1), optional
|
|
If *origin* is not *None*, then *extent* is interpreted as in `.imshow`: it
|
|
gives the outer pixel boundaries. In this case, the position of z[0, 0] is
|
|
the center of the pixel, not a corner. If *origin* is *None*, then
|
|
(*x0*, *y0*) is the position of z[0, 0], and (*x1*, *y1*) is the position
|
|
of z[-1, -1].
|
|
|
|
This argument is ignored if *X* and *Y* are specified in the call to
|
|
contour.
|
|
|
|
locator : ticker.Locator subclass, optional
|
|
The locator is used to determine the contour levels if they are not given
|
|
explicitly via *levels*.
|
|
Defaults to `~.ticker.MaxNLocator`.
|
|
|
|
extend : {'neither', 'both', 'min', 'max'}, default: 'neither'
|
|
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',
|
|
'max' or 'both', color the values below, above or below and above the
|
|
*levels* range.
|
|
|
|
Values below ``min(levels)`` and above ``max(levels)`` are mapped to the
|
|
under/over values of the `.Colormap`. Note that most colormaps do not have
|
|
dedicated colors for these by default, so that the over and under values
|
|
are the edge values of the colormap. You may want to set these values
|
|
explicitly using `.Colormap.set_under` and `.Colormap.set_over`.
|
|
|
|
.. note::
|
|
|
|
An existing `.TriContourSet` does not get notified if properties of its
|
|
colormap are changed. Therefore, an explicit call to
|
|
`.ContourSet.changed()` is needed after modifying the colormap. The
|
|
explicit call can be left out, if a colorbar is assigned to the
|
|
`.TriContourSet` because it internally calls `.ContourSet.changed()`.
|
|
|
|
xunits, yunits : registered units, optional
|
|
Override axis units by specifying an instance of a
|
|
:class:`matplotlib.units.ConversionInterface`.
|
|
|
|
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`.""" % _docstring.interpd.params)
|
|
|
|
|
|
@_docstring.Substitution(func='tricontour', type='lines')
|
|
@_docstring.dedent_interpd
|
|
def tricontour(ax, *args, **kwargs):
|
|
"""
|
|
%(_tricontour_doc)s
|
|
|
|
linewidths : float or array-like, default: :rc:`contour.linewidth`
|
|
The line width of the contour lines.
|
|
|
|
If a number, all levels will be plotted with this linewidth.
|
|
|
|
If a sequence, the levels in ascending order will be plotted with
|
|
the linewidths in the order specified.
|
|
|
|
If None, this falls back to :rc:`lines.linewidth`.
|
|
|
|
linestyles : {*None*, 'solid', 'dashed', 'dashdot', 'dotted'}, optional
|
|
If *linestyles* is *None*, the default is 'solid' unless the lines are
|
|
monochrome. In that case, negative contours will take their linestyle
|
|
from :rc:`contour.negative_linestyle` setting.
|
|
|
|
*linestyles* can also be an iterable of the above strings specifying a
|
|
set of linestyles to be used. If this iterable is shorter than the
|
|
number of contour levels it will be repeated as necessary.
|
|
"""
|
|
kwargs['filled'] = False
|
|
return TriContourSet(ax, *args, **kwargs)
|
|
|
|
|
|
@_docstring.Substitution(func='tricontourf', type='regions')
|
|
@_docstring.dedent_interpd
|
|
def tricontourf(ax, *args, **kwargs):
|
|
"""
|
|
%(_tricontour_doc)s
|
|
|
|
hatches : list[str], optional
|
|
A list of crosshatch patterns to use on the filled areas.
|
|
If None, no hatching will be added to the contour.
|
|
|
|
Notes
|
|
-----
|
|
`.tricontourf` fills intervals that are closed at the top; that is, for
|
|
boundaries *z1* and *z2*, the filled region is::
|
|
|
|
z1 < Z <= z2
|
|
|
|
except for the lowest interval, which is closed on both sides (i.e. it
|
|
includes the lowest value).
|
|
"""
|
|
kwargs['filled'] = True
|
|
return TriContourSet(ax, *args, **kwargs)
|