| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
I agree with you that plt.arrow() has a lot of shortcomings.
plt.annotate() is not a solid solution for data-to-data pointing because the arrow tips don't fall in the center of the points.
That could probably be made configurable.
For vectorized arrows we have to solve two issues:
Unfortunately, as simple as it sounds, doing this right needs careful consideration and a non-negligable amount of work.
Indeed arrows are non-trivial, and there are lots of attempts already in the library. I'm not sure we should add another until we are sure we know we don't already have something that works. I think its well-understood that arrow is broken, and maybe needs a new backend.
I'm not entirely clear what is being asked above, but it sounds like what FancyArrowPatch is for? https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.FancyArrowPatch.html#matplotlib.patches.FancyArrowPatch
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
np.random.seed(19680808)
x0 = np.random.uniform(0, 1, 5)
y0 = np.repeat(0, 5)
x1 = np.random.uniform(0, 1, 5)
y1 = np.repeat(1, 5)
fig, ax = plt.subplots()
ax.plot(x0, y0, 'o', markersize=2)
ax.plot(x1, y1, 'o', markersize=2)
arrowstyle = mpatches.ArrowStyle("<->", head_length=6, head_width=6)
for j in range(5):
arrow = mpatches.FancyArrowPatch((x0[j], y0[j]), (x1[j], y1[j]),
arrowstyle=arrowstyle, zorder=10)
ax.add_patch(arrow)There is also quiver which takes vectors or matrices. So, for sure, the above uses a loop, but I'm not sure that is worth adding a new Collection for. How many arrows do you need on a plot?
Seconding quiver() as a vector of arrows plotter, it does almost everything what @vsbuffalo listed, (if I understand everything correctly):
x0 = np.random.uniform(0, 1, 5) / 100
y0 = np.repeat(0, 5)
dx = np.random.normal(0, 0.1, 5) / 100
dy = np.repeat(1, 5)
plt.quiver(x0, y0, dx, dy, angles='xy', scale_units='xy', scale=1)
plt.ylim(-0.1,1.1)The need of the manual limit scaling is unfortunate, but even plain linesegments can be achieved by setting headlength and headaxislength:
plt.quiver(x0, y0, dx, dy, angles='xy', scale_units='xy', scale=1,
headlength=0., headaxislength=0)
plt.ylim(-0.1,1.1)However, both these applications of quiver do not seem to be documented that well (I had to search quiet a bit on how to disable the arrowheads when I needed it for my own work).
An example showcasing these usages and "see also's" in the documentation of plt.arrow and plt.annotate might already go a long way in solving this?
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
| Back | FazBrowse Home | New Git URL |
Per this discussion on Twitter, the matplotlib account suggested we create a feature request for easier arrows. In thinking about how this could be addressed, I think it ties in with another frustration I have with matplotlib: drawing lots of line segments and both could be tackled with the same new function.
Problem
Visually, arrows can be used for a lot of different purposes. plt.annotate() is great for pointing to a feature and labeling it with text, but is not a solid solution for data-to-data pointing because the arrow tips don't fall in the center of the points, e.g.see this example.
plt.arrow() seems like the right solution. However, for general purposes, it has two main shortcomings. First, the scaling of the arrowhead is not automatic, so for certain scales of data the arrowheads look bizarre by default, and the arguments are not vectorized.
Second, as the example shows, the arguments x, y, dx, and dy are not vectorized and explicit looping is required. This relates to another section of the API that's undesirably complex in my view: to draw lots of line segments, one needs to use a LineCollection and use ax.add_collection().
Proposed Solution
Matplotlib could solve both of these issues with a new ax.segments() method. This would take xto, xfrom, yto, and yfrom arguments, and ideally a vector of colors or labels too, and then plot the line segments. Then, one could pass an arrowstyle argument too, which would turn this into a collection of line segments with arrow ends. Also, I think in general it would be easier if the API used to and from coordinates rather than from and dx, dy coordinates. Finally, the default should be that the arrows are lines, rather than filled rectangles as with plt.arrow(), which create visually odd thin-width arrow bodies depending on the angle is steep between the two and from points.