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

Skip to content

Commit d92d2ad

Browse files
committed
Merge pull request #3955 from tacaswell/quiver_pivot_validate
API : tighten validation on pivot in Quiver
2 parents f0bb0ab + e6419cf commit d92d2ad

File tree

2 files changed

+59
-31
lines changed

2 files changed

+59
-31
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Tighted input validation on 'pivot' kwarg to quiver
2+
```````````````````````````````````````````````````
3+
4+
Tightened validation so that only {'tip', 'tail', 'mid', and 'middle'}
5+
(but any capitalization) are valid values for the 'pivot' kwarg in
6+
the `Quiver.__init__` (and hence `Axes.quiver` and
7+
`plt.quiver` which both fully delegate to `Quiver`). Previously any
8+
input matching 'mid.*' would be interpreted as 'middle', 'tip.*' as
9+
'tip' and any string not matching one of those patterns as 'tail'.
10+
11+
The value of `Quiver.pivot` is normalized to be in the set {'tip',
12+
'tail', 'middle'} in `Quiver.__init__`.

lib/matplotlib/quiver.py

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@
136136
is less than this, plot a dot (hexagon) of this diameter instead.
137137
Default is 1.
138138
139-
*pivot*: [ 'tail' | 'middle' | 'tip' ]
139+
*pivot*: [ 'tail' | 'mid' | 'middle' | 'tip' ]
140140
The part of the arrow that is at the grid point; the arrow rotates
141141
about this point, hence the name *pivot*.
142142
@@ -247,8 +247,9 @@ def on_dpi_change(fig):
247247
if self_weakref is not None:
248248
self_weakref.labelsep = (self_weakref._labelsep_inches*fig.dpi)
249249
self_weakref._initialized = False # simple brute force update
250-
# works because _init is called
251-
# at the start of draw.
250+
# works because _init is
251+
# called at the start of
252+
# draw.
252253

253254
self._cid = Q.ax.figure.callbacks.connect('dpi_changed',
254255
on_dpi_change)
@@ -258,7 +259,7 @@ def on_dpi_change(fig):
258259
self.fontproperties = kw.pop('fontproperties', dict())
259260
self.kw = kw
260261
_fp = self.fontproperties
261-
#boxprops = dict(facecolor='red')
262+
# boxprops = dict(facecolor='red')
262263
self.text = mtext.Text(
263264
text=label, # bbox=boxprops,
264265
horizontalalignment=self.halign[self.labelpos],
@@ -405,6 +406,8 @@ class Quiver(mcollections.PolyCollection):
405406
in the draw() method.
406407
"""
407408

409+
_PIVOT_VALS = ('tail', 'mid', 'middle', 'tip')
410+
408411
@docstring.Substitution(_quiver_doc)
409412
def __init__(self, ax, *args, **kw):
410413
"""
@@ -430,7 +433,18 @@ def __init__(self, ax, *args, **kw):
430433
self.angles = kw.pop('angles', 'uv')
431434
self.width = kw.pop('width', None)
432435
self.color = kw.pop('color', 'k')
433-
self.pivot = kw.pop('pivot', 'tail')
436+
437+
pivot = kw.pop('pivot', 'tail').lower()
438+
# validate pivot
439+
if pivot not in self._PIVOT_VALS:
440+
raise ValueError(
441+
'pivot must be one of {keys}, you passed {inp}'.format(
442+
keys=self._PIVOT_VALS, inp=pivot))
443+
# normalize to 'middle'
444+
if pivot == 'mid':
445+
pivot = 'middle'
446+
self.pivot = pivot
447+
434448
self.transform = kw.pop('transform', ax.transData)
435449
kw.setdefault('facecolors', self.color)
436450
kw.setdefault('linewidths', (0,))
@@ -452,10 +466,11 @@ def on_dpi_change(fig):
452466
self_weakref = weak_self()
453467
if self_weakref is not None:
454468
self_weakref._new_UV = True # vertices depend on width, span
455-
# which in turn depend on dpi
469+
# which in turn depend on dpi
456470
self_weakref._initialized = False # simple brute force update
457-
# works because _init is called
458-
# at the start of draw.
471+
# works because _init is
472+
# called at the start of
473+
# draw.
459474

460475
self._cid = self.ax.figure.callbacks.connect('dpi_changed',
461476
on_dpi_change)
@@ -654,7 +669,7 @@ def _h_arrows(self, length):
654669
length = length.reshape(N, 1)
655670
# This number is chosen based on when pixel values overflow in Agg
656671
# causing rendering errors
657-
#length = np.minimum(length, 2 ** 16)
672+
# length = np.minimum(length, 2 ** 16)
658673
np.clip(length, 0, 2 ** 16, out=length)
659674
# x, y: normal horizontal arrow
660675
x = np.array([0, -self.headaxislength,
@@ -681,9 +696,9 @@ def _h_arrows(self, length):
681696
# Now select X0, Y0 if short, otherwise X, Y
682697
cbook._putmask(X, short, X0)
683698
cbook._putmask(Y, short, Y0)
684-
if self.pivot[:3] == 'mid':
699+
if self.pivot == 'middle':
685700
X -= 0.5 * X[:, 3, np.newaxis]
686-
elif self.pivot[:3] == 'tip':
701+
elif self.pivot == 'tip':
687702
X = X - X[:, 3, np.newaxis] # numpy bug? using -= does not
688703
# work here unless we multiply
689704
# by a float first, as with 'mid'.
@@ -857,9 +872,9 @@ class Barbs(mcollections.PolyCollection):
857872
From there :meth:`_make_barbs` is used to find the vertices of the
858873
polygon to represent the barb based on this information.
859874
'''
860-
#This may be an abuse of polygons here to render what is essentially maybe
861-
#1 triangle and a series of lines. It works fine as far as I can tell
862-
#however.
875+
# This may be an abuse of polygons here to render what is essentially maybe
876+
# 1 triangle and a series of lines. It works fine as far as I can tell
877+
# however.
863878
@docstring.interpd
864879
def __init__(self, ax, *args, **kw):
865880
"""
@@ -879,30 +894,31 @@ def __init__(self, ax, *args, **kw):
879894
self.flip = kw.pop('flip_barb', False)
880895
transform = kw.pop('transform', ax.transData)
881896

882-
#Flagcolor and and barbcolor provide convenience parameters for setting
883-
#the facecolor and edgecolor, respectively, of the barb polygon. We
884-
#also work here to make the flag the same color as the rest of the barb
885-
#by default
897+
# Flagcolor and and barbcolor provide convenience parameters for
898+
# setting the facecolor and edgecolor, respectively, of the barb
899+
# polygon. We also work here to make the flag the same color as the
900+
# rest of the barb by default
901+
886902
if None in (barbcolor, flagcolor):
887903
kw['edgecolors'] = 'face'
888904
if flagcolor:
889905
kw['facecolors'] = flagcolor
890906
elif barbcolor:
891907
kw['facecolors'] = barbcolor
892908
else:
893-
#Set to facecolor passed in or default to black
909+
# Set to facecolor passed in or default to black
894910
kw.setdefault('facecolors', 'k')
895911
else:
896912
kw['edgecolors'] = barbcolor
897913
kw['facecolors'] = flagcolor
898914

899-
#Parse out the data arrays from the various configurations supported
915+
# Parse out the data arrays from the various configurations supported
900916
x, y, u, v, c = _parse_args(*args)
901917
self.x = x
902918
self.y = y
903919
xy = np.hstack((x[:, np.newaxis], y[:, np.newaxis]))
904920

905-
#Make a collection
921+
# Make a collection
906922
barb_size = self._length ** 2 / 4 # Empirically determined
907923
mcollections.PolyCollection.__init__(self, [], (barb_size,),
908924
offsets=xy,
@@ -927,8 +943,8 @@ def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50):
927943
a barb is empty (too low to plot any barbs/flags.
928944
'''
929945

930-
#If rounding, round to the nearest multiple of half, the smallest
931-
#increment
946+
# If rounding, round to the nearest multiple of half, the smallest
947+
# increment
932948
if rounding:
933949
mag = half * (mag / half + 0.5).astype(np.int)
934950

@@ -989,17 +1005,17 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length,
9891005
properly align with the vector direction.
9901006
'''
9911007

992-
#These control the spacing and size of barb elements relative to the
993-
#length of the shaft
1008+
# These control the spacing and size of barb elements relative to the
1009+
# length of the shaft
9941010
spacing = length * sizes.get('spacing', 0.125)
9951011
full_height = length * sizes.get('height', 0.4)
9961012
full_width = length * sizes.get('width', 0.25)
9971013
empty_rad = length * sizes.get('emptybarb', 0.15)
9981014

999-
#Controls y point where to pivot the barb.
1015+
# Controls y point where to pivot the barb.
10001016
pivot_points = dict(tip=0.0, middle=-length / 2.)
10011017

1002-
#Check for flip
1018+
# Check for flip
10031019
if flip:
10041020
full_height = -full_height
10051021

@@ -1026,11 +1042,11 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length,
10261042

10271043
barb_list = []
10281044
for index, angle in np.ndenumerate(angles):
1029-
#If the vector magnitude is too weak to draw anything, plot an
1030-
#empty circle instead
1045+
# If the vector magnitude is too weak to draw anything, plot an
1046+
# empty circle instead
10311047
if empty_flag[index]:
1032-
#We can skip the transform since the circle has no preferred
1033-
#orientation
1048+
# We can skip the transform since the circle has no preferred
1049+
# orientation
10341050
barb_list.append(empty_barb)
10351051
continue
10361052

0 commit comments

Comments
 (0)