8

I want to plot a donut and my script is

import numpy as np
import matplotlib.pyplot as plt
pi,sin,cos = np.pi,np.sin,np.cos

r1 = 1
r2 = 2

theta = np.linspace(0,2*pi,36)

x1 = r1*cos(theta)
y1 = r1*sin(theta)

x2 = r2*cos(theta)
y2 = r2*sin(theta)

How to get a donut with red filled area ?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
zongyuan yang
  • 109
  • 1
  • 2

4 Answers4

17

You can traverse the boundaries of the area in closed curve, and use fill method to fill the area inside this closed area:

import numpy as np
import matplotlib.pyplot as plt

n, radii = 50, [.7, .95]
theta = np.linspace(0, 2*np.pi, n, endpoint=True)
xs = np.outer(radii, np.cos(theta))
ys = np.outer(radii, np.sin(theta))

# in order to have a closed area, the circles
# should be traversed in opposite directions
xs[1,:] = xs[1,::-1]
ys[1,:] = ys[1,::-1]

ax = plt.subplot(111, aspect='equal')
ax.fill(np.ravel(xs), np.ravel(ys), edgecolor='#348ABD')

plt.show()

enter image description here

This can easily be applied to any shape, for example, a pentagon inside or outside of a circle:

pentagon

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
behzad.nouri
  • 74,723
  • 18
  • 126
  • 124
3

You can do this by plotting the top and bottom halves separately:

import numpy as np
import matplotlib.pyplot as plt

inner = 5.
outer = 10.

x = np.linspace(-outer, outer, 1000, endpoint=True)

yO = outer*np.sin(np.arccos(x/outer)) # x-axis values -> outer circle
yI = inner*np.sin(np.arccos(x/inner)) # x-axis values -> inner circle (with nan's beyond circle)
yI[np.isnan(yI)] = 0.                 # yI now looks like a boulder hat, meeting yO at the outer points

ax = plt.subplot(111)
ax.fill_between(x, yI, yO, color="red")
ax.fill_between(x, -yO, -yI, color="red")

plt.show()

enter image description here

Or you can use polar coordinates, though whether this is beneficial depends on the broader context:

import numpy as np
import matplotlib.pyplot as plt

theta = np.linspace(0., 2.*np.pi, 80, endpoint=True)
ax = plt.subplot(111, polar=True)
ax.fill_between(theta, 5., 10., color="red")

plt.show()

enter image description here

tom10
  • 67,082
  • 10
  • 127
  • 137
1

It's a bit of a hack but the following works:

import numpy as np
import matplotlib.pyplot as plt
pi,sin,cos = np.pi,np.sin,np.cos

r1 = 1
r2 = 2

theta = np.linspace(0,2*pi,36)

x1 = r1*cos(theta)
y1 = r1*sin(theta)

x2 = r2*cos(theta)
y2 = r2*sin(theta)

fig, ax = plt.subplots()

ax.fill_between(x2, -y2, y2, color='red')
ax.fill_between(x1, y1, -y1, color='white')

plt.show()

It plots the whole area of your donut in red and then plots the central "hole" in white.

Example plot

Ffisegydd
  • 51,807
  • 15
  • 147
  • 125
0

The answer given by tom10 is ten ;) But if you want to define the circle (donut) origin is simple, just add the position x,y in the x, yI, yO and -yO and -yI with:

    ax.fill_between(x+pos[0], yI+pos[1], yO+pos[1], color=color)
    ax.fill_between(x+pos[0], -yO+pos[1], -yI+pos[1], color=color)

As shown below:

import numpy as np
import matplotlib.pyplot as plt
import math
 
 
def plot_circle_donut(pos, inner, outer, color):
    """
     REF: https://stackoverflow.com/questions/22789356/plot-a-donut-with-fill-or-fill-between-use-pyplot-in-matplotlib
     ton10's answer
    """
    x = np.linspace(-outer, outer, 300, endpoint=True)
 
    yO = outer * np.sin(np.arccos(x/ outer )) # x-axis values -> outer circle
    yI = inner * np.sin(np.arccos(x/ inner )) # x-axis values -> inner circle (with nan's beyond circle)
    yI[np.isnan(yI)] = 0.                 # yI now looks like a boulder hat, meeting yO at the outer points
 
    ax = plt.subplot(111)
    ax.fill_between(x+pos[0], yI+pos[1], yO+pos[1], color=color)
    ax.fill_between(x+pos[0], -yO+pos[1], -yI+pos[1], color=color)
 
    plt.show()
#
 
def plot_circle(r, pos):
    """ REF: https://math.stackexchange.com/questions/260096/find-the-coordinates-of-a-point-on-a-circle """
    arrx = []
    arry = []
    for theta in xrange(1000):
        x,y = r * math.sin(theta), r * math.cos(theta)
        arrx.append(x)
        arry.append(y)
    #
    plt.plot(arrx, arry, color='red')
 
    plt.show()
#
 
 
#r = 3
#pos = 2,2
#plot_circle(r, pos)
 
r1, r2 = 2, 2.1
position = [4,2]
color = 'b'
plot_circle_donut(position, r1, r2, color)

enter image description here

REF Example: https://pastebin.com/8Ew4Vthb

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Wagner Cipriano
  • 1,337
  • 1
  • 12
  • 13