Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: quiverkey shows multiple arrows under geographical projection and angle='xy' #26316

Closed
xlucn opened this issue Jul 15, 2023 · 3 comments · Fixed by #27044
Closed

[Bug]: quiverkey shows multiple arrows under geographical projection and angle='xy' #26316

xlucn opened this issue Jul 15, 2023 · 3 comments · Fixed by #27044

Comments

@xlucn
Copy link

xlucn commented Jul 15, 2023

Bug summary

When I plot quiverkey with subplot option projection='aitoff' and quiver option angle='xy', the quiverkey is then showing multiple arrows pointing at different directions.

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-np.pi, np.pi, 11)
y = np.ones_like(x) * np.pi / 6
vx = np.zeros_like(x)
vy = np.ones_like(x)

fig = plt.figure()
ax = fig.add_subplot(projection='aitoff')
q = ax.quiver(x, y, vx, vy, angles='xy')
ax.quiverkey(q, 0, 0, 1, '1 units')
ax.grid()
plt.show()

Actual outcome

quiver_anglexy

Expected outcome

I naturally expect the quiverkey to be as in the image below, with the default angle='uv' option:

quiver_angleuv

Additional information

No response

Operating system

Arch Linux

Matplotlib Version

3.7.1

Matplotlib Backend

QtAgg

Python version

Python 3.11.3

Jupyter version

No response

Installation

Linux package manager

@stevezhang1999
Copy link
Contributor

This can be reproduced when using mpl=3.7.2 and mpl=3.9.0dev

@stevezhang1999
Copy link
Contributor

stevezhang1999 commented Sep 30, 2023

I think something is wrong in QuiverKey._init(), which will curate the wrong QuiverKey.vector to be draw():
image

The culprit may be in _make_verts

angle = (self.Q.angles if isinstance(self.Q.angles, str)
                         else 'uv')
self.verts = self.Q._make_verts(
    np.array([u]), np.array([v]), angle)

Script to reproduce the figure:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl

x = np.linspace(-np.pi, np.pi, 11)
y = np.ones_like(x) * np.pi / 6
vx = np.zeros_like(x)
vy = np.ones_like(x)

fig = plt.figure()
ax = fig.add_subplot(projection='aitoff')
q = ax.quiver(x, y, vx, vy, angles='xy')
ax.quiverkey(q, 0, 0, 1, '1 units')

qk = ax.get_children()[1]
qk._init()

print(qk.vector._paths)
paths = qk.vector._paths

fig, ax = plt.subplots()

for path in paths: # 12 paths here!
    p = patches.PathPatch(path, facecolor='yellow',
                              edgecolor='red', alpha=0.5, lw=1)
    ax.add_patch(p)

ax.set_xlim(-.1, .1)
ax.set_ylim(-.1, .1)
plt.show()

@stevezhang1999
Copy link
Contributor

stevezhang1999 commented Oct 1, 2023

Things break when we are calling

 angles, lengths = self._angles_lengths(U, V, eps=…)

We are only calling this when we are trying adding a quiver key to a quiver with angles=“xy”
The bug happens becausequiver._angles_lengths assumes [U, V] is of the same shape of [X, Y] and it will use [X, Y] for processing. It’s designed for constructing the quiver - therefore it breaks when we want to reuse it to construct the quiver key. As a result, the return result is incorrectly broadcasted and its size become the same as Quiver()'s input size (We want only one arrow!).

More context:
We call _angles_lengths in Quiver._make_verts(self, U, V, angles). We call Quiver._make_verts(self, U, V, angles) for constructing paths for both the quiver and the quiver key. Quiver._make_verts(self, U, V, angles) isn’t formally documented, so, from its name, it will constructs vertices from given U, V, and mapping of angles (“xy” vs “uv”). We want to use the same _make_verts for both the quiver and the quiver key, because we want the properties of the quiver key be consistent with the quiver. The conclusion is that, although it breaks, we may still want to reuse _make_verts rather than drawing the quiver key with a new method.

Solution:

  1. Easiest solution but with one small question to be clarified:
    1. Solution: Make Quiver._make_verts(self, U, V, angles) in QuiverKey always use angles a default value (‘uv’ will be applied here)
      1. In the doc: “QuiverKey.angle: The angle of the key arrow, in degrees anti-clockwise from the x-axis.” Since we are not explicitly passing [U, V], but an angle, it doesn’t make sense that we can apply “xy” here.
    2. Question: I suggest change “anti-clockwise from the x-axis” to “anti-clockwise from the horizontal line”. I believe here the “x-axis” refers to x-aixs in a canonical x-y coordinates for a canvas (cuz we are printing the figure in a 2D canvas), rather than in coordinates that with a projection.
  2. Modify _angles_lengths to deal with size unmatch - lot’s of work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants