Search code examples
pythonnumpymatplotlibanimationmatplotlib-animation

Rotating circle going around the circumference of a larger circle on Matplotlib?


I'm trying to use matplotlib to make a program that will use any two circles (any radius) and the adjacent circle will rotate around the main larger circle. I've looked at matplotlib.animation and it doesn't seem to work. Apparently animations just won't work with shapes?

Here's my code so far (I've deleted the animations subroutine as they seem to just brick the program)

import matplotlib.pyplot as plt  
import matplotlib.animation
firstcircle = int(input("please input radius for the largest circle"))
secondcircle = int(input("please input radius for the adjacent circle"))
largest = int(firstcircle*2+secondcircle*2)
difference = int(0-(largest))
difference2 = int(0+(largest))


def createList(r1, r2):
    return [item for item in range(r1, r2+1)]


x = (createList(difference,difference2))
y = (createList(difference,difference2))

print(difference)
print(difference2)


def circle():
  theta = np.linspace(0, 2*np.pi, 100)

  r = np.sqrt(firstcircle**2)

  x1 = r*np.cos(theta)
  x2 = r*np.sin(theta)

  theta2 = np.linspace(0, 2*np.pi, 100)
  r1 = np.sqrt(secondcircle**2)
  x3 = r1*np.cos(theta2)+firstcircle+secondcircle
  x4 = r1*np.sin(theta2)

  fig = plt.figure()

  ax = fig.add_subplot(1, 1, 1)
  ax.spines['left'].set_position('center')
  ax.spines['bottom'].set_position('center')
  ax.spines['right'].set_color('none')
  ax.spines['top'].set_color('none')
  ax.xaxis.set_ticks_position('bottom')
  ax.yaxis.set_ticks_position('left')
  ax.plot(x1,x2)
  circlemove ,= ax.plot(x3,x4)  

  ax.set_aspect(1)
  plt.tight_layout()

  plt.xlim(difference,difference2)
  plt.ylim(difference,difference2)


  plt.grid(linestyle='--')

  plt.show()

circle()

Solution

  • You can use Matplotlib FuncAnimation with a function as argument (update in the code below) to call at each new frame. Use theta2 as argument to the update function (trough the frames parameter in the FuncAnimation) and use it together with the already declared variables x3 and x4 to give the perception of the smaller circle progressing around the larger one. Next, use set_data to allow the circlemove object to display different data points for each new frame.

    from matplotlib.animation import FuncAnimation
    ...
    
        ...
        plt.xlim(difference,difference2)
        plt.ylim(difference,difference2)
    
        plt.grid(linestyle='--')
    
        def update(angle):
            r_a = r1 + firstcircle
            x_a = x3 + r_a * np.cos(angle) - firstcircle - secondcircle
            y_a = x4 + r_a * np.sin(angle)
            circlemove.set_data(x_a, y_a)
            return circlemove
    
        anim = FuncAnimation(fig, update, frames=theta2, repeat=True)
        plt.show()
    
    circle()
    

    rotate_circle