Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/matplotlib/tri/triangulation.py : 13%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import numpy as np
4class Triangulation:
5 """
6 An unstructured triangular grid consisting of npoints points and
7 ntri triangles. The triangles can either be specified by the user
8 or automatically generated using a Delaunay triangulation.
10 Parameters
11 ----------
12 x, y : array-like of shape (npoints)
13 Coordinates of grid points.
14 triangles : integer array-like of shape (ntri, 3), optional
15 For each triangle, the indices of the three points that make
16 up the triangle, ordered in an anticlockwise manner. If not
17 specified, the Delaunay triangulation is calculated.
18 mask : boolean array-like of shape (ntri), optional
19 Which triangles are masked out.
21 Attributes
22 ----------
23 edges : int array of shape (nedges, 2)
24 See `~.Triangulation.edges`
25 neighbors : int array of shape (ntri, 3)
26 See `~.Triangulation.neighbors`
27 mask : bool array of shape (ntri, 3)
28 Masked out triangles.
29 is_delaunay : bool
30 Whether the Triangulation is a calculated Delaunay
31 triangulation (where *triangles* was not specified) or not.
33 Notes
34 -----
35 For a Triangulation to be valid it must not have duplicate points,
36 triangles formed from colinear points, or overlapping triangles.
37 """
38 def __init__(self, x, y, triangles=None, mask=None):
39 from matplotlib import _qhull
41 self.x = np.asarray(x, dtype=np.float64)
42 self.y = np.asarray(y, dtype=np.float64)
43 if self.x.shape != self.y.shape or self.x.ndim != 1:
44 raise ValueError("x and y must be equal-length 1-D arrays")
46 self.mask = None
47 self._edges = None
48 self._neighbors = None
49 self.is_delaunay = False
51 if triangles is None:
52 # No triangulation specified, so use matplotlib._qhull to obtain
53 # Delaunay triangulation.
54 self.triangles, self._neighbors = _qhull.delaunay(x, y)
55 self.is_delaunay = True
56 else:
57 # Triangulation specified. Copy, since we may correct triangle
58 # orientation.
59 self.triangles = np.array(triangles, dtype=np.int32, order='C')
60 if self.triangles.ndim != 2 or self.triangles.shape[1] != 3:
61 raise ValueError('triangles must be a (?,3) array')
62 if self.triangles.max() >= len(self.x):
63 raise ValueError('triangles max element is out of bounds')
64 if self.triangles.min() < 0:
65 raise ValueError('triangles min element is out of bounds')
67 if mask is not None:
68 self.mask = np.asarray(mask, dtype=bool)
69 if self.mask.shape != (self.triangles.shape[0],):
70 raise ValueError('mask array must have same length as '
71 'triangles array')
73 # Underlying C++ object is not created until first needed.
74 self._cpp_triangulation = None
76 # Default TriFinder not created until needed.
77 self._trifinder = None
79 def calculate_plane_coefficients(self, z):
80 """
81 Calculate plane equation coefficients for all unmasked triangles from
82 the point (x, y) coordinates and specified z-array of shape (npoints).
83 The returned array has shape (npoints, 3) and allows z-value at (x, y)
84 position in triangle tri to be calculated using
85 ``z = array[tri, 0] * x + array[tri, 1] * y + array[tri, 2]``.
86 """
87 return self.get_cpp_triangulation().calculate_plane_coefficients(z)
89 @property
90 def edges(self):
91 """
92 Return integer array of shape (nedges, 2) containing all edges of
93 non-masked triangles.
95 Each row defines an edge by it's start point index and end point
96 index. Each edge appears only once, i.e. for an edge between points
97 *i* and *j*, there will only be either *(i, j)* or *(j, i)*.
98 """
99 if self._edges is None:
100 self._edges = self.get_cpp_triangulation().get_edges()
101 return self._edges
103 def get_cpp_triangulation(self):
104 """
105 Return the underlying C++ Triangulation object, creating it
106 if necessary.
107 """
108 from matplotlib import _tri
109 if self._cpp_triangulation is None:
110 self._cpp_triangulation = _tri.Triangulation(
111 self.x, self.y, self.triangles, self.mask, self._edges,
112 self._neighbors, not self.is_delaunay)
113 return self._cpp_triangulation
115 def get_masked_triangles(self):
116 """
117 Return an array of triangles that are not masked.
118 """
119 if self.mask is not None:
120 return self.triangles[~self.mask]
121 else:
122 return self.triangles
124 @staticmethod
125 def get_from_args_and_kwargs(*args, **kwargs):
126 """
127 Return a Triangulation object from the args and kwargs, and
128 the remaining args and kwargs with the consumed values removed.
130 There are two alternatives: either the first argument is a
131 Triangulation object, in which case it is returned, or the args
132 and kwargs are sufficient to create a new Triangulation to
133 return. In the latter case, see Triangulation.__init__ for
134 the possible args and kwargs.
135 """
136 if isinstance(args[0], Triangulation):
137 triangulation, *args = args
138 else:
139 x, y, *args = args
141 # Check triangles in kwargs then args.
142 triangles = kwargs.pop('triangles', None)
143 from_args = False
144 if triangles is None and args:
145 triangles = args[0]
146 from_args = True
148 if triangles is not None:
149 try:
150 triangles = np.asarray(triangles, dtype=np.int32)
151 except ValueError:
152 triangles = None
154 if triangles is not None and (triangles.ndim != 2 or
155 triangles.shape[1] != 3):
156 triangles = None
158 if triangles is not None and from_args:
159 args = args[1:] # Consumed first item in args.
161 # Check for mask in kwargs.
162 mask = kwargs.pop('mask', None)
164 triangulation = Triangulation(x, y, triangles, mask)
165 return triangulation, args, kwargs
167 def get_trifinder(self):
168 """
169 Return the default :class:`matplotlib.tri.TriFinder` of this
170 triangulation, creating it if necessary. This allows the same
171 TriFinder object to be easily shared.
172 """
173 if self._trifinder is None:
174 # Default TriFinder class.
175 from matplotlib.tri.trifinder import TrapezoidMapTriFinder
176 self._trifinder = TrapezoidMapTriFinder(self)
177 return self._trifinder
179 @property
180 def neighbors(self):
181 """
182 Return integer array of shape (ntri, 3) containing neighbor triangles.
184 For each triangle, the indices of the three triangles that
185 share the same edges, or -1 if there is no such neighboring
186 triangle. ``neighbors[i, j]`` is the triangle that is the neighbor
187 to the edge from point index ``triangles[i,j]`` to point index
188 ``triangles[i,(j+1)%3]``.
189 """
190 if self._neighbors is None:
191 self._neighbors = self.get_cpp_triangulation().get_neighbors()
192 return self._neighbors
194 def set_mask(self, mask):
195 """
196 Set or clear the mask array. This is either None, or a boolean
197 array of shape (ntri).
198 """
199 if mask is None:
200 self.mask = None
201 else:
202 self.mask = np.asarray(mask, dtype=bool)
203 if self.mask.shape != (self.triangles.shape[0],):
204 raise ValueError('mask array must have same length as '
205 'triangles array')
207 # Set mask in C++ Triangulation.
208 if self._cpp_triangulation is not None:
209 self._cpp_triangulation.set_mask(self.mask)
211 # Clear derived fields so they are recalculated when needed.
212 self._edges = None
213 self._neighbors = None
215 # Recalculate TriFinder if it exists.
216 if self._trifinder is not None:
217 self._trifinder._initialize()