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

Skip to content

Let quiver retrieve X, Y from base PolyCollection.get_offsets(). #24952

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 36 additions & 41 deletions lib/matplotlib/quiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,22 +445,20 @@ def _check_consistent_shapes(*arrays):

class Quiver(mcollections.PolyCollection):
"""
Specialized PolyCollection for arrows.

The only API method is set_UVC(), which can be used
to change the size, orientation, and color of the
arrows; their locations are fixed when the class is
instantiated. Possibly this method will be useful
in animations.

Much of the work in this class is done in the draw()
method so that as much information as possible is available
about the plot. In subsequent draw() calls, recalculation
is limited to things that might have changed, so there
should be no performance penalty from putting the calculations
in the draw() method.
Specialized `.PolyCollection` for arrows.

The only API method is `set_UVC`, which can be used to change the size,
orientation, and color of the arrows. Locations are changed using the
(inherited) `.PolyCollection.set_offsets` method. This method may be
useful in animations.
Comment on lines +451 to +453
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I think the behavior is a little bit more complicated than than just using set_offsets due to the interactions of UVC and XY which may be difficult for users to discover. See #22407

"""

# Much of the work in this class is done in the draw() method so that as
# much information as possible is available about the plot. In subsequent
# draw() calls, recalculation is limited to things that might have changed,
# so there should be no performance penalty from putting the calculations
# in the draw() method.

_PIVOT_VALS = ('tail', 'middle', 'tip')

@_docstring.Substitution(_quiver_doc)
Expand All @@ -476,10 +474,6 @@ def __init__(self, ax, *args,
"""
self._axes = ax # The attr actually set by the Artist.axes property.
X, Y, U, V, C = _parse_args(*args, caller_name='quiver')
self.X = X
self.Y = Y
self.XY = np.column_stack((X, Y))
self.N = len(X)
self.scale = scale
self.headwidth = headwidth
self.headlength = float(headlength)
Expand All @@ -499,12 +493,18 @@ def __init__(self, ax, *args,
self.transform = kwargs.pop('transform', ax.transData)
kwargs.setdefault('facecolors', color)
kwargs.setdefault('linewidths', (0,))
super().__init__([], offsets=self.XY, offset_transform=self.transform,
super().__init__([], offsets=np.column_stack([X, Y]),
offset_transform=self.transform,
closed=False, **kwargs)
self.polykw = kwargs
self.set_UVC(U, V, C)
self._dpi_at_last_init = None

XY = property(lambda self: self.get_offsets())
X = property(lambda self: self.get_offsets()[:, 0])
Y = property(lambda self: self.get_offsets()[:, 1])
N = property(lambda self: len(self.get_offsets()))

def _init(self):
"""
Initialization delayed until first draw;
Expand Down Expand Up @@ -675,16 +675,14 @@ def _h_arrows(self, length):
# length = np.minimum(length, 2 ** 16)
np.clip(length, 0, 2 ** 16, out=length)
# x, y: normal horizontal arrow
x = np.array([0, -self.headaxislength,
-self.headlength, 0],
np.float64)
x = np.array([0, -self.headaxislength, -self.headlength, 0], float)
x = x + np.array([0, 1, 1, 1]) * length
y = 0.5 * np.array([1, 1, self.headwidth, 0], np.float64)
y = 0.5 * np.array([1, 1, self.headwidth, 0], float)
y = np.repeat(y[np.newaxis, :], N, axis=0)
# x0, y0: arrow without shaft, for short vectors
x0 = np.array([0, minsh - self.headaxislength,
minsh - self.headlength, minsh], np.float64)
y0 = 0.5 * np.array([1, 1, self.headwidth, 0], np.float64)
minsh - self.headlength, minsh], float)
y0 = 0.5 * np.array([1, 1, self.headwidth, 0], float)
ii = [0, 1, 2, 3, 2, 1, 0, 0]
X = x[:, ii]
Y = y[:, ii]
Expand Down Expand Up @@ -866,22 +864,18 @@ def _h_arrows(self, length):

class Barbs(mcollections.PolyCollection):
"""
Specialized PolyCollection for barbs.

The only API method is :meth:`set_UVC`, which can be used to
change the size, orientation, and color of the arrows. Locations
are changed using the :meth:`set_offsets` collection method.
Possibly this method will be useful in animations.
Specialized `.PolyCollection` for barbs.

There is one internal function :meth:`_find_tails` which finds
exactly what should be put on the barb given the vector magnitude.
From there :meth:`_make_barbs` is used to find the vertices of the
polygon to represent the barb based on this information.
The only API method is `set_UVC`, which can be used to change the size,
orientation, and color of the arrows. Locations are changed using the
(inherited) `.PolyCollection.set_offsets` method. This method may be
useful in animations.
"""

# This may be an abuse of polygons here to render what is essentially maybe
# 1 triangle and a series of lines. It works fine as far as I can tell
# however.
# There is one internal function :meth:`_find_tails` which finds
# exactly what should be put on the barb given the vector magnitude.
# From there :meth:`_make_barbs` is used to find the vertices of the
# polygon to represent the barb based on this information.

@_docstring.interpd
def __init__(self, ax, *args,
Expand All @@ -903,7 +897,7 @@ def __init__(self, ax, *args,
self._pivot = pivot
self._length = length

# Flagcolor and barbcolor provide convenience parameters for
# flagcolor and barbcolor provide convenience parameters for
# setting the facecolor and edgecolor, respectively, of the barb
# polygon. We also work here to make the flag the same color as the
# rest of the barb by default
Expand All @@ -928,8 +922,6 @@ def __init__(self, ax, *args,

# Parse out the data arrays from the various configurations supported
x, y, u, v, c = _parse_args(*args, caller_name='barbs')
self.x = x
self.y = y
xy = np.column_stack((x, y))

# Make a collection
Expand All @@ -940,6 +932,9 @@ def __init__(self, ax, *args,

self.set_UVC(u, v, c)

x = property(lambda self: self.get_offsets()[:, 0])
y = property(lambda self: self.get_offsets()[:, 1])

def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50):
"""
Find how many of each of the tail pieces is necessary.
Expand Down