Search code examples
pythonanimationmatplotlibpolar-coordinates

how can I animate points between sectors of polar axis?


I'm trying to animate a circle travelling on an arch around sectors in a polar graph (e.g. quarters of a circle, pie pieces). In the image below, the animation would move a single circle from point 1 to 2, then from 2 to 3, and so on until the circle travels from 5 to 6.

unsuccessful polar animation

So far, I'm unable to make the shape a circle and the movement isn't happening between sectors.

After much experimenting and googling I haven't been able to find any pointers on how to define the location of patch.center in init() appropriately, and how to update it in animate() so that it travels in sequence from 1 to 6, as explained above. I saw in this post that adding the parameter transform=ax.transData._b to plt.Circle() makes it a circle, but then on animation I get the error ValueError: The shortcut cannot be computed since other's transform includes a non-invertable component..

Any pointers are appreciated!

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation

r_list = [1.3, 1.3, 1.3, 1.3, 1.3, 1.3] 
theta_list = [1.5707963267948966, 0.7853981633974483, -3.9269908169872414, 0.0, 3.141592653589793, -0.7853981633974483]


def cart2pol(x, y):
    rho = np.sqrt(x**2 + y**2)
    phi = np.arctan2(y, x)
    return(rho, phi)

def pol2cart(rho, phi):
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)
    return(x, y)

fig = plt.figure()
ax = plt.subplot(111, polar=True)


####### used only to clearly label intended travel #######

c = plt.scatter(theta_list, r_list)
ax.set_yticklabels([])
labels=["1", "2", "3", "4", "5", "6"]
for i, txt in enumerate(labels):
    ax.annotate(txt, (theta_list[i], r_list[i]))

##########################################################

patch = plt.Circle(pol2cart(r_list[0], theta_list[0]), 0.5, alpha=0.5)

def init():
    patch.center = (pol2cart(r_list[0], theta_list[0]))
    ax.add_patch(patch)
    return patch,


def animate(i):
    x, y = patch.center
    x, y = (pol2cart(r_list[i%6], theta_list[i%6]))
    patch.center = (x, y)
    return patch,


anim = animation.FuncAnimation(fig, animate, 
                               init_func=init, 
                               frames=360, 
                               interval=200,
                               blit=True)
plt.show()

Solution

  • Change to the following code, use scatter() to draw the circle, and set the center of the circle by set_offsets() method:

    patch = plt.scatter(theta_list[0], r_list[0], 600, alpha=0.5)
    
    def init():
        patch.set_offsets([[theta_list[0], r_list[0]]])
        return patch,
    
    def animate(i):
        patch.set_offsets([[theta_list[i % 6], r_list[i % 6]]])
        return patch,
    

    the plot is looking like this:

    enter image description here