-
-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
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.
# it looks fine if we don't divide by 100, but if we do, the scaling is way off
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)
for i in range(5):
plt.arrow(x0[i], y0[i], dx[i], dy[i])
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.