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

Skip to content

Commit 5218f47

Browse files
committed
Added the cleared method to Path, and updated the path module's documentation.
1 parent 99d4e40 commit 5218f47

File tree

3 files changed

+167
-91
lines changed

3 files changed

+167
-91
lines changed

doc/api/api_changes.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ Changes in 1.3.x
104104
existing text objects. This brings their behavior in line with most
105105
other rcParams.
106106

107+
* To support XKCD style plots, the :func:`matplotlib.path.cleanup_path`
108+
method's signature was updated to require a sketch argument. Users of
109+
:func:`matplotlib.path.cleanup_path` are encouraged to use the new
110+
:meth:`~matplotlib.path.Path.cleaned` Path method.
111+
112+
* The list at ``Path.NUM_VERTICES`` was replaced by a dictionary mapping
113+
Path codes to the number of expected vertices at
114+
:attr:`~matplotlib.path.Path.NUM_VERTICES_FOR_CODE`.
115+
107116
* Fixed a bug in setting the position for the right/top spine with data
108117
position type. Previously, it would draw the right or top spine at
109118
+1 data offset.

lib/matplotlib/cm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,9 @@ def __init__(self, norm=None, cmap=None):
189189
norm = colors.Normalize()
190190

191191
self._A = None;
192-
#; The Normalization instance of this ScalarMappable.
192+
#: The Normalization instance of this ScalarMappable.
193193
self.norm = norm
194-
#; The Colormap instance of this ScalarMappable.
194+
#: The Colormap instance of this ScalarMappable.
195195
self.cmap = get_cmap(cmap)
196196
self.colorbar = None
197197
self.update_dict = {'array': False}

lib/matplotlib/path.py

Lines changed: 156 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
"""
2-
Contains a class for managing paths (polylines).
2+
A module for dealing with the polylines used throughout matplotlib.
3+
4+
The primary class for polyline handling in matplotlib is :class:`Path`.
5+
Almost all vector drawing makes use of Paths somewhere in the drawing
6+
pipeline.
7+
8+
Whilst a :class:`Path` instance itself cannot be drawn, there exists
9+
:class:`~matplotlib.artist.Artist` subclasses which can be used for
10+
convenient Path visualisation - the two most frequently used of these are
11+
:class:`~matplotlib.patches.PathPatch` and
12+
:class:`~matplotlib.collections.PathCollection`.
313
"""
414

515
from __future__ import print_function
@@ -53,9 +63,9 @@ class Path(object):
5363
5464
Users of Path objects should not access the vertices and codes
5565
arrays directly. Instead, they should use :meth:`iter_segments`
56-
to get the vertex/code pairs. This is important, since many
57-
:class:`Path` objects, as an optimization, do not store a *codes*
58-
at all, but have a default one provided for them by
66+
or :meth:`cleaned` to get the vertex/code pairs. This is important,
67+
since many :class:`Path` objects, as an optimization, do not store a
68+
*codes* at all, but have a default one provided for them by
5969
:meth:`iter_segments`.
6070
6171
.. note::
@@ -73,12 +83,16 @@ class Path(object):
7383
LINETO = 2 # 1 vertex
7484
CURVE3 = 3 # 2 vertices
7585
CURVE4 = 4 # 3 vertices
76-
CLOSEPOLY = 0x4f # 1 vertex
86+
CLOSEPOLY = 79 # 1 vertex
7787

78-
NUM_VERTICES = [1, 1, 1, 2,
79-
3, 1, 1, 1,
80-
1, 1, 1, 1,
81-
1, 1, 1, 1]
88+
#: A dictionary mapping Path codes to the number of vertices that the
89+
#: code expects.
90+
NUM_VERTICES_FOR_CODE = {STOP: 1,
91+
MOVETO: 1,
92+
LINETO: 1,
93+
CURVE3: 2,
94+
CURVE4: 3,
95+
CLOSEPOLY: 1}
8296

8397
code_type = np.uint8
8498

