Matplotlib scatter plot animation keeps crashing Python - python

I've found some flaky resources online about what to do when a matplotlib animation crashes Python.
Here is the code. I know that certain changes to the number of points or smallness of the dt variable might cause some overwhelming computation, but I could really use some help. Overall it behaves extremely slowly and I need to have this running smoothly. The code is for a physics class and it is not an optimization problem - the goal of the project is not to optimize matplotlib's animation facilities but to model a system in phase space. I could use any help I can get.
import matplotlib
#matplotlib.use("TkAgg")
from matplotlib import animation
import matplotlib.pyplot as plt
import matplotlib.pylab as pl
import numpy as np
import math
# Create the window and the plot.
fig = plt.figure()
fig.canvas.set_window_title("Modelling Non-Linear Chaotic Systems in Phase ")
ax = fig.add_subplot(111)
##### CONSTANTS #####
NUM_POINTS = 40 # The number of points to discretize.
AUTOSCALE = False # Sets autoscale to true or false. If true, there will be odd (expected to a degree) behavior as time goes on.
NO_TRAIL = False # Adds a trail.
##### CONSTANTS #####
##### Cool Settings #####
# Double tail swirl.
# k = .2
# alpha = .4
# dt = .1
##### #####
##### VARIABLES #####
m = 1 # mass constant
k = 5 # spring constant
alpha = .3 # stretch/deformation constant
dt = .01 # change in time
interval = 100 # interval in milliseconds between each animation
##### VARIABLES #####
class Point():
def x():
return self.x
def y():
return self.y
def pos(xy):
self.x=xy[0]
self.y=xy[1]
# initial_pos is a tuple
def __init__(self, initial_pos):
self.initial_position = initial_pos
self._x = initial_pos[0]
self._y = initial_pos[1]
self.x = self._x
self.y = self._y
def evolve(x_map, y_map, l):
return [Point([x_map(el), y_map(el)]) for el in l]
"""
Lagrangian
L = T - V = .5dq^2 - .5kq^2 - .333alpha*q^3
p = mdq; dx = p/m
Hamiltonian
H = p^2/m - L
H = p^2/m - p^2/2m + .5kq^2 + .333alpha*q^3
dp = -partial(H)/partial(q) = -kq - alpha*q^2
dx = partial(H)/partial(p) = p/m
"""
def time_dependent_funcs(name, dt):
### This is the adjustment of p over time. ###
def p_map(point):
p = point.y
q = point.x
try:
dp = -1*k*q-alpha*q**2
ddp = -k*p/m-alpha*q*p/m
return p+dp*dt+ddp*dt**2
except:
return p
### End adjustment of p. ###
### This is the adjustment of q over time. ###
def q_map(point):
q = point.x
p = point.y
try:
dq = p/m
dp = -1*k*q-alpha*q**2
ddp = -k*p/m-alpha*q*p/m
return q+dq*dt+ddp*dt**2/m
except:
return q
### End adjustment of q. ###
if name == "p_map":
return p_map
elif name == "q_map":
return q_map
# Used this post to help create this function: http://stackoverflow.com/questions/14619876/how-do-i-generate-pair-of-random-points-in-a-circle-using-matlab
def circle(r, n):
l = []
for i in range(n):
x=r+1 # necessary to enter loop
y=r+1 # necessary to enter loop
while (x**2 + y**2) > r**2:
x = 2*r*np.random.randn()
y = 2*r*np.random.randn()
l.append(Point([x,y]))
return l
### DOESN'T CURRENTLY WORK
def square(h, n):
l = []
for i in range(n):
x=h+1 # necessary to enter loop
y=h+1 # necessary to enter loop
while x < h and y < h:
x = np.random.randn()
y = np.random.randn()
l.append(Point([x,y]))
return l
def rand(n):
return [Point([np.random.randn(),np.random.randn()]) for i in range(n)]
def x(l):
return [el.x for el in l]
def y(l):
return [el.y for el in l]
#list_of_points = rand(NUM_POINTS) # works
#list_of_points = square(.2, 400) # doesn't currently work
list_of_points = circle(20,NUM_POINTS) # need this to be a global
def init():
global list_of_points, dt
scat = ax.scatter(x(list_of_points), y(list_of_points),color="blue", animated=NO_TRAIL)
if NO_TRAIL:
return scat,
def animate(i):
global list_of_points, dt
map_p = time_dependent_funcs("p_map", dt)
map_q = time_dependent_funcs("q_map", dt)
### evolve the points ###
list_of_points = evolve(map_q, map_p, list_of_points)
scat = ax.scatter(x(list_of_points), y(list_of_points), color="blue",lw=2, animated=NO_TRAIL)
if NO_TRAIL:
return scat,
### Animates the figure fig by executing init_func init (initially) followed by animation function
### animate for 10 frames at an interval of 100ms all the while erasing the last animation (blit=True).
ani = animation.FuncAnimation(fig, animate, init_func=init, frames = 100, interval=interval,blit=NO_TRAIL,save_count=0)
if not AUTOSCALE:
plt.autoscale(enable=False)
plt.show()

