Circle-wave

Inspired by https://dribbble.com/shots/1696376-Circle-wave

They are several ways to produce such a plot :

  • fixed rotating curve
  • moving filter to a fixed curve

I tried the second approach here


In [ ]:
%matplotlib 
 
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as manimation

plt.ion()

In [ ]:
nwave = 8
amp_wave = 0.1
rad_wave = 0.8
frames = 100

npoints=500

In [ ]:
# We want a square figure with a black background

fig = plt.figure(facecolor='k', figsize=(5,5))

# Obviously a polar plot and enough space to see all the curves
ax = fig.add_subplot(111, polar=True)
ax.set_xlim(0,rad_wave+amp_wave*1.1)
ax.set_ylim(0,rad_wave+amp_wave*1.1)

# Let's put everything in black and remove the axis 
ax.set_axis_bgcolor('black')
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
for spine in ax.spines.itervalues():
    spine.set_visible(False)

We basically need two cosine plots


In [ ]:
x = np.linspace(0,2*np.pi,npoints)

plots = [ ax.plot(x, rad_wave+amp_wave*np.cos(nwave*x), color='w', linewidth=4)[0], \
          ax.plot(x, rad_wave-amp_wave*np.cos(nwave*x), color='w', linewidth=4)[0] ]

fig.tight_layout()

We can define an atenuation filter on those plots, let's try a simple gaussian


In [ ]:
tau = np.exp(-(x-np.pi)**2/(2*(np.pi/4)**2))

plots[0].set_ydata(rad_wave+amp_wave*np.cos(nwave*x)*tau)
plots[1].set_ydata(rad_wave-amp_wave*np.cos(nwave*x)*tau)

Looks good enough, we can try to animate it by shifting the filter


In [ ]:
def init():
    return plots

def update_image(iframe):
    global x
    tau = np.roll( np.exp(-(x-np.pi)**2/(2*(np.pi/4)**2)), -int(iframe*1.0/frames*npoints))
    plots[0].set_ydata( rad_wave+amp_wave*np.cos(nwave*x)*tau )
    plots[1].set_ydata( rad_wave-amp_wave*np.cos(nwave*x)*tau )

    return plots

In [ ]:
map_animation = manimation.FuncAnimation(fig, update_image, init_func=init, frames=frames, interval=50, repeat=True)
plt.show()

And we can simply save this animation as a gif


In [ ]:
map_animation.save('circle-wave.gif', writer='imagemagic', dpi=40, fps=25, savefig_kwargs=dict(facecolor=fig.get_facecolor(), edgecolor='none'))

And if everything worked properly you should get a tidy gif :