|
| 1 | +""" |
| 2 | +============== |
| 3 | +Angle Arc Demo |
| 4 | +============== |
| 5 | +
|
| 6 | +Draw an angle arc between two vectors |
| 7 | +""" |
| 8 | +from math import atan2, sqrt, pi |
| 9 | +import matplotlib.pyplot as plt |
| 10 | +import matplotlib.patches as mpatches |
| 11 | + |
| 12 | +fig, ax = plt.subplots() |
| 13 | + |
| 14 | +vec1 = ax.arrow(0, 0, 2, 1, head_width=0.05) |
| 15 | +vec2 = ax.arrow(0, 0, -1, 2, head_width=0.05) |
| 16 | + |
| 17 | + |
| 18 | +def get_vector_angle(vec): |
| 19 | + """ |
| 20 | + Finds the angle of a FancyArrow. Probably |
| 21 | + a better way to do this. |
| 22 | +
|
| 23 | + Parameters |
| 24 | + ---------- |
| 25 | + vec : matplotlib.patches.FancyArrow |
| 26 | +
|
| 27 | + Returns |
| 28 | + ------- |
| 29 | + float |
| 30 | + Angle in radians between +x axis |
| 31 | + and vec. |
| 32 | + """ |
| 33 | + xy = vec.get_xy() |
| 34 | + dx = max(xy[:, 0], key=abs) - min(xy[:, 0], key=abs) |
| 35 | + dy = max(xy[:, 1], key=abs) - min(xy[:, 1], key=abs) |
| 36 | + return atan2(dy, dx)*180/pi |
| 37 | + |
| 38 | + |
| 39 | +def draw_arc_between_vectors(ax, vec1, vec2): |
| 40 | + """ |
| 41 | + Draws a scale-invariant arc between two vectors. |
| 42 | +
|
| 43 | + Arc will be drawn counterclockwise if the angle |
| 44 | + of vec1 is smaller than the angle of vec2 and |
| 45 | + will be drawn clockwise otherwise. Arc will be |
| 46 | + drawn as a mpatches.Arc on the provided axes. |
| 47 | +
|
| 48 | + Parameters |
| 49 | + ---------- |
| 50 | + ax : matplotlib.axes._subplots.AxesSubplot |
| 51 | + The axes on which vec1 and vec2 are drawn |
| 52 | + vec1 : matplotlib.patches.FancyArrow |
| 53 | + Vector 1 |
| 54 | + vec2 : matplotlib.patches.FancyArrow |
| 55 | + Vector 2 |
| 56 | + """ |
| 57 | + x0, y0 = ax.transData.transform((0, 0)) |
| 58 | + x1, y1 = ax.transData.transform((1, 1)) |
| 59 | + dx = x1 - x0 |
| 60 | + dy = y1 - y0 |
| 61 | + d = sqrt(dx**2 + dy**2) |
| 62 | + width = d/dx |
| 63 | + height = d/dy |
| 64 | + norm = sqrt(width**2 + height**2) |
| 65 | + width /= norm |
| 66 | + height /= norm |
| 67 | + theta1 = get_vector_angle(vec1) |
| 68 | + theta2 = get_vector_angle(vec2) |
| 69 | + arc = mpatches.Arc((0, 0), width, height, theta1=theta1, theta2=theta2) |
| 70 | + try: |
| 71 | + ax.patches[0].remove() |
| 72 | + except: |
| 73 | + pass |
| 74 | + ax.add_patch(arc) |
| 75 | + print(ax.patches[0].gid) |
| 76 | + |
| 77 | + |
| 78 | +def fig_resize(event): |
| 79 | + draw_arc_between_vectors(ax, vec1, vec2) |
| 80 | + |
| 81 | + |
| 82 | +def axes_resize(ax): |
| 83 | + draw_arc_between_vectors(ax, vec1, vec2) |
| 84 | + |
| 85 | +fig.canvas.mpl_connect("resize_event", fig_resize) |
| 86 | +ax.callbacks.connect("xlim_changed", axes_resize) |
| 87 | +ax.callbacks.connect("ylim_changed", axes_resize) |
| 88 | + |
| 89 | +plt.xlim(-3, 3) |
| 90 | +plt.ylim(-3, 3) |
| 91 | + |
| 92 | +plt.show() |
0 commit comments