Related

I'm trying to render a 3D Mandelbulb (in Blender) using a Python script, and it doesn't look right

Currently my code returns no errors, and generates a weird looking set of points, totally not a Mandelbulb. I've looked over the formulas multiple times and everything seems right, but I could definitely be overlooking something. Any ideas? Just to note, I'm quite inexperienced with Python (I work in Java a lot though so I get the main ideas). Here's my code:
import bpy
import numpy as np
import math
def mandelbulb(x, y, z, iterations):
c = x + y*1j + z*1j
z = c
r = 0
for i in range(iterations):
r2 = x*x + y*y + z*z
if r2 > 2:
return math.sqrt(r2)
theta = math.atan2(math.sqrt(x*x + y*y), z)
phi = math.atan2(y, x)
r = math.sqrt(abs(x*x + y*y + z*z))
x = r*r*r*r * math.cos(4*theta) * math.cos(4*phi) + c.real
y = r*r*r*r * math.cos(4*theta) * math.sin(4*phi) + c.imag
z = r*r*r*r * math.sin(4*theta)
return 0
def generate_mesh(size, iterations):
vertices = []
for x in np.linspace(-2, 2, size):
for y in np.linspace(-2, 2, size):
for z in np.linspace(-2, 2, size):
value = mandelbulb(x, y, z, iterations)
if value >= 2:
vertices.append((x, y, z))
return vertices, []
def create_mesh_object(vertices, faces, name):
mesh = bpy.data.meshes.new(name)
mesh.from_pydata(vertices, [], faces)
mesh.update()
object = bpy.data.objects.new(name, mesh)
bpy.context.collection.objects.link(object)
def execute(size, iterations):
vertices, faces = generate_mesh(size, iterations)
create_mesh_object(vertices, faces, "Mandelbulb")
class MandelbulbOperator(bpy.types.Operator):
bl_idname = "object.mandelbulb_operator"
bl_label = "Mandelbulb Operator"
bl_options = {'REGISTER', 'UNDO'}
size: bpy.props.IntProperty(
name="Size",
default=32,
min=1,
max=256,
step=1
)
iterations: bpy.props.IntProperty(
name="Iterations",
default=64,
min=1,
max=512,
step=1
)
def execute(self, context):
execute(self.size, self.iterations)
return {'FINISHED'}
def draw(self, context):
layout = self.layout
layout.label(text="Create a 3D Mandelbulb")
layout.prop(self, "size")
layout.prop(self, "iterations")
def register():
bpy.utils.register_class(MandelbulbOperator)
def unregister():
bpy.utils.unregister_class(MandelbulbOperator)
if __name__ == "__main__":
register()
I tried messing with values, such as size and iterations but nothing seemed to change the look of the result, and changing the iterations straight up did nothing. I've also tried using variations on the main Mandelbulb formula but to no avail. Any suggestions are welcome.

Adding name and history attribute to 2D particle simulation

