Why does plt.quiver flattens the vectors when I give angles?

Question:

So i tried to use plt.quiver, but i couldn’t align the vectors to the grids. When I try to use angles = "xy" it flattens the vectors. When i use angles = "uv" its not aligned.

Here is my code:

import matplotlib.pyplot as plt
import numpy as np

v1 = np.array([[2],[2]])
V = 0
U = 0

fig = plt.figure(figsize=(5,10))
ax1 = plt.subplot(2,1,1)

ax1.quiver(V, U, v1[0], v1[1], scale = 1, units= "xy",angles = "uv")
ax1.set_ylim(-3,3)
ax1.set_xlim(-3,3)
ax1.grid()

ax2 = plt.subplot(2,1,2)

ax2.quiver(V, U, v1[0], v1[1], scale = 1, units= "xy",angles = "uv")
ax2.set_ylim(-3,3)
ax2.set_xlim(-3,3)
ax2.grid()

plt.show()

Error code when using angles ="xy":

The error code : …PythonPython310libsite-packagesmatplotlibquiver.py:609:
RuntimeWarning: invalid value encountered in true_divide
lengths = np.hypot(*dxy.T) / eps

The plot:

When angles = "xy": https://i.stack.imgur.com/6DFd9.png

When angles = "uv": https://i.stack.imgur.com/dB5dv.png

I’m a little bit new to the quiver function and I’m not sure how could i solve this.

Asked By: krusoadam

||

Answers:

This appears to be an artifact (bug?) of how matplotlib is trying to scale the arrows.

In the source of Quiver, here there is the following lines:

if str_angles == 'xy' and self.scale_units == 'xy':
    # Here eps is 1 so that if we get U, V by diffing
    # the X, Y arrays, the vectors will connect the
    # points, regardless of the axis scaling (including log).
    angles, lengths = self._angles_lengths(U, V, eps=1)
elif str_angles == 'xy' or self.scale_units == 'xy':
    # Calculate eps based on the extents of the plot
    # so that we don't end up with roundoff error from
    # adding a small number to a large.
    eps = np.abs(self.axes.dataLim.extents).max() * 0.001
    angles, lengths = self._angles_lengths(U, V, eps=eps)

The key line being eps = np.abs(self.axes.dataLim.extents).max() * 0.001 inside the second if block, which is what applies to your call to quiver(...).

All of your data is located at (0,0), which means self.axes.dataLim.extents are zero, and so eps is in turn zero.

The error:

RuntimeWarning: invalid value encountered in true_divide lengths = np.hypot(*dxy.T) / eps

you see is because of a division by zero later on, which tries to use that eps value as a denominator.

You can work-around this either by passing scale_units="xy" to the quiver(...) call, or by calling update_datalim on your axes. E.g.

ax1.update_datalim([(-3, -3), (3, 3)])  # Force axis datalimits to include area we want to view.

or

ax1.quiver(V, U, v1[0], v1[1], scale=1, units="xy", angles="uv", scale_units="xy")
Answered By: mbrig