Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit df31677

Browse filesBrowse files
committed
Merge remote-tracking branch 'origin/v1.1.x'
Conflicts: lib/matplotlib/delaunay/triangulate.py
2 parents 67df281 + 97f7130 commit df31677
Copy full SHA for df31677

File tree

Expand file treeCollapse file tree

6 files changed

+179
-46
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+179
-46
lines changed

‎lib/matplotlib/delaunay/triangulate.py

Copy file name to clipboardExpand all lines: lib/matplotlib/delaunay/triangulate.py
+54-13Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,29 @@ class Triangulation(object):
6363
6464
hull -- list of point_id's giving the nodes which form the convex hull
6565
of the point set. This list is sorted in counter-clockwise order.
66+
67+
Duplicate points.
68+
If there are no duplicate points, Triangulation stores the specified
69+
x and y arrays and there is no difference between the client's and
70+
Triangulation's understanding of point indices used in edge_db,
71+
triangle_nodes and hull.
72+
73+
If there are duplicate points, they are removed from the stored
74+
self.x and self.y as the underlying delaunay code cannot deal with
75+
duplicates. len(self.x) is therefore equal to len(x) minus the
76+
number of duplicate points. Triangulation's edge_db, triangle_nodes
77+
and hull refer to point indices in self.x and self.y, for internal
78+
consistency within Triangulation and the corresponding Interpolator
79+
classes. Client code must take care to deal with this in one of
80+
two ways:
81+
82+
1. Ignore the x,y it specified in Triangulation's constructor and
83+
use triangulation.x and triangulation.y instead, as these are
84+
consistent with edge_db, triangle_nodes and hull.
85+
86+
2. If using the x,y the client specified then edge_db,
87+
triangle_nodes and hull should be passed through the function
88+
to_client_point_indices() first.
6689
"""
6790
def __init__(self, x, y):
6891
self.x = np.asarray(x, dtype=np.float64)
@@ -72,38 +95,46 @@ def __init__(self, x, y):
7295
raise ValueError("x,y must be equal-length 1-D arrays")
7396

7497
self.old_shape = self.x.shape
75-
j_unique = self._collapse_duplicate_points()
98+
duplicates = self._get_duplicate_point_indices()
7699

77-
if j_unique.shape != self.x.shape:
100+
if len(duplicates) > 0:
78101
warnings.warn(
79102
"Input data contains duplicate x,y points; some values are ignored.",
80103
DuplicatePointWarning,
81104
)
82-
self.j_unique = j_unique
105+
106+
# self.j_unique is the array of non-duplicate indices, in
107+
# increasing order.
108+
self.j_unique = np.delete(np.arange(len(self.x)), duplicates)
83109
self.x = self.x[self.j_unique]
84110
self.y = self.y[self.j_unique]
85111
else:
86112
self.j_unique = None
87113

114+
# If there are duplicate points, need a map of point indices used
115+
# by delaunay to those used by client. If there are no duplicate
116+
# points then the map is not needed. Either way, the map is
117+
# conveniently the same as j_unique, so share it.
118+
self._client_point_index_map = self.j_unique
88119

89120
self.circumcenters, self.edge_db, self.triangle_nodes, \
90121
self.triangle_neighbors = delaunay(self.x, self.y)
91122

92123
self.hull = self._compute_convex_hull()
93124

94-
def _collapse_duplicate_points(self):
95-
"""Generate index array that picks out unique x,y points.
96-
97-
This appears to be required by the underlying delaunay triangulation
98-
code.
125+
def _get_duplicate_point_indices(self):
126+
"""Return array of indices of x,y points that are duplicates of
127+
previous points. Indices are in no particular order.
99128
"""
100-
# Find the indices of the unique entries
129+
# Indices of sorted x,y points.
101130
j_sorted = np.lexsort(keys=(self.x, self.y))
102-
mask_unique = np.hstack([
103-
True,
104-
(np.diff(self.x[j_sorted]) != 0) | (np.diff(self.y[j_sorted]) != 0),
131+
mask_duplicates = np.hstack([
132+
False,
133+
(np.diff(self.x[j_sorted]) == 0) & (np.diff(self.y[j_sorted]) == 0),
105134
])
106-
return j_sorted[mask_unique]
135+
136+
# Array of duplicate point indices, in no particular order.
137+
return j_sorted[mask_duplicates]
107138

108139
def _compute_convex_hull(self):
109140
"""Extract the convex hull from the triangulation information.
@@ -131,6 +162,16 @@ def _compute_convex_hull(self):
131162

132163
return hull
133164

165+
def to_client_point_indices(self, array):
166+
"""Converts any array of point indices used within this class to
167+
refer to point indices within the (x,y) arrays specified in the
168+
constructor before duplicates were removed.
169+
"""
170+
if self._client_point_index_map is not None:
171+
return self._client_point_index_map[array]
172+
else:
173+
return array
174+
134175
def linear_interpolator(self, z, default_value=np.nan):
135176
"""Get an object which can interpolate within the convex hull by
136177
assigning a plane to each triangle.

‎lib/matplotlib/patches.py

Copy file name to clipboardExpand all lines: lib/matplotlib/patches.py
+2-4Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,13 +1030,14 @@ def __init__(self, figure, xytip, xybase, width=4, frac=0.1, headwidth=12, **kwa
10301030
%(Patch)s
10311031
10321032
"""
1033-
self.figure = figure
10341033
self.xytip = xytip
10351034
self.xybase = xybase
10361035
self.width = width
10371036
self.frac = frac
10381037
self.headwidth = headwidth
10391038
Patch.__init__(self, **kwargs)
1039+
# Set self.figure after Patch.__init__, since it sets self.figure to None
1040+
self.figure = figure
10401041

10411042
def get_path(self):
10421043
# Since this is dpi dependent, we need to recompute the path
@@ -4239,6 +4240,3 @@ def draw(self, renderer):
42394240
return
42404241

42414242
FancyArrowPatch.draw(self, renderer)
4242-
4243-
4244-
+96Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import numpy as np
2+
import matplotlib.tri as mtri
3+
import matplotlib.delaunay as mdel
4+
from nose.tools import assert_equal
5+
from numpy.testing import assert_array_equal, assert_array_almost_equal
6+
7+
def test_delaunay():
8+
# No duplicate points.
9+
x = [0,1,1,0]
10+
y = [0,0,1,1]
11+
npoints = 4
12+
ntriangles = 2
13+
nedges = 5
14+
15+
# Without duplicate points, mpl calls delaunay triangulation and
16+
# does not modify it.
17+
mpl_triang = mtri.Triangulation(x,y)
18+
del_triang = mdel.Triangulation(x,y)
19+
20+
# Points - floating point.
21+
assert_array_almost_equal(mpl_triang.x, x)
22+
assert_array_almost_equal(mpl_triang.x, del_triang.x)
23+
assert_array_almost_equal(mpl_triang.y, y)
24+
assert_array_almost_equal(mpl_triang.y, del_triang.y)
25+
26+
# Triangles - integers.
27+
assert_equal(len(mpl_triang.triangles), ntriangles)
28+
assert_equal(np.min(mpl_triang.triangles), 0)
29+
assert_equal(np.max(mpl_triang.triangles), npoints-1)
30+
assert_array_equal(mpl_triang.triangles, del_triang.triangle_nodes)
31+
32+
# Edges - integers.
33+
assert_equal(len(mpl_triang.edges), nedges)
34+
assert_equal(np.min(mpl_triang.edges), 0)
35+
assert_equal(np.max(mpl_triang.edges), npoints-1)
36+
assert_array_equal(mpl_triang.edges, del_triang.edge_db)
37+
38+
def test_delaunay_duplicate_points():
39+
# Issue 838.
40+
import warnings
41+
42+
# Index 2 is the same as index 0.
43+
x = [0,1,0,1,0]
44+
y = [0,0,0,1,1]
45+
duplicate_index = 2
46+
npoints = 4 # Number of non-duplicate points.
47+
nduplicates = 1
48+
ntriangles = 2
49+
nedges = 5
50+
51+
# With duplicate points, mpl calls delaunay triangulation but
52+
# modified returned arrays.
53+
warnings.simplefilter("ignore") # Ignore DuplicatePointWarning.
54+
mpl_triang = mtri.Triangulation(x,y)
55+
del_triang = mdel.Triangulation(x,y)
56+
warnings.resetwarnings()
57+
58+
# Points - floating point.
59+
assert_equal(len(mpl_triang.x), npoints + nduplicates)
60+
assert_equal(len(del_triang.x), npoints)
61+
assert_array_almost_equal(mpl_triang.x, x)
62+
assert_array_almost_equal(del_triang.x[:duplicate_index], x[:duplicate_index])
63+
assert_array_almost_equal(del_triang.x[duplicate_index:], x[duplicate_index+1:])
64+
65+
assert_equal(len(mpl_triang.y), npoints + nduplicates)
66+
assert_equal(len(del_triang.y), npoints)
67+
assert_array_almost_equal(mpl_triang.y, y)
68+
assert_array_almost_equal(del_triang.y[:duplicate_index], y[:duplicate_index])
69+
assert_array_almost_equal(del_triang.y[duplicate_index:], y[duplicate_index+1:])
70+
71+
# Triangles - integers.
72+
assert_equal(len(mpl_triang.triangles), ntriangles)
73+
assert_equal(np.min(mpl_triang.triangles), 0)
74+
assert_equal(np.max(mpl_triang.triangles), npoints-1 + nduplicates)
75+
assert_equal(len(del_triang.triangle_nodes), ntriangles)
76+
assert_equal(np.min(del_triang.triangle_nodes), 0)
77+
assert_equal(np.max(del_triang.triangle_nodes), npoints-1)
78+
# Convert mpl triangle point indices to delaunay's.
79+
converted_indices = np.where(mpl_triang.triangles > duplicate_index,
80+
mpl_triang.triangles - nduplicates,
81+
mpl_triang.triangles)
82+
assert_array_equal(del_triang.triangle_nodes, converted_indices)
83+
84+
# Edges - integers.
85+
assert_equal(len(mpl_triang.edges), nedges)
86+
assert_equal(np.min(mpl_triang.edges), 0)
87+
assert_equal(np.max(mpl_triang.edges), npoints-1 + nduplicates)
88+
assert_equal(len(del_triang.edge_db), nedges)
89+
assert_equal(np.min(del_triang.edge_db), 0)
90+
assert_equal(np.max(del_triang.edge_db), npoints-1)
91+
# Convert mpl edge point indices to delaunay's.
92+
converted_indices = np.where(mpl_triang.edges > duplicate_index,
93+
mpl_triang.edges - nduplicates,
94+
mpl_triang.edges)
95+
assert_array_equal(del_triang.edge_db, converted_indices)
96+

‎lib/matplotlib/tri/triangulation.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tri/triangulation.py
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,11 @@ def __init__(self, x, y, triangles=None, mask=None):
7070
if triangles is None:
7171
# No triangulation specified, so use matplotlib.delaunay.
7272
dt = delaunay.Triangulation(self.x, self.y)
73-
self.triangles = np.asarray(dt.triangle_nodes, dtype=np.int32)
73+
self.triangles = np.asarray(dt.to_client_point_indices(dt.triangle_nodes),
74+
dtype=np.int32)
7475
if mask is None:
75-
self._edges = np.asarray(dt.edge_db, dtype=np.int32)
76+
self._edges = np.asarray(dt.to_client_point_indices(dt.edge_db),
77+
dtype=np.int32)
7678
# Delaunay triangle_neighbors uses different edge indexing,
7779
# so convert.
7880
neighbors = np.asarray(dt.triangle_neighbors, dtype=np.int32)

‎src/_image.cpp

Copy file name to clipboardExpand all lines: src/_image.cpp
+1-2Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,8 +1066,7 @@ _image_module::fromarray2(const Py::Tuple& args)
10661066
int rgba = A->dimensions[2] == 4;
10671067
double r, g, b, alpha;
10681068
const size_t N = imo->rowsIn * imo->colsIn;
1069-
size_t i = 0;
1070-
while (i < N)
1069+
for (size_t i = 0; i < N; ++i)
10711070
{
10721071
r = *(double *)(A->data++);
10731072
g = *(double *)(A->data++);

‎ttconv/pprdrv_tt2.cpp

Copy file name to clipboardExpand all lines: ttconv/pprdrv_tt2.cpp
+22-25Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,9 @@ void GlyphToType3::PSConvert(TTStreamWriter& stream)
203203
/* Step thru the coutours. */
204204
/* I believe that a contour is a detatched */
205205
/* set of curves and lines. */
206-
i=j=k=0;
207-
while ( i < num_ctr )
206+
for(i = j = k = 0;
207+
i != NOMOREOUTCTR && i < num_ctr;
208+
k = nextinctr(i, k), (k == NOMOREINCTR && (i = k = nextoutctr(i))))
208209
{
209210
// A TrueType contour consists of on-path and off-path points.
210211
// Two consecutive on-path points are to be joined with a
@@ -224,6 +225,11 @@ void GlyphToType3::PSConvert(TTStreamWriter& stream)
224225
}
225226
}
226227

228+
if (points.size() == 0) {
229+
// Don't try to access the last element of an empty list
230+
continue;
231+
}
232+
227233
// For any two consecutive off-path points, insert the implied
228234
// on-path point.
229235
FlaggedPoint prev = points.back();
@@ -254,44 +260,35 @@ void GlyphToType3::PSConvert(TTStreamWriter& stream)
254260
points.push_back(points.front());
255261
}
256262

257-
// For output, a vector is more convenient than a list.
258-
std::vector<FlaggedPoint> points_v(points.begin(), points.end());
259263
// The first point
260264
stack(stream, 3);
261-
PSMoveto(stream, points_v.front().x, points_v.front().y);
265+
PSMoveto(stream, points.front().x, points.front().y);
262266

263267
// Step through the remaining points
264-
for (size_t p = 1; p < points_v.size(); )
268+
std::list<FlaggedPoint>::const_iterator it = points.begin();
269+
for (it++; it != points.end(); /* incremented inside */)
265270
{
266-
const FlaggedPoint& point = points_v.at(p);
271+
const FlaggedPoint& point = *it;
267272
if (point.flag == ON_PATH)
268273
{
269274
stack(stream, 3);
270275
PSLineto(stream, point.x, point.y);
271-
p++;
276+
it++;
272277
} else {
273-
assert(points_v.at(p-1).flag == ON_PATH);
274-
assert(points_v.at(p+1).flag == ON_PATH);
278+
std::list<FlaggedPoint>::const_iterator prev = it, next = it;
279+
prev--;
280+
next++;
281+
assert(prev->flag == ON_PATH);
282+
assert(next->flag == ON_PATH);
275283
stack(stream, 7);
276284
PSCurveto(stream,
277-
points_v.at(p-1).x, points_v.at(p-1).y,
285+
prev->x, prev->y,
278286
point.x, point.y,
279-
points_v.at(p+1).x, points_v.at(p+1).y);
280-
p += 2;
287+
next->x, next->y);
288+
it++;
289+
it++;
281290
}
282291
}
283-
284-
k=nextinctr(i,k);
285-
286-
if (k==NOMOREINCTR)
287-
{
288-
i=k=nextoutctr(i);
289-
}
290-
291-
if (i==NOMOREOUTCTR)
292-
{
293-
break;
294-
}
295292
}
296293

297294
/* Now, we can fill the whole thing. */

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.