I am attempting to create a program which simulates particles colliding in a 2D box, but each particle is labeled with a random 5 character string name and each collision is tracked in a list along each particle. So after the simulation, I would like a list from each particle listing which particles it has hit. I have forked this great simulation https://github.com/xnx/collision and added the name and history attributes to the particle class. However, whenever I attempt to access .name or .history, my kernel dies. The output says:
Kernel died, restarting
Restarting kernel...
The failure happens in the handle_collisions function (line 197), or whenever I try to access the history or the name, so there must be something wrong in my implementation of the name and history attributes. I have also tried to instantiate name and history in the init_particles function instead of place_particles but that had the same results. I'm not exactly sure how to correctly implement them. Thanks for your help.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from matplotlib import animation
from itertools import combinations
import random
import string
class Particle:
"""A class representing a two-dimensional particle."""
def __init__(self, x, y, vx, vy, name, history, radius=0.01, styles=None):
"""Initialize the particle's position, velocity, name, history and radius.
Any key-value pairs passed in the styles dictionary will be passed
as arguments to Matplotlib's Circle patch constructor.
"""
self.r = np.array((x, y))
self.v = np.array((vx, vy))
self.radius = radius
self.mass = self.radius**2
self.styles = styles
if not self.styles:
# Default circle styles
self.styles = {'edgecolor': 'b', 'fill': False}
# For convenience, map the components of the particle's position and
# velocity vector onto the attributes x, y, vx and vy.
#property
def x(self):
return self.r[0]
#x.setter
def x(self, value):
self.r[0] = value
#property
def y(self):
return self.r[1]
#y.setter
def y(self, value):
self.r[1] = value
#property
def vx(self):
return self.v[0]
#vx.setter
def vx(self, value):
self.v[0] = value
#property
def vy(self):
return self.v[1]
#vy.setter
def vy(self, value):
self.v[1] = value
#property
def history(self):
return self.history
#history.setter
def history(self,value):
self.history=value
#property
def name(self):
return self.name
#name.setter
def name(self,value):
self.name=value
def overlaps(self, other):
"""Does the circle of this Particle overlap that of other?"""
return np.hypot(*(self.r - other.r)) < self.radius + other.radius
def draw(self, ax):
"""Add this Particle's Circle patch to the Matplotlib Axes ax."""
circle = Circle(xy=self.r, radius=self.radius, **self.styles)
ax.add_patch(circle)
return circle
def advance(self, dt):
"""Advance the Particle's position forward in time by dt."""
self.r += self.v * dt
class Simulation:
"""A class for a simple hard-circle molecular dynamics simulation.
The simulation is carried out on a square domain: 0 <= x < 1, 0 <= y < 1.
"""
ParticleClass = Particle
def __init__(self, n, radius=0.01, styles=None):
"""Initialize the simulation with n Particles with radii radius.
Each particle is initialized with a 10 letter string name and an empty history.
radius can be a single value or a sequence with n values.
Any key-value pairs passed in the styles dictionary will be passed
as arguments to Matplotlib's Circle patch constructor when drawing
the Particles.
"""
self.init_particles(n, radius, styles)
self.dt = 0.01
def place_particle(self, rad, styles):
# Choose x, y so that the Particle is entirely inside the
# domain of the simulation.
x, y = rad + (1 - 2*rad) * np.random.random(2)
# Choose a random velocity (within some reasonable range of
# values) for the Particle.
vr = 0.1 * np.sqrt(np.random.random()) + 0.05
vphi = 2*np.pi * np.random.random()
vx, vy = vr * np.cos(vphi), vr * np.sin(vphi)
name = self.assignname
history = []
particle = self.ParticleClass(x, y, vx, vy, name, history, rad, styles)
# Check that the Particle doesn't overlap one that's already
# been placed.
for p2 in self.particles:
if p2.overlaps(particle):
break
else:
self.particles.append(particle)
return True
return False
def assignname(self):
letters = string.ascii_lowercase
name=''.join(random.choice(letters) for i in range(5))
return name
def init_particles(self, n, radius, styles=None):
"""Initialize the n Particles of the simulation.
Positions and velocities are chosen randomly; radius can be a single
value or a sequence with n values.
"""
try:
iterator = iter(radius)
assert n == len(radius)
except TypeError:
# r isn't iterable: turn it into a generator that returns the
# same value n times.
def r_gen(n, radius):
for i in range(n):
yield radius
radius = r_gen(n, radius)
self.n = n
self.particles = []
for i, rad in enumerate(radius):
# Try to find a random initial position for this particle.
while not self.place_particle(rad, styles):
pass
def change_velocities(self, p1, p2):
"""
Particles p1 and p2 have collided elastically: update their
velocities.
"""
m1, m2 = p1.mass, p2.mass
M = m1 + m2
r1, r2 = p1.r, p2.r
d = np.linalg.norm(r1 - r2)**2
v1, v2 = p1.v, p2.v
u1 = v1 - 2*m2 / M * np.dot(v1-v2, r1-r2) / d * (r1 - r2)
u2 = v2 - 2*m1 / M * np.dot(v2-v1, r2-r1) / d * (r2 - r1)
p1.v = u1
p2.v = u2
def handle_collisions(self):
"""Detect and handle any collisions between the Particles.
When two Particles collide, they do so elastically: their velocities
change such that both energy and momentum are conserved.
"""
# We're going to need a sequence of all of the pairs of particles when
# we are detecting collisions. combinations generates pairs of indexes
# into the self.particles list of Particles on the fly.
#particles share history when they collide
pairs = combinations(range(self.n), 2)
for i,j in pairs:
if self.particles[i].overlaps(self.particles[j]):
self.change_velocities(self.particles[i], self.particles[j])
#FAILS HERE
#self.particles[i].history.append(self.particles[j].name)
#self.particles[j].history.append(self.particles[i].name)
def handle_boundary_collisions(self, p):
"""Bounce the particles off the walls elastically."""
if p.x - p.radius < 0:
p.x = p.radius
p.vx = -p.vx
if p.x + p.radius > 1:
p.x = 1-p.radius
p.vx = -p.vx
if p.y - p.radius < 0:
p.y = p.radius
p.vy = -p.vy
if p.y + p.radius > 1:
p.y = 1-p.radius
p.vy = -p.vy
def apply_forces(self):
"""Override this method to accelerate the particles."""
pass
def advance_animation(self):
"""Advance the animation by dt, returning the updated Circles list."""
for i, p in enumerate(self.particles):
p.advance(self.dt)
self.handle_boundary_collisions(p)
self.circles[i].center = p.r
self.handle_collisions()
self.apply_forces()
return self.circles
def advance(self):
"""Advance the animation by dt."""
for i, p in enumerate(self.particles):
p.advance(self.dt)
self.handle_boundary_collisions(p)
self.handle_collisions()
self.apply_forces()
def init(self):
"""Initialize the Matplotlib animation."""
self.circles = []
for particle in self.particles:
self.circles.append(particle.draw(self.ax))
return self.circles
def animate(self, i):
"""The function passed to Matplotlib's FuncAnimation routine."""
self.advance_animation()
return self.circles
def setup_animation(self):
self.fig, self.ax = plt.subplots()
for s in ['top','bottom','left','right']:
self.ax.spines[s].set_linewidth(2)
self.ax.set_aspect('equal', 'box')
self.ax.set_xlim(0, 1)
self.ax.set_ylim(0, 1)
self.ax.xaxis.set_ticks([])
self.ax.yaxis.set_ticks([])
def save_or_show_animation(self, anim, save, filename='collision.mp4'):
if save:
Writer = animation.writers['ffmpeg']
writer = Writer(fps=10, bitrate=1800)
anim.save(filename, writer=writer)
else:
plt.show()
def do_animation(self, save=False, interval=1, filename='collision.mp4'):
"""Set up and carry out the animation of the molecular dynamics.
To save the animation as a MP4 movie, set save=True.
"""
self.setup_animation()
anim = animation.FuncAnimation(self.fig, self.animate,
init_func=self.init, frames=800, interval=interval, blit=True)
self.save_or_show_animation(anim, save, filename)
if __name__ == '__main__':
nparticles = 20
radii = .02
styles = {'edgecolor': 'C0', 'linewidth': 2, 'fill': None}
sim = Simulation(nparticles, radii, styles)
sim.do_animation(save=False)
I see two immediate problems in your code.
First: you did add history as a Particle.__init__ parameter but you never initialize the property itself.
Add something like this:
def __init__(self, x, y, vx, vy, name, history, radius=0.01, styles=None):
self._history = history
And bigger problem: you have an infinite recursion in your #property definition:
#property
def history(self):
return self.history
#history.setter
def history(self,value):
self.history=value
So in your getter you called history you call itself return self.history which will loop itself until program will crash.
Rename internal property to _history:
#property
def history(self):
return self._history
#history.setter
def history(self,value):
self._history=value

