diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index ee38cc91ab83..faed03104c72 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -6777,6 +6777,50 @@ def hist(self, x, bins=None, range=None, density=False, weights=None, else "list[Polygon]") return tops, bins, cbook.silent_list(patch_type, patches) + def vector(self, start, *, delta=None, end=None, **kwargs): + """ + Plot an arrow indicating a vector. + + Parameters + ---------- + start : (float, float) + The base point of the vector. + delta : (float, float) + The delta (deltaX, deltaY) from the start to the end of the vector. + Incompatible with *end* + end : float (optional) + The end point of the vector. Incompatible with *delta* + + Other Parameters + ---------------- + **kwargs + `~matplotlib.patches.FancyArrowPatch` properties + """ + if not((delta is None) ^ (end is None)): + raise ValueError("Exactly one *delta* or *end* must be Non-Zero") + if end is None: + end = np.asanyarray(start) + np.asanyarray(delta) + + color = kwargs.pop("color", None) + if color is None: + color = self._get_lines.get_next_color() + shrinkA = kwargs.get("shrinkA", 0) + shrinkB = kwargs.get("shrinkB", 0) + vect = mpatches.FancyArrowPatch( + start, end, color=color, shrinkA=shrinkA, shrinkB=shrinkB, **kwargs + ) + ms = vect._mutation_scale + stylekw = { + "head_length": kwargs.get("head_length", 12) / ms, + "head_width": kwargs.get("head_width", 12) / ms, + "tail_width": kwargs.get("tail_width", 4) / ms, + } + vect.set_arrowstyle(kwargs.get("arrowstyle", "simple"), **stylekw) + self.add_patch(vect) + self.update_datalim([start, end]) + self._request_autoscale_view() + return vect + @_preprocess_data() def stairs(self, values, edges=None, *, orientation='vertical', baseline=0, fill=False, **kwargs): diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 894717dcdd3e..d6700f5fa2c9 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -4378,6 +4378,28 @@ def set_positions(self, posA, posB): self._posA_posB[1] = posB self.stale = True + def set_delta(self, delta): + """ + Set the end position by the delta from the start (posA). + + Parameters + ---------- + delta : (float, float) + The delta between the arrow tail and head. + """ + self._posA_posB[1] = self._posA_posB[0] + delta + self.stale = True + + def get_delta(self): + """ + Get the delta between the end and start positions. + + Returns + ------- + np.array + """ + return np.asanyarray(self._posA_posB[1] - self._posA_posB[0]) + def set_patchA(self, patchA): """ Set the tail patch.