Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9e1f7b5

Browse files
committed
Does simplify paths when NaN/inf is present.
svn path=/trunk/matplotlib/; revision=6018
1 parent ec042a9 commit 9e1f7b5

5 files changed

Lines changed: 33 additions & 37 deletions

File tree

CHANGELOG

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
2008-08-11 Fix more bugs in NaN/inf handling. In particular, path simplification
2+
(which does not handle NaNs or infs) will be turned off automatically
3+
when infs or NaNs are present. Also masked arrays are now converted
4+
to arrays with NaNs for consistent handling of masks and NaNs
5+
- MGD and EF
6+
17
=================================================================
28
2008-08-03 Released 0.98.3 at svn r5947
39

lib/matplotlib/path.py

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ class Path(object):
5656
:class:`Path` objects, as an optimization, do not store a *codes*
5757
at all, but have a default one provided for them by
5858
:meth:`iter_segments`.
59+
60+
Note also that the vertices and codes arrays should be treated as
61+
immutable -- there are a number of optimizations and assumptions
62+
made up front in the constructor that will not change when the
63+
data changes.
5964
"""
6065

6166
# Path codes
@@ -84,46 +89,29 @@ def __init__(self, vertices, codes=None):
8489
dimension.
8590
8691
If *codes* is None, *vertices* will be treated as a series of
87-
line segments. If *vertices* contains masked values, the
88-
resulting path will be compressed, with ``MOVETO`` codes
89-
inserted in the correct places to jump over the masked
90-
regions.
92+
line segments.
93+
94+
If *vertices* contains masked values, they will be converted
95+
to NaNs which are then handled correctly by the Agg
96+
PathIterator and other consumers of path data, such as
97+
:meth:`iter_segments`.
9198
"""
9299
if ma.isMaskedArray(vertices):
93-
is_mask = True
94-
mask = ma.getmask(vertices)
100+
vertices = vertices.astype(np.float_).filled(np.nan)
95101
else:
96-
is_mask = False
97102
vertices = np.asarray(vertices, np.float_)
98-
mask = ma.nomask
99103

100104
if codes is not None:
101105
codes = np.asarray(codes, self.code_type)
102106
assert codes.ndim == 1
103107
assert len(codes) == len(vertices)
104108

105-
# The path being passed in may have masked values. However,
106-
# the backends (and any affine transformations in matplotlib
107-
# itself), are not expected to deal with masked arrays, so we
108-
# must remove them from the array (using compressed), and add
109-
# MOVETO commands to the codes array accordingly.
110-
if is_mask:
111-
if mask is not ma.nomask:
112-
mask1d = np.logical_or.reduce(mask, axis=1)
113-
gmask1d = np.invert(mask1d)
114-
if codes is None:
115-
codes = np.empty((len(vertices)), self.code_type)
116-
codes.fill(self.LINETO)
117-
codes[0] = self.MOVETO
118-
vertices = vertices[gmask1d].filled() # ndarray
119-
codes[np.roll(mask1d, 1)] = self.MOVETO
120-
codes = codes[gmask1d] # np.compress is much slower
121-
else:
122-
vertices = np.asarray(vertices, np.float_)
123-
124109
assert vertices.ndim == 2
125110
assert vertices.shape[1] == 2
126111

112+
self.should_simplify = (codes is None and
113+
np.all(np.isfinite(vertices)) and
114+
len(vertices) >= 128)
127115
self.codes = codes
128116
self.vertices = vertices
129117

src/_backend_agg.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ bool should_snap(Path& path, const agg::trans_affine& trans) {
387387
double x0, y0, x1, y1;
388388
unsigned code;
389389

390-
if (path.total_vertices() > 15)
390+
if (!path.should_simplify() || path.total_vertices() > 15)
391391
return false;
392392

393393
code = path.vertex(&x0, &y0);
@@ -420,11 +420,6 @@ bool should_snap(Path& path, const agg::trans_affine& trans) {
420420
return true;
421421
}
422422

423-
template<class Path>
424-
bool should_simplify(Path& path) {
425-
return !path.has_curves() && path.total_vertices() >= 128;
426-
}
427-
428423
Py::Object
429424
RendererAgg::copy_from_bbox(const Py::Tuple& args) {
430425
//copy region in bbox to buffer and return swig/agg buffer object
@@ -938,7 +933,7 @@ RendererAgg::draw_path(const Py::Tuple& args) {
938933
trans *= agg::trans_affine_scaling(1.0, -1.0);
939934
trans *= agg::trans_affine_translation(0.0, (double)height);
940935
bool snap = should_snap(path, trans);
941-
bool simplify = should_simplify(path) && !face.first;
936+
bool simplify = path.should_simplify() && !face.first;
942937

943938
transformed_path_t tpath(path, trans);
944939
simplify_t simplified(tpath, snap, simplify, width, height);
@@ -1236,6 +1231,10 @@ class QuadMeshGenerator {
12361231
inline unsigned total_vertices() {
12371232
return 5;
12381233
}
1234+
1235+
inline bool should_simplify() {
1236+
return false;
1237+
}
12391238
};
12401239

12411240
public:

src/_path.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,7 @@ Py::Object _path_module::convert_path_to_polygons(const Py::Tuple& args)
11201120
double width = Py::Float(args[2]);
11211121
double height = Py::Float(args[3]);
11221122

1123-
bool simplify = !path.has_curves() && width != 0.0 && height != 0.0;
1123+
bool simplify = path.should_simplify() && width != 0.0 && height != 0.0;
11241124

11251125
transformed_path_t tpath(path, trans);
11261126
simplify_t simplified(tpath, false, simplify, width, height);

src/agg_py_path_iterator.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ class PathIterator
1515
PyArrayObject* m_codes;
1616
size_t m_iterator;
1717
size_t m_total_vertices;
18+
bool m_should_simplify;
1819

1920
public:
2021
PathIterator(const Py::Object& path_obj) :
2122
m_vertices(NULL), m_codes(NULL), m_iterator(0)
2223
{
2324
Py::Object vertices_obj = path_obj.getAttr("vertices");
2425
Py::Object codes_obj = path_obj.getAttr("codes");
26+
Py::Object should_simplify_obj = path_obj.getAttr("should_simplify");
2527

2628
m_vertices = (PyArrayObject*)PyArray_FromObject
2729
(vertices_obj.ptr(), PyArray_DOUBLE, 2, 2);
@@ -38,6 +40,7 @@ class PathIterator
3840
throw Py::ValueError("Invalid codes array.");
3941
}
4042

43+
m_should_simplify = bool(Py::Int(should_simplify_obj));
4144
m_total_vertices = m_vertices->dimensions[0];
4245
}
4346

@@ -100,9 +103,9 @@ class PathIterator
100103
return m_total_vertices;
101104
}
102105

103-
inline bool has_curves()
106+
inline bool should_simplify()
104107
{
105-
return m_codes;
108+
return m_should_simplify;
106109
}
107110
};
108111

0 commit comments

Comments
 (0)