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

Skip to content

Commit 9b5bc95

Browse files
committed
Don't check length of arguments in quiver collection and increase coverage
1 parent aba8d9b commit 9b5bc95

File tree

3 files changed

+92
-85
lines changed

3 files changed

+92
-85
lines changed

lib/matplotlib/quiver.py

Lines changed: 30 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -454,11 +454,10 @@ class Quiver(mcollections.PolyCollection):
454454
"""
455455
Specialized PolyCollection for arrows.
456456
457-
The API methods are set_UVC(), set_U(), set_V() and set_C(), which
458-
can be used to change the size, orientation, and color of the
459-
arrows; their locations are fixed when the class is
460-
instantiated. Possibly these methods will be useful
461-
in animations.
457+
The API methods are set_XYUVC(), set_X(), set_Y(), set_U() and set_V(),
458+
which can be used to change the size, orientation, and color of the
459+
arrows; their locations are fixed when the class is instantiated.
460+
Possibly these methods will be useful in animations.
462461
463462
Much of the work in this class is done in the draw()
464463
method so that as much information as possible is available
@@ -512,7 +511,7 @@ def __init__(self, ax, *args,
512511
X, Y, U, V, C, self._nr, self._nc = _parse_args(
513512
*args, caller_name='quiver()'
514513
)
515-
self.set_XYUVC(X=X, Y=Y, U=U, V=V, C=C)
514+
self.set_XYUVC(X=X, Y=Y, U=U, V=V, C=C, check_shape=True)
516515
self._dpi_at_last_init = None
517516

518517
def _init(self):
@@ -547,59 +546,49 @@ def X(self):
547546
return self.get_X()
548547

549548
@X.setter
550-
def X(self):
549+
def X(self, value):
551550
_api.warn_deprecated("3.9", alternative="set_X")
552-
return self.set_X()
551+
return self.set_X(value)
553552

554553
@property
555554
def Y(self):
556555
_api.warn_deprecated("3.9", alternative="get_Y")
557556
return self.get_Y()
558557

559558
@Y.setter
560-
def Y(self):
559+
def Y(self, value):
561560
_api.warn_deprecated("3.9", alternative="set_Y")
562-
return self.set_Y()
561+
return self.set_Y(value)
563562

564563
@property
565564
def U(self):
566565
_api.warn_deprecated("3.9", alternative="get_U")
567566
return self.get_U()
568567

569568
@U.setter
570-
def U(self):
569+
def U(self, value):
571570
_api.warn_deprecated("3.9", alternative="set_U")
572-
return self.set_U()
571+
return self.set_U(value)
573572

574573
@property
575574
def V(self):
576575
_api.warn_deprecated("3.9", alternative="get_V")
577576
return self.get_V()
578577

579578
@V.setter
580-
def V(self):
579+
def V(self, value):
581580
_api.warn_deprecated("3.9", alternative="set_V")
582-
return self.set_V()
583-
584-
@property
585-
def C(self):
586-
_api.warn_deprecated("3.9", alternative="get_C")
587-
return self.get_C()
588-
589-
@C.setter
590-
def C(self):
591-
_api.warn_deprecated("3.9", alternative="set_C")
592-
return self.set_C()
581+
return self.set_V(value)
593582

594583
@property
595584
def XY(self):
596-
_api.warn_deprecated("3.9", alternative="get_XY")
585+
_api.warn_deprecated("3.9", alternative="get_offsets")
597586
return self.get_offsets()
598587

599588
@XY.setter
600-
def XY(self, XY):
601-
_api.warn_deprecated("3.9", alternative="set_XY")
602-
self.set_offsets(offsets=XY)
589+
def XY(self, value):
590+
_api.warn_deprecated("3.9", alternative="set_offsets")
591+
self.set_offsets(offsets=value)
603592

604593
def set_offsets(self, offsets):
605594
self.set_XYUVC(X=offsets[:, 0], Y=offsets[:, 1])
@@ -621,23 +610,6 @@ def draw(self, renderer):
621610
super().draw(renderer)
622611
self.stale = False
623612

624-
def get_XY(self):
625-
"""Returns the positions. Alias for ``get_offsets``."""
626-
return self.get_offsets()
627-
628-
def set_XY(self, XY):
629-
"""
630-
Set positions. Alias for ``set_offsets``. If the size
631-
changes and it is not compatible with ``U``, ``V`` or
632-
``C``, use ``set_XYUVC`` instead.
633-
634-
Parameters
635-
----------
636-
X : array-like
637-
The size must be compatible with ``U``, ``V`` and ``C``.
638-
"""
639-
self.set_offsets(offsets=XY)
640-
641613
def set_X(self, X):
642614
"""
643615
Set positions in the horizontal direction.
@@ -711,9 +683,9 @@ def set_C(self, C):
711683

