0

I am attempting to build a scatterplot and am stumped on the animations. Ultimately, I want there to be >1000 points, plotted at a random, normal distribution around (0,0). Each point should then rotate either clockwise or counter-clockwise around (0,0) at varying speeds.

I was trying to do this with a loop function that would randomize movement, but it is extremely slow, and as of yet I have been unable to make more than one point move:

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = 4,3
from matplotlib.animation import FuncAnimation
from math import sqrt, exp
from matplotlib.animation import FuncAnimation, PillowWriter

fig, ax = plt.subplots()
# set the axes limits
ax.axis([-2.5,2.5,-2.5,2.5])
# set equal aspect such that the circle is not shown as ellipse
ax.set_aspect("equal")
# create a point in the axes

for i in range(0,6):
    x = np.random.normal()
    y = np.random.normal()
    r = np.sqrt(x*x+y*y)
    def circle(phi):
        return np.array([r*np.cos(phi), r*np.sin(phi)])
    point, = ax.plot(x,y, marker="o")
    ani = FuncAnimation(fig, update, interval=10, blit=True, repeat=True,
                    frames=np.linspace(0,2*np.pi,360, endpoint=False))
    
plt.show()

writer = PillowWriter(fps=25) 
ani.save(r'[path --> .gif]', writer=writer)

How can I fix this code?

Tom
  • 8,310
  • 2
  • 16
  • 36
stimsssss
  • 5
  • 4

2 Answers2

0

Is this what you want?

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = 4,3
from matplotlib.animation import FuncAnimation
from math import sqrt, exp


fig, ax = plt.subplots()
# set the axes limits
ax.axis([-2.5,2.5,-2.5,2.5])
# set equal aspect such that the circle is not shown as ellipse
ax.set_aspect("equal")
# create a point in the axes

def update(i):
    x = np.random.normal()
    y = np.random.normal()
    r = np.sqrt(x*x+y*y)
    def circle(phi):
        return np.array([r*np.cos(phi), r*np.sin(phi)])
    ax.plot(x,y, marker="o")

ani = FuncAnimation(fig, func=update, interval=10, blit=False, repeat=True,
                frames=np.linspace(0,2*np.pi,360, endpoint=False))

plt.show()
Ynjxsjmh
  • 28,441
  • 6
  • 34
  • 52
0

I couldn't quite figure out how to update your code to get towards the solution. But I came up with this, which uses some of the same logic:

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

# how many points to draw
points = 100

# generating x & y coordinates, their distance from origin,
# their angle relative to the origin, and random rotations to
# apply to each point each frame
xs = np.random.uniform(-1, 1, points)
ys = np.random.uniform(-1, 1, points)
ls = np.sqrt(xs**2 + ys**2)
angles = np.arctan2(ys, xs)
negs = np.random.choice([-1, 1], size=points)
rotations = (np.random.uniform(np.pi/50, np.pi/6, size=points) * negs)

# initialize a figure, make a color range to color each point
fig, ax = plt.subplots(figsize=(4,4))
ax.set_xlim(-1.5,1.5)
ax.set_ylim(-1.5,1.5)
color_divisions = [(1/points)*i for i in range(points)]
cmap = mpl.cm.get_cmap('jet')
colors = cmap(color_divisions)

# update function
# update gets fed elements from the frames parameter of FuncAnimation
# each update we clear the graph (but reapply the same x/y limits)
# we then draw the points as a scatter and update the data for the next frame
# add each rotation to each angle, and then calculate the new x and y coordinates
# with numpy these calculations can be done w/o a loop, but global is needed
# to update variables from the global scope
def update(f):
    global xs, ys, angles, rotations
    ax.clear()
    ax.set_xlim(-1.5,1.5)
    ax.set_ylim(-1.5,1.5)
    ax.scatter(xs, ys, color=colors)
    angles += rotations
    ys = np.sin(angles) * ls
    xs = np.cos(angles) * ls

#call the animation and save
ani = FuncAnimation(fig, update, interval=200, frames=range(100))
ani.save('ani.gif', writer='pillow')

Producing the following animation of 100 points rotating around the origin at random speeds:

enter image description here

You can increase the number of points (this may get pretty slow for 1000 points), tweak the FPS (interval), or the amount to rotate each point by.

Tom
  • 8,310
  • 2
  • 16
  • 36
  • That's exactly it. Thanks so much! – stimsssss Aug 13 '20 at 16:06
  • Only question I'd add is this: Is it possible to save this ani as a gif with a transparent background? (In my case, so it could be inserted into a Powerpoint to lay over a background image)? – stimsssss Aug 13 '20 at 16:15
  • @stimsssss Hmmmm I am not aware of how to do this. I have seen [this post](https://adrian.pw/blog/matplotlib-transparent-animation/) and [this issue](https://stackoverflow.com/questions/38406617/mplot3d-animation-with-transparent-background) which you could look into. I wasn't able to quickly get it working for this example. But if you can't get something going, you can open a new post (showing what didn't work) – Tom Aug 13 '20 at 17:25
  • Will do @Tom thanks. I will keep working, and if I find a successful answer, then I will post it here for future reference. – stimsssss Aug 13 '20 at 20:27