Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
207 views
in Technique[技术] by (71.8m points)

python - Best way to plot an angle between two lines in Matplotlib

I am fairly new to using matplotlib and cannot find any examples that show two lines with the angle between them plotted.

This is my current image: enter image description here

And this is an example of what I want to achieve:

enter image description here

I usually take a look at the Matplotlib gallery to get an idea of how to perform certain tasks but there does not seem to be anything similar.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You could use matplotlib.patches.Arc to plot an arc of the corresponding angle measure.

To draw the angle arc:

Define a function that could take 2 matplotlib.lines.Line2D objects, calculate the angle and return a matplotlib.patches.Arc object, which you can add to your plot along with the lines.

def get_angle_plot(line1, line2, offset = 1, color = None, origin = [0,0], len_x_axis = 1, len_y_axis = 1):

    l1xy = line1.get_xydata()

    # Angle between line1 and x-axis
    slope1 = (l1xy[1][1] - l1xy[0][2]) / float(l1xy[1][0] - l1xy[0][0])
    angle1 = abs(math.degrees(math.atan(slope1))) # Taking only the positive angle

    l2xy = line2.get_xydata()

    # Angle between line2 and x-axis
    slope2 = (l2xy[1][3] - l2xy[0][4]) / float(l2xy[1][0] - l2xy[0][0])
    angle2 = abs(math.degrees(math.atan(slope2)))

    theta1 = min(angle1, angle2)
    theta2 = max(angle1, angle2)

    angle = theta2 - theta1

    if color is None:
        color = line1.get_color() # Uses the color of line 1 if color parameter is not passed.

    return Arc(origin, len_x_axis*offset, len_y_axis*offset, 0, theta1, theta2, color=color, label = str(angle)+u"u00b0")

To print the angle values :

Incase you want the angle value to be displayed inline, refer this SO Question for how to print inline labels in matplotlib. Note that you must print the label for the arc.

I made a small function which extracts the vertices of the arc and tries to compute the coordinate of the angle text.

This may not be optimal and may not work well with all angle values.

def get_angle_text(angle_plot):
    angle = angle_plot.get_label()[:-1] # Excluding the degree symbol
    angle = "%0.2f"%float(angle)+u"u00b0" # Display angle upto 2 decimal places

    # Get the vertices of the angle arc
    vertices = angle_plot.get_verts()

    # Get the midpoint of the arc extremes
    x_width = (vertices[0][0] + vertices[-1][0]) / 2.0
    y_width = (vertices[0][5] + vertices[-1][6]) / 2.0

    #print x_width, y_width

    separation_radius = max(x_width/2.0, y_width/2.0)

    return [ x_width + separation_radius, y_width + separation_radius, angle]       

Or you could always precompute the label point manually and use text to display the angle value. You can get the angle value from the label of the Arc object using the get_label() method (Since we had set the label to the angle value + the unicode degree symbol).

Example usage of the above functions :

fig = plt.figure()

line_1 = Line2D([0,1], [0,4], linewidth=1, linestyle = "-", color="green")
line_2 = Line2D([0,4.5], [0,3], linewidth=1, linestyle = "-", color="red")

ax = fig.add_subplot(1,1,1)

ax.add_line(line_1)
ax.add_line(line_2)

angle_plot = get_angle_plot(line_1, line_2, 1)
angle_text = get_angle_text(angle_plot) 
# Gets the arguments to be passed to ax.text as a list to display the angle value besides the arc

ax.add_patch(angle_plot) # To display the angle arc
ax.text(*angle_text) # To display the angle value

ax.set_xlim(0,7)
ax.set_ylim(0,5)

If you do not care about inline placement of the angle text. You could use plt.legend() to print the angle value.

Finally :

plt.legend()
plt.show()

Angle plot with 2 Lines

The offset parameter in the function get_angle_plot is used to specify a psudo-radius value to the arc.

This will be useful when angle arcs may overlap with each other.

( In this figure, like I said, my get_angle_text function is not very optimal in placing the text value, but should give you an idea on how to compute the point )

Adding a third line :

line_3 = Line2D([0,7], [0,1], linewidth=1, linestyle = "-", color="brown")
ax.add_line(line_3)
angle_plot = get_angle_plot(line_1, line_3, 2, color="red") # Second angle arc will be red in color
angle_text = get_angle_text(angle_plot)

ax.add_patch(angle_plot) # To display the 2nd angle arc
ax.text(*angle_text) # To display the 2nd angle value

Angle plot with 3 Lines


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...