Skip to content

Commit 661d32a

Browse files
authored
Merge pull request #27044 from stevezhang1999/fix-quiver-key
Fix quiver key plot when angles='xy' and/or scale_units='xy'
2 parents c5b9343 + 42e42d5 commit 661d32a

File tree

3 files changed

+73
-13
lines changed

3 files changed

+73
-13
lines changed

lib/matplotlib/quiver.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ def __init__(self, Q, X, Y, U, label,
263263
The key label (e.g., length and units of the key).
264264
angle : float, default: 0
265265
The angle of the key arrow, in degrees anti-clockwise from the
266-
x-axis.
266+
horizontal axis.
267267
coordinates : {'axes', 'figure', 'data', 'inches'}, default: 'axes'
268268
Coordinate system and units for *X*, *Y*: 'axes' and 'figure' are
269269
normalized coordinate systems with (0, 0) in the lower left and
@@ -327,10 +327,8 @@ def _init(self):
327327
Umask=ma.nomask):
328328
u = self.U * np.cos(np.radians(self.angle))
329329
v = self.U * np.sin(np.radians(self.angle))
330-
angle = (self.Q.angles if isinstance(self.Q.angles, str)
331-
else 'uv')
332-
self.verts = self.Q._make_verts(
333-
np.array([u]), np.array([v]), angle)
330+
self.verts = self.Q._make_verts([[0., 0.]],
331+
np.array([u]), np.array([v]), 'uv')
334332
kwargs = self.Q.polykw
335333
kwargs.update(self.kw)
336334
self.vector = mcollections.PolyCollection(
@@ -521,7 +519,7 @@ def _init(self):
521519
# _make_verts sets self.scale if not already specified
522520
if (self._dpi_at_last_init != self.axes.figure.dpi
523521
and self.scale is None):
524-
self._make_verts(self.U, self.V, self.angles)
522+
self._make_verts(self.XY, self.U, self.V, self.angles)
525523

526524
self._dpi_at_last_init = self.axes.figure.dpi
527525

@@ -537,7 +535,7 @@ def get_datalim(self, transData):
537535
@martist.allow_rasterization
538536
def draw(self, renderer):
539537
self._init()
540-
verts = self._make_verts(self.U, self.V, self.angles)
538+
verts = self._make_verts(self.XY, self.U, self.V, self.angles)
541539
self.set_verts(verts, closed=False)
542540
super().draw(renderer)
543541
self.stale = False
@@ -594,33 +592,38 @@ def _set_transform(self):
594592
self.set_transform(trans)
595593
return trans
596594

597-
def _angles_lengths(self, U, V, eps=1):
598-
xy = self.axes.transData.transform(self.XY)
595+
# Calculate angles and lengths for segment between (x, y), (x+u, y+v)
596+
def _angles_lengths(self, XY, U, V, eps=1):
597+
xy = self.axes.transData.transform(XY)
599598
uv = np.column_stack((U, V))
600-
xyp = self.axes.transData.transform(self.XY + eps * uv)
599+
xyp = self.axes.transData.transform(XY + eps * uv)
601600
dxy = xyp - xy
602601
angles = np.arctan2(dxy[:, 1], dxy[:, 0])
603602
lengths = np.hypot(*dxy.T) / eps
604603
return angles, lengths
605604

606-
def _make_verts(self, U, V, angles):
605+
# XY is stacked [X, Y].
606+
# See quiver() doc for meaning of X, Y, U, V, angles.
607+
def _make_verts(self, XY, U, V, angles):
607608
uv = (U + V * 1j)
608609
str_angles = angles if isinstance(angles, str) else ''
609610
if str_angles == 'xy' and self.scale_units == 'xy':
610611
# Here eps is 1 so that if we get U, V by diffing
611612
# the X, Y arrays, the vectors will connect the
612613
# points, regardless of the axis scaling (including log).
613-
angles, lengths = self._angles_lengths(U, V, eps=1)
614+
angles, lengths = self._angles_lengths(XY, U, V, eps=1)
614615
elif str_angles == 'xy' or self.scale_units == 'xy':
615616
# Calculate eps based on the extents of the plot
616617
# so that we don't end up with roundoff error from
617618
# adding a small number to a large.
618619
eps = np.abs(self.axes.dataLim.extents).max() * 0.001
619-
angles, lengths = self._angles_lengths(U, V, eps=eps)
620+
angles, lengths = self._angles_lengths(XY, U, V, eps=eps)
621+
620622
if str_angles and self.scale_units == 'xy':
621623
a = lengths
622624
else:
623625
a = np.abs(uv)
626+
624627
if self.scale is None:
625628
sn = max(10, math.sqrt(self.N))
626629
if self.Umask is not ma.nomask:
@@ -630,6 +633,7 @@ def _make_verts(self, U, V, angles):
630633
# crude auto-scaling
631634
# scale is typical arrow length as a multiple of the arrow width
632635
scale = 1.8 * amean * sn / self.span
636+
633637
if self.scale_units is None:
634638
if self.scale is None:
635639
self.scale = scale

lib/matplotlib/tests/test_quiver.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,62 @@ def test_quiverkey_angles():
267267
assert len(qk.verts) == 1
268268

269269

270+
def test_quiverkey_angles_xy_aitoff():
271+
# GH 26316 and GH 26748
272+
# Test that only one arrow will be plotted with non-cartesian
273+
# when angles='xy' and/or scale_units='xy'
274+
275+
# only for test purpose
276+
# scale_units='xy' may not be a valid use case for non-cartesian
277+
kwargs_list = [
278+
{'angles': 'xy'},
279+
{'angles': 'xy', 'scale_units': 'xy'},
280+
{'scale_units': 'xy'}
281+
]
282+
283+
for kwargs_dict in kwargs_list:
284+
285+
x = np.linspace(-np.pi, np.pi, 11)
286+
y = np.ones_like(x) * np.pi / 6
287+
vx = np.zeros_like(x)
288+
vy = np.ones_like(x)
289+
290+
fig = plt.figure()
291+
ax = fig.add_subplot(projection='aitoff')
292+
q = ax.quiver(x, y, vx, vy, **kwargs_dict)
293+
qk = ax.quiverkey(q, 0, 0, 1, '1 units')
294+
295+
fig.canvas.draw()
296+
assert len(qk.verts) == 1
297+
298+
299+
def test_quiverkey_angles_scale_units_cartesian():
300+
# GH 26316
301+
# Test that only one arrow will be plotted with normal cartesian
302+
# when angles='xy' and/or scale_units='xy'
303+
304+
kwargs_list = [
305+
{'angles': 'xy'},
306+
{'angles': 'xy', 'scale_units': 'xy'},
307+
{'scale_units': 'xy'}
308+
]
309+
310+
for kwargs_dict in kwargs_list:
311+
X = [0, -1, 0]
312+
Y = [0, -1, 0]
313+
U = [1, -1, 1]
314+
V = [1, -1, 0]
315+
316+
fig, ax = plt.subplots()
317+
q = ax.quiver(X, Y, U, V, **kwargs_dict)
318+
ax.quiverkey(q, X=0.3, Y=1.1, U=1,
319+
label='Quiver key, length = 1', labelpos='E')
320+
qk = ax.quiverkey(q, 0, 0, 1, '1 units')
321+
322+
fig.canvas.draw()
323+
assert len(qk.verts) == 1
324+
325+
270326
def test_quiver_setuvc_numbers():
271327
"""Check that it is possible to set all arrow UVC to the same numbers"""
272328

0 commit comments

Comments
 (0)