712684
def get_C(self):
713685
"""Returns the arrow colors."""
714-
return self._C
686+
return self.get_array()
715687

716-
def set_XYUVC(self, X=None, Y=None, U=None, V=None, C=None):
688+
def set_XYUVC(self, X=None, Y=None, U=None, V=None, C=None, check_shape=False):
717689
"""
718690
Set the positions (X, Y) and components (U, V) of the arrow vectors
719691
and arrow colors (C) values of the arrows.
@@ -733,6 +705,9 @@ def set_XYUVC(self, X=None, Y=None, U=None, V=None, C=None):
733705
C : array-like or None, optional
734706
The arrow colors. The default is None.
735707
The size must the same as the existing U, V or be one.
708+
check_shape : bool
709+
Whether to check if the shape of the parameters are
710+
consistent. Default is False.
736711
"""
737712

738713
X = self.get_X() if X is None else X
@@ -752,13 +727,14 @@ def set_XYUVC(self, X=None, Y=None, U=None, V=None, C=None):
752727
C = ma.masked_invalid(
753728
self._C if C is None else C, copy=True
754729
).ravel()
755-
for name, var in zip(('U', 'V', 'C'), (U, V, C)):
756-
if not (var is None or var.size == N or var.size == 1):
757-
raise ValueError(
758-
f'Argument {name} has a size {var.size}'
759-
f' which does not match {N},'
760-
' the number of arrow positions'
761-
)
730+
if check_shape:
731+
for name, var in zip(('U', 'V', 'C'), (U, V, C)):
732+
if not (var is None or var.size == N or var.size == 1):
733+
raise ValueError(
734+
f'Argument {name} has a size {var.size}'
735+
f' which does not match {N},'
736+
' the number of arrow positions'
737+
)
762738

763739
# now shapes are validated and we can start assigning things
764740
mask = ma.mask_or(U.mask, V.mask, copy=False, shrink=True)

lib/matplotlib/quiver.pyi

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ class Quiver(mcollections.PolyCollection):
125125
def N(self) -> int: ...
126126
def get_datalim(self, transData: Transform) -> Bbox: ...
127127
def set_offsets(self, offsets: ArrayLike) -> None: ...
128-
def set_XY(self, XY: ArrayLike) -> None: ...
129-
def get_XY(self) -> ArrayLike: ...
130128
def set_X(self, X: ArrayLike) -> None: ...
131129
def get_X(self) -> ArrayLike: ...
132130
def set_Y(self, Y: ArrayLike) -> None: ...
@@ -143,7 +141,8 @@ class Quiver(mcollections.PolyCollection):
143141
Y: ArrayLike | None = ...,
144142
U: ArrayLike | None = ...,
145143
V: ArrayLike | None = ...,
146-
C: ArrayLike | None = ...
144+
C: ArrayLike | None = ...,
145+
check_shape: bool = ...,
147146
) -> None: ...
148147

149148
class Barbs(mcollections.PolyCollection):

lib/matplotlib/tests/test_collections.py

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -389,17 +389,9 @@ def test_quiver_offsets():
389389

390390
# new length
391391
L = 2
392-
with pytest.raises(ValueError):
393-
qc.set_X(qc.get_X()[:L])
394-
395-
with pytest.raises(ValueError):
396-
qc.set_Y(qc.get_Y()[:L])
397-
398-
with pytest.raises(ValueError):
399-
qc.set_offsets(qc.get_offsets()[:L])
400-
401-
with pytest.raises(ValueError):
402-
qc.set_XYUVC(X=new_X[:L], Y=new_Y[:L])
392+
qc.set_XYUVC(X=new_X[:L], Y=new_Y[:L])
393+
np.testing.assert_allclose(qc.get_X(), new_X[:L])
394+
np.testing.assert_allclose(qc.get_Y(), new_Y[:L])
403395