@@ -87,29 +101,31 @@ def __init__(self, vertices, codes=None, _interpolation_steps=1, closed=False,
87101
"""
88102
Create a new path with the given vertices and codes.
89103
90-
*vertices* is an Nx2 numpy float array, masked array or Python
91-
sequence.
92-
93-
*codes* is an N-length numpy array or Python sequence of type
94-
:attr:`matplotlib.path.Path.code_type`.
95-
96-
These two arrays must have the same length in the first
97-
dimension.
98-
99-
If *codes* is None, *vertices* will be treated as a series of
100-
line segments.
101-
102-
If *vertices* contains masked values, they will be converted
103-
to NaNs which are then handled correctly by the Agg
104-
PathIterator and other consumers of path data, such as
105-
:meth:`iter_segments`.
106-
107-
*interpolation_steps* is used as a hint to certain projections,
108-
such as Polar, that this path should be linearly interpolated
109-
immediately before drawing. This attribute is primarily an
110-
implementation detail and is not intended for public use.
111-
112-
*readonly*, when True, makes the path immutable.
104+
Parameters
105+
----------
106+
vertices : array_like
107+
The ``(n, 2)`` float array, masked array or sequence of pairs
108+
representing the vertices of the path.
109+
110+
If *vertices* contains masked values, they will be converted
111+
to NaNs which are then handled correctly by the Agg
112+
PathIterator and other consumers of path data, such as
113+
:meth:`iter_segments`.
114+
codes : {None, array_like}, optional
115+
n-length array integers representing the codes of the path.
116+
If not None, codes must be the same length as vertices.
117+
If None, *vertices* will be treated as a series of line segments.
118+
_interpolation_steps : int, optional
119+
Used as a hint to certain projections, such as Polar, that this
120+
path should be linearly interpolated immediately before drawing.
121+
This attribute is primarily an implementation detail and is not
122+
intended for public use.
123+
closed : bool, optional
124+
If *codes* is None and closed is True, vertices will be treated as
125+
line segments of a closed polygon.
126+
readonly : bool, optional
127+
Makes the path behave in an immutable way and sets the vertices
128+
and codes as read-only arrays.
113129
"""
114130
if ma.isMaskedArray(vertices):
115131
vertices = vertices.astype(np.float_).filled(np.nan)
@@ -144,6 +160,37 @@ def __init__(self, vertices, codes=None, _interpolation_steps=1, closed=False,
144160
else:
145161
self._readonly = False
146162

163+
@classmethod
164+
def _fast_from_codes_and_verts(cls, verts, codes, internals=None):
165+
"""
166+
Creates a Path instance without the expense of calling the constructor
167+
168+
Use this method at your own risk...
169+
170+
Parameters
171+
----------
172+
verts : numpy array
173+
codes : numpy array (may not be None)
174+
internals : dict or None
175+
The attributes that the resulting path should have.
176+
177+
"""
178+
internals = internals or {}
179+
pth = cls.__new__(cls)
180+
pth._vertices = verts
181+
pth._codes = codes
182+
pth._readonly = internals.pop('_readonly', False)
183+
pth._should_simplify = internals.pop('_should_simplify', True)
184+
pth._simplify_threshold = internals.pop('_simplify_threshold',
185+
rcParams['path.simplify_threshold'])
186+
pth._has_nonfinite = internals.pop('_has_nonfinite', False)
187+
pth._interpolation_steps = internals.pop('_interpolation_steps', 1)
188+
if internals:
189+
raise ValueError('Unexpected internals provided to '
190+
'_fast_from_codes_and_verts: '
191+
'{0}'.format('\n *'.join(internals.keys())))
192+
return pth
193+
147194
def _update_values(self):
148195
self._should_simplify = (
149196
rcParams['path.simplify'] and
@@ -246,7 +293,7 @@ def __deepcopy__(self):
246293
@classmethod
247294
def make_compound_path_from_polys(cls, XY):
248295
"""
249-
(static method) Make a compound path object to draw a number
296+
Make a compound path object to draw a number
250297
of polygons with equal numbers of sides XY is a (numpolys x
251298
numsides x 2) numpy array of vertices. Return object is a
252299
:class:`Path`
@@ -273,10 +320,7 @@ def make_compound_path_from_polys(cls, XY):
273320

274321
@classmethod
275322
def make_compound_path(cls, *args):
276-
"""
277-
(staticmethod) Make a compound path from a list of Path
278-
objects.
279-
"""
323+
"""Make a compound path from a list of Path objects."""
280324
lengths = [len(x) for x in args]
281325
total_length = sum(lengths)
282326

@@ -313,64 +357,87 @@ def iter_segments(self, transform=None, remove_nans=True, clip=None,
313357
Additionally, this method can provide a number of standard
314358
cleanups and conversions to the path.
315359
316-
*transform*: if not None, the given affine transformation will
317-
be applied to the path.
318-
319-
*remove_nans*: if True, will remove all NaNs from the path and
320-
insert MOVETO commands to skip over them.
321-
322-
*clip*: if not None, must be a four-tuple (x1, y1, x2, y2)
323-
defining a rectangle in which to clip the path.
324-
325-
*snap*: if None, auto-snap to pixels, to reduce
326-
fuzziness of rectilinear lines. If True, force snapping, and
327-
if False, don't snap.
328-
329-
*stroke_width*: the width of the stroke being drawn. Needed
330-
as a hint for the snapping algorithm.
331-
332-
*simplify*: if True, perform simplification, to remove
333-
vertices that do not affect the appearance of the path. If
334-
False, perform no simplification. If None, use the
335-
should_simplify member variable.
336-
337-
*curves*: If True, curve segments will be returned as curve
338-
segments. If False, all curves will be converted to line
339-
segments.
340-
341-
*sketch*: If not None, must be a 3-tuple of the form
342-
(scale, length, randomness), representing the sketch
343-
parameters.
344-
"""
345-
vertices = self.vertices
346-
if not len(vertices):
360+
Parameters
361+
----------
362+
transform : None or :class:`~matplotlib.transforms.Transform` instance
363+
If not None, the given affine transformation will
364+
be applied to the path.
365+
remove_nans : {False, True}, optional
366+
If True, will remove all NaNs from the path and
367+
insert MOVETO commands to skip over them.
368+
clip : None or sequence, optional
369+
If not None, must be a four-tuple (x1, y1, x2, y2)
370+
defining a rectangle in which to clip the path.
371+
snap : None or bool, optional
372+
If None, auto-snap to pixels, to reduce
373+
fuzziness of rectilinear lines. If True, force snapping, and
374+
if False, don't snap.
375+
stroke_width : float, optional
376+
The width of the stroke being drawn. Needed
377+
as a hint for the snapping algorithm.
378+
simplify : None or bool, optional
379+
If True, perform simplification, to remove
380+
vertices that do not affect the appearance of the path. If
381+
False, perform no simplification. If None, use the
382+
should_simplify member variable.
383+
curves : {True, False}, optional
384+
If True, curve segments will be returned as curve
385+
segments. If False, all curves will be converted to line
386+
segments.
387+
sketch : None or sequence, optional
388+
If not None, must be a 3-tuple of the form
389+
(scale, length, randomness), representing the sketch
390+
parameters.
391+
"""
392+
if not len(self):
347393
return
348394

349-
codes = self.codes
350-
351-
NUM_VERTICES = self.NUM_VERTICES
352-
MOVETO = self.MOVETO
353-
LINETO = self.LINETO
354-
CLOSEPOLY = self.CLOSEPOLY
355-
STOP = self.STOP
395+
cleaned = self.cleaned(transform=transform,
396+
remove_nans=remove_nans, clip=clip,
397+
snap=snap, stroke_width=stroke_width,
398+
simplify=simplify, curves=curves,
399+
sketch=sketch)
400+
vertices = cleaned.vertices
401+
codes = cleaned.codes
402+
len_vertices = vertices.shape[0]
356403

357-
vertices, codes = _path.cleanup_path(
358-
self, transform, remove_nans, clip,
359-
snap, stroke_width, simplify, curves,
360-
sketch)
361-
len_vertices = len(vertices)
404+
# Cache these object lookups for performance in the loop.
405+
NUM_VERTICES_FOR_CODE = self.NUM_VERTICES_FOR_CODE
406+
STOP = self.STOP
362407

363408
i = 0
364409
while i < len_vertices:
365410
code = codes[i]
366411
if code == STOP:
367412
return
368413
else:
369-
num_vertices = NUM_VERTICES[int(code) & 0xf]
414+
num_vertices = NUM_VERTICES_FOR_CODE[code]
370415
curr_vertices = vertices[i:i+num_vertices].flatten()
371416
yield curr_vertices, code
372417
i += num_vertices
373418

419+
def cleaned(self, transform=None, remove_nans=False, clip=None,
420+
quantize=False, simplify=False, curves=False,
421+
stroke_width=1.0, snap=False, sketch=None):
422+
"""
423+
Cleans up the path according to the parameters returning a new
424+
Path instance.
425+
426+
.. seealso::
427+
428+
See :meth:`iter_segments` for details of the keyword arguments.
429+
430+
Returns
431+
-------
432+
Path instance with cleaned up vertices and codes.
433+
434+
"""
435+
vertices, codes = cleanup_path(self, transform,
436+
remove_nans, clip,
437+
snap, stroke_width,
438+
simplify, curves, sketch)
439+
return Path._fast_from_codes_and_verts(vertices, codes)
440+
374441
def transformed(self, transform):
375442
"""
376443
Return a transformed copy of the path.
@@ -519,7 +586,7 @@ def to_polygons(self, transform=None, width=0, height=0):
519586
@classmethod
520587
def unit_rectangle(cls):
521588
"""
522-
(staticmethod) Returns a :class:`Path` of the unit rectangle
589+
Return a :class:`Path` instance of the unit rectangle
523590
from (0, 0) to (1, 1).
524591
"""
525592
if cls._unit_rectangle is None:
@@ -534,7 +601,7 @@ def unit_rectangle(cls):
534601
@classmethod
535602
def unit_regular_polygon(cls, numVertices):
536603
"""
537-
(staticmethod) Returns a :class:`Path` for a unit regular
604+
Return a :class:`Path` instance for a unit regular
538605
polygon with the given *numVertices* and radius of 1.0,
539606
centered at (0, 0).
540607
"""
@@ -563,7 +630,7 @@ def unit_regular_polygon(cls, numVertices):
563630
@classmethod
564631
def unit_regular_star(cls, numVertices, innerCircle=0.5):
565632
"""
566-
(staticmethod) Returns a :class:`Path` for a unit regular star
633+
Return a :class:`Path` for a unit regular star
567634
with the given numVertices and radius of 1.0, centered at (0,
568635
0).
569636
"""
@@ -592,7 +659,7 @@ def unit_regular_star(cls, numVertices, innerCircle=0.5):
592659
@classmethod
593660
def unit_regular_asterisk(cls, numVertices):
594661
"""
595-
(staticmethod) Returns a :class:`Path` for a unit regular
662+
Return a :class:`Path` for a unit regular
596663
asterisk with the given numVertices and radius of 1.0,
597664
centered at (0, 0).
598665
"""
@@ -603,7 +670,7 @@ def unit_regular_asterisk(cls, numVertices):
603670
@classmethod
604671
def unit_circle(cls):
605672
"""
606-
(staticmethod) Returns a :class:`Path` of the unit circle.
673+
Return a :class:`Path` of the unit circle.
607674
The circle is approximated using cubic Bezier curves. This
608675
uses 8 splines around the circle using the approach presented
609676
here:
@@ -666,7 +733,7 @@ def unit_circle(cls):
666733
@classmethod
667734
def unit_circle_righthalf(cls):
668735
"""
669-
(staticmethod) Returns a :class:`Path` of the right half
736+
Return a :class:`Path` of the right half
670737
of a unit circle. The circle is approximated using cubic Bezier
671738
curves. This uses 4 splines around the circle using the approach
672739
presented here:
@@ -712,7 +779,7 @@ def unit_circle_righthalf(cls):
712779
@classmethod
713780
def arc(cls, theta1, theta2, n=None, is_wedge=False):
714781
"""
715-
(staticmethod) Returns an arc on the unit circle from angle
782+
Return an arc on the unit circle from angle
716783
*theta1* to angle *theta2* (in degrees).
717784
718785
If *n* is provided, it is the number of spline segments to make.
@@ -790,7 +857,7 @@ def arc(cls, theta1, theta2, n=None, is_wedge=False):
790857
@classmethod
791858
def wedge(cls, theta1, theta2, n=None):
792859
"""
793-
(staticmethod) Returns a wedge of the unit circle from angle
860+
Return a wedge of the unit circle from angle
794861
*theta1* to angle *theta2* (in degrees).
795862
796863
If *n* is provided, it is the number of spline segments to make.

0 commit comments

Comments
 (0)