Skip to content Skip to sidebar Skip to footer

How To Draw A Filled Arc In Matplotlib

In matplotlib, I would like draw an filled arc which looks like this: The following code results in an unfilled line arc: import matplotlib.patches as mpatches import matplotlib.p

Solution 1:

@jeanrjc's solution almost gets you there, but it adds a completely unnecessary white triangle, which will hide other objects as well (see figure below, version 1).

This is a simpler approach, which only adds a polygon of the arc:

Basically we create a series of points (points) along the edge of the circle (from theta1 to theta2). This is already enough, as we can set the close flag in the Polygon constructor which will add the line from the last to the first point (creating a closed arc).

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np

def arc_patch(center, radius, theta1, theta2, ax=None, resolution=50, **kwargs):
    # make sure ax is not empty
    if ax is None:
        ax = plt.gca()
    # generate the points
    theta = np.linspace(np.radians(theta1), np.radians(theta2), resolution)
    points = np.vstack((radius*np.cos(theta) + center[0], 
                        radius*np.sin(theta) + center[1]))
    # build the polygon and add it to the axes
    poly = mpatches.Polygon(points.T, closed=True, **kwargs)
    ax.add_patch(poly)
    return poly

And then we apply it:

fig, ax = plt.subplots(1,2)

# @jeanrjc solution, which might hide other objects in your plot
ax[0].plot([-1,1],[1,-1], 'r', zorder = -10)
filled_arc((0.,0.3), 1, 90, 180, ax[0], 'blue')
ax[0].set_title('version 1')

# simpler approach, which really is just the arc
ax[1].plot([-1,1],[1,-1], 'r', zorder = -10)
arc_patch((0.,0.3), 1, 90, 180, ax=ax[1], fill=True, color='blue')
ax[1].set_title('version 2')

# axis settings
for a in ax:
    a.set_aspect('equal')
    a.set_xlim(-1.5, 1.5)
    a.set_ylim(-1.5, 1.5)

plt.show()

Result (version 2):

enter image description here


Solution 2:

You can use fill_between to achieve this

 import matplotlib.patches as mpatches
 import matplotlib.pyplot as plt
 import numpy as np

 fg, ax = plt.subplots(1, 1)

 r=2.
 yoff=-1
 x=np.arange(-1.,1.05,0.05)
 y=np.sqrt(r-x**2)+yoff

 ax.fill_between(x,y,0)

 ax.axis([-2, 2, -2, 2])
 ax.set_aspect("equal")
 fg.canvas.draw()

Play around with r and yoff to move the arc

enter image description here

EDIT:

OK, so you want to be able to plot arbitrary angles? You just need to find the equation of the chord, rather than using a flat line like above. Here's a function to do just that:

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np

fg, ax = plt.subplots(1, 1)

col='rgbkmcyk'

def filled_arc(center,r,theta1,theta2):

    # Range of angles
    phi=np.linspace(theta1,theta2,100)

    # x values
    x=center[0]+r*np.sin(np.radians(phi))

    # y values. need to correct for negative values in range theta=90--270
    yy = np.sqrt(r-x**2)
    yy = [-yy[i] if phi[i] > 90 and phi[i] < 270 else yy[i] for i in range(len(yy))]

    y = center[1] + np.array(yy)

    # Equation of the chord
    m=(y[-1]-y[0])/(x[-1]-x[0])
    c=y[0]-m*x[0]
    y2=m*x+c

    # Plot the filled arc
    ax.fill_between(x,y,y2,color=col[theta1/45])

# Lets plot a whole range of arcs
for i in [0,45,90,135,180,225,270,315]:
    filled_arc([0,0],1,i,i+45)

ax.axis([-2, 2, -2, 2])
ax.set_aspect("equal")
fg.savefig('filled_arc.png')

And here's the output:

enter image description here


Solution 3:

Here's a simpler workaround. Use the hatch argument in your mpatches.Arc command. If you repeat symbols with the hatch argument it increases the density of the patterning. I find that if you use 6 dashes, '-', or 6 dots, '.' (others probably also work), then it solidly fills in the arc as desired. When I run this

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt 

plt.axes()
pac = mpatches.Arc([0, -2.5], 5, 5, 45, theta1=45, theta2=135, hatch = '......')
plt.gca().add_patch(pac)
pac.set_color('cyan')
plt.axis('equal')
plt.show()

I get this:

Arc filled with dense dot hatch and rotated 45 degrees just for show


Solution 4:

You can draw a wedge, and then hide part of it with a triangle:

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np

def filled_arc(center, radius, theta1, theta2, ax, color):

    circ = mpatches.Wedge(center, radius, theta1, theta2, fill=True, color=color)
    pt1 = (radius * (np.cos(theta1*np.pi/180.)) + center[0],
           radius * (np.sin(theta1*np.pi/180.)) + center[1])
    pt2 = (radius * (np.cos(theta2*np.pi/180.)) + center[0],
           radius * (np.sin(theta2*np.pi/180.)) + center[1])
    pt3 = center
    pol = mpatches.Polygon([pt1, pt2, pt3], color=ax.get_axis_bgcolor(),
                           ec=ax.get_axis_bgcolor(), lw=2 )
    ax.add_patch(circ)
    ax.add_patch(pol)

and then you can call it:

fig, ax = plt.subplots(1,2)
filled_arc((0,0), 1, 45, 135, ax[0], "blue")
filled_arc((0,0), 1, 0, 40, ax[1], "blue")

and you get:

filled_arc

or:

fig, ax = plt.subplots(1, 1)
for i in range(0,360,45):
    filled_arc((0,0), 1, i, i+45, ax, plt.cm.jet(i))

and you get:

enter image description here

HTH


Solution 5:

The command ax.get_axis_bgcolor() needs to be replaced by ax.get_fc() for newer matplotlib.


Post a Comment for "How To Draw A Filled Arc In Matplotlib"