How to run a python program 10 times in a loop and plot the rsults in each time

I am trying to run this code. We run the EM for 10 loops and plot the result in each loop. You want to observe the progress for each EM loop below.
X = np.linspace(-5,5,num=20)
X0 = X*np.random.rand(len(X))+10 # Create data cluster 1
X1 = X*np.random.rand(len(X))-10 # Create data cluster 2
X2 = X*np.random.rand(len(X)) # Create data cluster 3
X_tot = np.stack((X0,X1,X2)).flatten() # Combine the clusters to get the random datapoints from above
class GMD:
def __init__(self,X,iterations):
self.iterations = iterations
self.X = X
self.mu = None
self.pi = None
self.var = None
def run(self):
self.mu = [-8,8,5]
self.pi = [1/3,1/3,1/3]
self.var = [5,3,1]
for iter in range(self.iterations):
r = np.zeros((len(X_tot),3))
for c,g,p in zip(range(3),[norm(loc=self.mu[0],scale=self.var[0]),
norm(loc=self.mu[1],scale=self.var[1]),
norm(loc=self.mu[2],scale=self.var[2])],self.pi):
r[:,c] = p*g.pdf(X_tot)
for i in range(len(r)):
r[i] = r[i]/(np.sum(pi)*np.sum(r,axis=1)[i])
"""Plot the data"""
fig = plt.figure(figsize=(10,10))
ax0 = fig.add_subplot(111)
for i in range(len(r)):
ax0.scatter(self.X[i],0,c=np.array([r[i][0],r[i][1],r[i][2]]),s=100)
"""Plot the gaussians"""
for g,c in zip([norm(loc=self.mu[0],scale=self.var[0]).pdf(np.linspace(-20,20,num=60)),
norm(loc=self.mu[1],scale=self.var[1]).pdf(np.linspace(-20,20,num=60)),
norm(loc=self.mu[2],scale=self.var[2]).pdf(np.linspace(-20,20,num=60))],['r','g','b']):
ax0.plot(np.linspace(-20,20,num=60),g,c=c)
var_c.append((1/m_c[c])*np.dot(((np.array(r[:,c]).reshape(60,1))*(self.X.reshape(len(self.X),1)-self.mu[c])).T,(self.X.reshape(len(self.X),1)-self.mu[c])))
plt.show()
GMD = GMD(X_tot,10)
GMD.run()
But after running this code it's showing this below error as a output
this message showing when I am going to run this code
You could make another file and import your class and do:
for x in range(0,9):
class.function()
I'm unable to reply to Klaus' answer but as he pointed out, you might have missed self while calling the pi value on one occasion:
for i in range(len(r)):
r[i] = r[i]/(np.sum(pi)*np.sum(r,axis=1)[i]) # Here the pi should be self.pi

