-
-
Notifications
You must be signed in to change notification settings - Fork 7.5k
/
_tripcolor.py
149 lines (131 loc) · 6.13 KB
/
_tripcolor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import numpy as np
from matplotlib import _api
from matplotlib.collections import PolyCollection, TriMesh
from matplotlib.tri._triangulation import Triangulation
def tripcolor(ax, *args, alpha=1.0, norm=None, cmap=None, vmin=None,
vmax=None, shading='flat', facecolors=None, **kwargs):
"""
Create a pseudocolor plot of an unstructured triangular grid.
Call signatures::
tripcolor(triangulation, c, *, ...)
tripcolor(x, y, c, *, [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.
It is possible to pass the triangles positionally, i.e.
``tripcolor(x, y, triangles, c, ...)``. However, this is discouraged.
For more clarity, pass *triangles* via keyword argument.
If neither of *triangulation* or *triangles* are given, the triangulation
is calculated on the fly. In this case, it does not make sense to provide
colors at the triangle faces via *c* or *facecolors* because there are
multiple possible triangulations for a group of points and you don't know
which triangles will be constructed.
Parameters
----------
triangulation : `.Triangulation`
An already created triangular grid.
x, y, triangles, mask
Parameters defining the triangular grid. See `.Triangulation`.
This is mutually exclusive with specifying *triangulation*.
c : array-like
The color values, either for the points or for the triangles. Which one
is automatically inferred from the length of *c*, i.e. does it match
the number of points or the number of triangles. If there are the same
number of points and triangles in the triangulation it is assumed that
color values are defined at points; to force the use of color values at
triangles use the keyword argument ``facecolors=c`` instead of just
``c``.
This parameter is position-only.
facecolors : array-like, optional
Can be used alternatively to *c* to specify colors at the triangle
faces. This parameter takes precedence over *c*.
shading : {'flat', 'gouraud'}, default: 'flat'
If 'flat' and the color values *c* are defined at points, the color
values used for each triangle are from the mean c of the triangle's
three points. If *shading* is 'gouraud' then color values must be
defined at points.
other_parameters
All other parameters are the same as for `~.Axes.pcolor`.
"""
_api.check_in_list(['flat', 'gouraud'], shading=shading)
tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args, **kwargs)
# Parse the color to be in one of (the other variable will be None):
# - facecolors: if specified at the triangle faces
# - point_colors: if specified at the points
if facecolors is not None:
if args:
_api.warn_external(
"Positional parameter c has no effect when the keyword "
"facecolors is given")
point_colors = None
if len(facecolors) != len(tri.triangles):
raise ValueError("The length of facecolors must match the number "
"of triangles")
else:
# Color from positional parameter c
if not args:
raise TypeError(
"tripcolor() missing 1 required positional argument: 'c'; or "
"1 required keyword-only argument: 'facecolors'")
elif len(args) > 1:
raise TypeError(f"Unexpected positional parameters: {args[1:]!r}")
c = np.asarray(args[0])
if len(c) == len(tri.x):
# having this before the len(tri.triangles) comparison gives
# precedence to nodes if there are as many nodes as triangles
point_colors = c
facecolors = None
elif len(c) == len(tri.triangles):
point_colors = None
facecolors = c
else:
raise ValueError('The length of c must match either the number '
'of points or the number of triangles')
# Handling of linewidths, shading, edgecolors and antialiased as
# in Axes.pcolor
linewidths = (0.25,)
if 'linewidth' in kwargs:
kwargs['linewidths'] = kwargs.pop('linewidth')
kwargs.setdefault('linewidths', linewidths)
edgecolors = 'none'
if 'edgecolor' in kwargs:
kwargs['edgecolors'] = kwargs.pop('edgecolor')
ec = kwargs.setdefault('edgecolors', edgecolors)
if 'antialiased' in kwargs:
kwargs['antialiaseds'] = kwargs.pop('antialiased')
if 'antialiaseds' not in kwargs and ec.lower() == "none":
kwargs['antialiaseds'] = False
if shading == 'gouraud':
if facecolors is not None:
raise ValueError(
"shading='gouraud' can only be used when the colors "
"are specified at the points, not at the faces.")
collection = TriMesh(tri, alpha=alpha, array=point_colors,
cmap=cmap, norm=norm, **kwargs)
else: # 'flat'
# Vertices of triangles.
maskedTris = tri.get_masked_triangles()
verts = np.stack((tri.x[maskedTris], tri.y[maskedTris]), axis=-1)
# Color values.
if facecolors is None:
# One color per triangle, the mean of the 3 vertex color values.
colors = point_colors[maskedTris].mean(axis=1)
elif tri.mask is not None:
# Remove color values of masked triangles.
colors = facecolors[~tri.mask]
else:
colors = facecolors
collection = PolyCollection(verts, alpha=alpha, array=colors,
cmap=cmap, norm=norm, **kwargs)
collection._scale_norm(norm, vmin, vmax)
ax.grid(False)
minx = tri.x.min()
maxx = tri.x.max()
miny = tri.y.min()
maxy = tri.y.max()
corners = (minx, miny), (maxx, maxy)
ax.update_datalim(corners)
ax.autoscale_view()
ax.add_collection(collection)
return collection