404396
qc.set_XYUVC(X=X[:L], Y=Y[:L], U=qc.get_U()[:L], V=qc.get_V()[:L])
405397
np.testing.assert_allclose(qc.get_X(), X[:L])
@@ -408,23 +400,21 @@ def test_quiver_offsets():
408400
np.testing.assert_allclose(qc.get_V(), V.ravel()[:L])
409401

410402

411-
def test_quiver_change_UVC():
403+
def test_quiver_change_XYUVC():
412404
fig, ax = plt.subplots()
413405
X = np.arange(-10, 10, 1)
414406
Y = np.arange(-10, 10, 1)
415407
U, V = np.meshgrid(X, Y)
416-
M = np.hypot(U, V)
417-
qc = mquiver.Quiver(
418-
ax, X, Y, U, V, M
419-
)
408+
C = np.hypot(U, V)
409+
qc = mquiver.Quiver(ax, X, Y, U, V, C)
420410
ax.add_collection(qc)
421411
ax.autoscale_view()
422412

423413
np.testing.assert_allclose(qc.get_U(), U.ravel())
424414
np.testing.assert_allclose(qc.get_V(), V.ravel())
425-
np.testing.assert_allclose(qc.get_array(), M.ravel())
415+
np.testing.assert_allclose(qc.get_C(), C.ravel())
426416

427-
qc.set_XYUVC(U=U/2, V=V/3)
417+
qc.set(U=U/2, V=V/3)
428418
np.testing.assert_allclose(qc.get_U(), U.ravel() / 2)
429419
np.testing.assert_allclose(qc.get_V(), V.ravel() / 3)
430420

@@ -434,23 +424,65 @@ def test_quiver_change_UVC():
434424
qc.set_V(V/6)
435425
np.testing.assert_allclose(qc.get_V(), V.ravel() / 6)
436426

437-
qc.set_C(C=M/10)
438-
np.testing.assert_allclose(qc.get_array(), M.ravel() / 10)
427+
qc.set_C(C/3)
428+
np.testing.assert_allclose(qc.get_C(), C.ravel() / 3)
439429

430+
# check consistency not enable
431+
qc.set_XYUVC(X=X[:2], Y=Y[:2])
440432
with pytest.raises(ValueError):
441-
qc.set_X(X[:2])
442-
with pytest.raises(ValueError):
443-
qc.set_Y(Y[:2])
444-
with pytest.raises(ValueError):
445-
qc.set_U(U[:2])
446-
with pytest.raises(ValueError):
447-
qc.set_V(V[:2])
433+
# setting only one of the two X, Y fails because X and Y needs
434+
# to be stacked when passed to `offsets`
435+
qc.set(Y=Y[:3])
448436

449-
qc.set_XYUVC()
437+
qc.set()
450438
np.testing.assert_allclose(qc.get_U(), U.ravel() / 4)
451439
np.testing.assert_allclose(qc.get_V(), V.ravel() / 6)
452440

453441

442+
def test_quiver_deprecated_attribute():
443+
fig, ax = plt.subplots()
444+
X = np.arange(-10, 10, 1)
445+
Y = np.arange(-10, 10, 1)
446+
U, V = np.meshgrid(X, Y)
447+
C = np.hypot(U, V)
448+
qc = mquiver.Quiver(ax, X, Y, U, V, C)
449+
ax.add_collection(qc)
450+
ax.autoscale_view()
451+
452+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
453+
x = qc.X
454+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
455+
qc.X = x * 2
456+
np.testing.assert_allclose(qc.get_X(), x * 2)
457+
458+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
459+
y = qc.Y
460+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
461+
qc.Y = y * 2
462+
np.testing.assert_allclose(qc.get_Y(), y * 2)
463+
464+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
465+
np.testing.assert_allclose(qc.N, len(qc.get_offsets()))
466+
467+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
468+
u = qc.U
469+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
470+
qc.U = u * 2
471+
np.testing.assert_allclose(qc.get_U(), u * 2)
472+
473+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
474+
v = qc.V
475+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
476+
qc.V = v * 2
477+
np.testing.assert_allclose(qc.get_V(), v * 2)
478+
479+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
480+
xy = qc.XY
481+
with pytest.warns(mpl.MatplotlibDeprecationWarning):
482+
qc.XY = xy * 2
483+
np.testing.assert_allclose(qc.get_offsets(), xy * 2)
484+
485+
454486
def test_quiver_limits():
455487
ax = plt.axes()
456488
x, y = np.arange(8), np.arange(10)

0 commit comments

Comments
 (0)