Python file generates points to plot - RuntimeError

UPDATED:
I would like to plot real time y values generated randomly from Random_Generation_List.py. I have imported the python file and have them in the same folder. The points are only being printed and show only a vertical line on the graph. How do I fix this to make the points plot onto the graph in real time? Like a point every 0.001?
Random_Generation_List:
import random
import threading
def main():
for count in range(12000):
y = random.randint(0,1000)
print(y)
def getvalues():
return [random.randint(0,1000) for count in range(12000)]
def coordinate():
threading.Timer(0.0001, coordinate).start ()
coordinate()
main()
Real_Time_Graph
import time
from collections import deque
from matplotlib import pyplot as plt
from matplotlib import style
import Random_Generation_List
start = time.time()
class RealtimePlot:
def __init__(self, axes, max_entries = 100):
self.axis_x = deque(maxlen=max_entries)
self.axis_y = deque(maxlen=max_entries)
self.axes = axes
self.max_entries = max_entries
self.lineplot, = axes.plot([], [], "g-")
self.axes.set_autoscaley_on(True)
def add(self, x, y):
self.axis_x.append(x)
self.axis_y.append(y)
self.lineplot.set_data(self.axis_x, self.axis_y)
self.axes.set_xlim(self.axis_x[0], self.axis_x[-1] + 1e-15)
self.axes.relim(); self.axes.autoscale_view() # rescale the y-axis
def animate(self, figure, callback, interval = 50):
def wrapper(frame_index):
self.add(*callback(frame_index))
self.axes.relim(); self.axes.autoscale_view() # rescale the y-axis
return self.lineplot
def main():
style.use('dark_background')
fig, axes = plt.subplots()
display = RealtimePlot(axes)
axes.set_xlabel("Seconds")
axes.set_ylabel("Amplitude")
values = Random_Generation_List.getvalues()
print(values)
while True:
display.add(time.time() - start, values)
plt.pause(0.001)
display.animate(fig, lambda frame_index: (time.time() - start, values))
plt.show()
if __name__ == "__main__": main()
Error Message:
raise RuntimeError('xdata and ydata must be the same length')
RuntimeError: xdata and ydata must be the same length

Particle instance has no attribute '__getitem__'

I am coding basic PSO (particle swarm optimization) and have been getting this error that particle instance has no attribute __getitem__. I think everything is fine but the particle class seems to have some error. Take a look at the particle class.
from numpy import array
from random import random
from math import sin, sqrt, cos, pi
import matplotlib.pyplot as plt
import pylab
## Settings
c1 = 2
c2 = 2
size = 100
bad_size = 10
dim = 10
max_iterations = 20
Error_limit = 0.00001
def functR(k):
val = 10*dim
for i in range(dim):
val = val + (k[i])**2 - 10*cos(2*pi*k[i])
return val
#print functR([0]*20)
class particle():
def __init__(self, pos, fitness,vel, pbestpos, pbestfit):
self.pos = pos
self.fitness = fitness
self.vel = vel
self.pbestpos = pbestpos
self.pbestfitness = pbestfit
class swarm():
def __init__(self, size, bad_size, dim):
#self.gbest = gbest
self.size = size
self.bad_size = bad_size
self.dim = dim
def create(self):
particles = []
for i in range(size + bad_size):
p = particle()
p.pos = array([random() for i in range(dim)])
p.vel = 0.0
p.fitness = 0.0
p.pbestpos = p.pos
p.pbestfit = p.fitness
#p = particle(pos, fitness,vel, pbestpos, pbestfit)
particles.append(p)
return particles
def optimizer():
s = swarm(size, bad_size, dim)
new_swarm = s.create()
gbest = new_swarm[0]
gbestfit = functR(gbest)
i = 0
## The iterative loop
while i < max_iterations:
for p in s:
fitness = functR(p.pos)
if fitness > p.fitness:
p.fitness = fitness
p.pbestpos = p.pos
if fitness > gbestfit:
gbest = p
## Plotting
pylab.xlim([0,10])
pylab.ylim([0,1.5])
plt.plot(i,gbest.fitness, "bo")
## Velocity and Position update
vel = p.vel + c1 * random() * (p.pbestpos - p.pos) \
+ c2 * random() * (gbest.pos - p.pos)
p.pos = p.pos + vel
plt.show()
i += 1
print "gbest fitness :", gbestfit
print "Best particle :", gbest.pos
print optimizer()
You are treating a single particle() instance as a list here:
val = val + (k[i])**2 - 10*cos(2*pi*k[i])
k is an instance of particle(), the [i] syntax translates to a __getitem__ call on that instance.
You are passing in that instance here:
gbest = new_swarm[0]
gbestfit = functR(gbest)
while elsewhere you pass in the .pos parameter instead:
for p in s:
fitness = functR(p.pos)
so perhaps you meant to do the same for the gbestfit line:
gbest = new_swarm[0]
gbestfit = functR(gbest.pos)

Categories