I'm relatively new to programming, and I've tried using matplotlib's animation library to, quite obviously, animate. However, the animation I produce is really slow and discontinuous. The following code is an example of this, it does, however, involve a relatively large number of computations.
random_set is just a randomly generated set, temp_set serves to be a copy of random_set because I sort random_set later, and new_set just stores the values of the change in y and x that the animation will alter each point by. I've tried using transform on the ax.texts that might make it faster, but I learned that transform doesn't mean it in the traditional mathematics way; so I just resorted to constantly deleting and replotting these points. Is there any way to speed up the animation? I feel the entire piece of code is necessary to demonstrate the extent of the problem.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import random
import math
fig , ax = plt.subplots()
random_set = []
while len(random_set) != 99:
choice = random.randint(-100,100)
if choice in random_set:
pass
else:
random_set.append(choice)
print(random_set)
lengths = [(i,int(len(random_set) / i)) for i in range(1,int(len(random_set) ** (1/2) + 1)) if len(random_set) % i == 0][-1]
print(lengths)
counter = 0
temp_set = []
for i in random_set:
plt.text(*(counter % lengths[1],math.floor(counter / lengths[1])),i)
temp_set.append((i,counter % lengths[1],math.floor(counter / lengths[1])))
counter += 1
random_set.sort()
x_lims = (0,lengths[1])
y_lims = (0,lengths[0])
ax.set_xlim(*x_lims)
ax.set_ylim(*y_lims)
plt.axis("off")
new_set = []
for j in temp_set:
new_x = random_set.index(j[0]) / lengths[0]
random_set[random_set.index(j[0])] = None
new_y = (lengths[0] - 1) / 2
dy = (new_y - j[2]) / 250
dx = (new_x - j[1]) / 250
new_set.append((j[0],dx,dy))
def percentile(i):
ax.texts.clear()
for j in range(0,len(new_set)):
plt.text(temp_set[j][1] + (i * new_set[j][1]),temp_set[j][2] + (i * new_set[j][2]),new_set[j][0])
animate = animation.FuncAnimation(fig, func = percentile, frames = [i for i in range(1,251)], interval = 1,repeat = False)
plt.show()
Check this code:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import random
import math
fig , ax = plt.subplots()
N = 25
random_set = []
while len(random_set) != 99:
choice = random.randint(-100,100)
if choice in random_set:
pass
else:
random_set.append(choice)
print(random_set)
lengths = [(i,int(len(random_set) / i)) for i in range(1,int(len(random_set) ** (1/2) + 1)) if len(random_set) % i == 0][-1]
print(lengths)
counter = 0
temp_set = []
for i in random_set:
plt.text(*(counter % lengths[1],math.floor(counter / lengths[1])),i)
temp_set.append((i,counter % lengths[1],math.floor(counter / lengths[1])))
counter += 1
random_set.sort()
x_lims = (0,lengths[1])
y_lims = (0,lengths[0])
ax.set_xlim(*x_lims)
ax.set_ylim(*y_lims)
plt.axis("off")
new_set = []
for j in temp_set:
new_x = random_set.index(j[0]) / lengths[0]
random_set[random_set.index(j[0])] = None
new_y = (lengths[0] - 1) / 2
dy = (new_y - j[2]) / N
dx = (new_x - j[1]) / N
new_set.append((j[0],dx,dy))
def percentile(i):
ax.texts.clear()
for j in range(0,len(new_set)):
plt.text(temp_set[j][1] + (i * new_set[j][1]),temp_set[j][2] + (i * new_set[j][2]),new_set[j][0])
animate = animation.FuncAnimation(fig, func = percentile, frames = [i for i in range(1,N+1)], interval = 1, repeat = False)
plt.show()
I replaced your 250 with N (and 251 with N+1), then I set N = 25 in order to decrease the number of frames. This is the result:
Related
I'm using a thermal camera with Python code on my Raspberry Pi. I inserted some code yesterday that'll allow me to find the radius of where a fire is on the thermal camera and I'm going to output the theta in a different code.
What I'm having trouble with however is showcasing one output rather than a consistent output every second (or in respect to the refresh rate). Is there a way to accomplish this?
Here is my code below:
import time,board,busio
import numpy as np
import adafruit_mlx90640
import matplotlib.pyplot as plt
import math
extent = (-16, 16, -12.5, 12.5)
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000)
mlx = adafruit_mlx90640.MLX90640(i2c)
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_1_HZ
mlx_shape = (24,32)
plt.ion()
fig,ax = plt.subplots(figsize=(12,7))
therm1 = ax.imshow(np.zeros(mlx_shape),vmin=0, vmax=60, extent=extent)
cbar = fig.colorbar(therm1)
cbar.set_label('Temperature [$^{\circ}$C]', fontsize=14)
frame = np.zeros((2432,))
t_array = []
np.array
print("Starting loop")
while True:
t1 = time.monotonic()
try:
mlx.getFrame(frame)
data_array = (np.reshape(frame,mlx_shape))
therm1.set_data(np.reshape(frame,mlx_shape))
therm1.set_clim(vmin=np.min(data_array))
cbar.update_normal(therm1)
plt.title("Max")
plt.pause(0.001)
t_array.append(time.monotonic() - t1)
# fig.savefig('mlx90640_test_fliplr.png', dpi=300, facecolor = '#FCFCFC', bbox_inches='tight')
highest_num = data_array[0][0]
x = 0
y = 0
for i in range (len(data_array)):
for j in range(len(data_array[i])):
if data_array[x][y] < data_array[i][j]:
x = i
y = j
highest_num = data_array[i][j]
idx = np.argmax(data_array)
m, n = len(data_array), len(data_array[0])
r, c = m - (idx // n) - 1 , idx % n
y, x = r - (m // 2), c - (n // 2)
radius = math.sqrt( x x + y * y)
theta = math.atan(y/x)
theta = 180 * theta/math.pi
print("Radius", radius)
except ValueError:
continue
I am playing with the code in this tutorial of the Barnsley fern, and I would like the fern to be plotted slowly (not at once). Python is not comfortable, yet, and I see that the function plt.pause() may do the trick in some other answers; however, I don't know how to combine plt.pause() with plt.scatter() to obtain an animated gif effect. Would I have to incorporate plt.scatter within the for loop, for example?
# importing necessary modules
import matplotlib.pyplot as plt
from random import randint
# initializing the list
x = []
y = []
# setting first element to 0
x.append(0)
y.append(0)
current = 0
for i in range(1, 50000):
# generates a random integer between 1 and 100
z = randint(1, 100)
# the x and y coordinates of the equations
# are appended in the lists respectively.
# for the probability 0.01
if z == 1:
a = 0; b = 0; c = 0; d = 0.16; e = 0; f = 0
x.append(0)
y.append(d*(y[current]))
# for the probability 0.85
if z>= 2 and z<= 86:
a = 0.85; b = 0.04; c = -0.04; d = 0.85; e = 0; f = 1.6
x.append(a*(x[current]) + b*(y[current]))
y.append(c*(x[current]) + d*(y[current])+f)
# for the probability 0.07
if z>= 87 and z<= 93:
a = 0.2; b = -0.26; c = 0.23; d = 0.22; e = 0; f = 1.6
x.append(a*(x[current]) + b*(y[current]))
y.append(c*(x[current]) + d*(y[current])+f)
# for the probability 0.07
if z>= 94 and z<= 100:
a = -0.15; b = 0.28; c = 0.26; d = 0.24; e = 0; f = 0.44
x.append(a*(x[current]) + b*(y[current]))
y.append(c*(x[current]) + d*(y[current])+f)
current = current + 1
plt.figure(figsize=(10,10))
plt.scatter(x, y, s = 0.2, edgecolor ='green')
This is the desired effect:
I suggest you to use FuncAnimation from matplotlib.animation:
You can just a point in each frame. You just have to set axes limits to avoid figure to move:
fig, ax = plt.subplots(figsize=(10, 10))
ax.set_xlim(min(x), max(x))
ax.set_ylim(min(y), max(y))
def animation(i):
ax.scatter(x[i], y[i], s=0.2, edgecolor='green')
ani = FuncAnimation(fig, animation, frames=len(x))
plt.show()
EDIT
In case you want more points to be drawn at the same time e.g. 15:
fig, ax = plt.subplots(figsize=(10, 10))
ax.set_xlim(min(x), max(x))
ax.set_ylim(min(y), max(y))
nb_points = 15
# calculate number of frames needed:
# one more frame if remainder is not 0
nb_frames = len(x) // nb_points + (len(x) % nb_points != 0)
def animation(i):
i_from = i * nb_points
# are we on the last frame?
if i_from + nb_points > len(x) - 1:
i_to = len(x) - 1
else:
i_to = i_from + nb_points
ax.scatter(x[i_from:i_to], y[i_from:i_to], s=0.2, edgecolor='green')
ani = FuncAnimation(fig, animation, frames=nb_frames)
plt.show()
I am trying to plot sinc function in python in the same plot, which is basically a OFDM carrier signal, which will sums up in the second figure.
Can you tell me what is wrong. Here is the code snippet.
NoOfCarriers = 11
interval = math.pi/50
f = np.arange((-5*math.pi),(5*math.pi),interval)
fnoiseMax = 0.3
iMin = -(NoOfCarriers-1)//2
iMax = (NoOfCarriers-1)//2
csum = np.zeros(len(f))
fList = [];cList = []
ax = plt.subplot(111)
for i in range(iMin,iMax):
print("i = ", i)
fnoise = fnoiseMax*(np.random.uniform(-1,1))
fshift = (i * (1//math.pi) * math.pi) + fnoise
c = np.sinc(f - fshift)
csum = csum + c[i]
fList = [fList,fshift]
cList = [cList,max(c)]
ax.plot(f, c)
plt.grid(True)
plt.show()
Here is what i got :
Here is what i expected:
i don't know how to add stem function in python. basic math logic for the stem function stem((i * (1/pi) * pi) + fnoise,1)
updated plot after taking out plt.show from loop
Try to place plt.show out of the loop, like that:
import math
import numpy as np
import matplotlib.pyplot as plt
NoOfCarriers = 11
interval = math.pi/50
f = np.arange((-5*math.pi),(5*math.pi),interval)
fnoiseMax = 0.3
iMin = -(NoOfCarriers-1)//2
iMax = (NoOfCarriers-1)//2
csum = np.zeros(len(f))
fList = [];cList = []
ax = plt.subplot(111)
for i in range(iMin,iMax):
print("i = ", i)
fnoise = fnoiseMax*(np.random.uniform(-1,1))
fshift = (i * (1//math.pi) * math.pi) + fnoise
c = np.sinc(f - fshift)
csum = csum + c[i]
fList = [fList,fshift]
cList = [cList,max(c)]
ax.plot(f, c)
plt.grid(True)
plt.show()
The problem is triggering show function (blocking) when not all plots are on the ax.
I am new to python and in learning stages. I wanted to implement Particle Swarm Optimization(PSO) algorithm which I did by taking help from on-line materials and python tutorials. In PSO, a simple calculus problem is inferred i-e 100 * ((y - (x2))2) + ((1 - (x2))2). This problem is defined in a fitness function.
def fitness(x, y):
return 100 * ((y - (x**2))**2) + ((1 - (x**2))**2)
Now, I want to replace this simple calculus problem by simple first order Ordinary Differential Equation(ODE) by without changing existing function parameters (x,y) and want to return the value of dy_dx,y0 and t for further process.
# Define a function which calculates the derivative
def dy_dx(y, x):
return x - y
t = np.linspace(0,5,100)
y0 = 1.0 # the initial condition
ys = odeint(dy_dx, y0, t)`
In python odeint function is used for ODE which requires three essential parameters i-e func/model, y0( Initial condition on y (can be a vector) and t(A sequence of time points for which to solve for y) Example of odeint parameters.
I don't want to change its parameters because it will be difficult for me to make changes in algorithm.
For simplicity I pasted the full code below and my question is open to anyone if wants to modify the code with further parameters in General Best, Personal Best and r[i].
import numpy as np
from scipy.integrate import odeint
import random as rand
from scipy.integrate import odeint
from numpy import array
import matplotlib.pyplot as plt
def main():
#Variables
n = 40
num_variables = 2
a = np.empty((num_variables, n))
v = np.empty((num_variables, n))
Pbest = np.empty((num_variables, n))
Gbest = np.empty((1, 2))
r = np.empty((n))
for i in range(0, num_variables):
for j in range(0, n):
Pbest[i][j] = rand.randint(-20, 20)
a[i][j] = Pbest[i][j]
v[i][j] = 0
for i in range(0, n):
r[i] = fitness(a[0][i], a[1][i])
#Sort elements of Pbest
Order(Pbest, r, n)
Gbest[0][0] = Pbest[0][0]
Gbest[0][1] = Pbest[1][0]
generation = 0
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.grid(True)
while(generation < 1000):
for i in range(n):
#Get Personal Best
if(fitness(a[0][i], a[1][i]) < fitness(Pbest[0][i], Pbest[1][i])):
Pbest[0][i] = a[0][i]
Pbest[1][i] = a[1][i]
#Get General Best
if(fitness(Pbest[0][i], Pbest[1][i]) < fitness(Gbest[0][0], Gbest[0][1])):
Gbest[0][0] = Pbest[0][i]
Gbest[0][1] = Pbest[1][i]
#Calculate Velocity
Vector_Velocidad(n, a, Pbest, Gbest, v)
generation = generation + 1
print 'Generacion: ' + str(generation) + ' - - - Gbest: ' +str(Gbest)
line1 = ax.plot(a[0], a[1], 'r+')
line2 = ax.plot(Gbest[0][0], Gbest[0][1], 'g*')
ax.set_xlim(-10, 10)
ax.set_ylim(-10, 10)
fig.canvas.draw()
ax.clear()
ax.grid(True)
print 'Gbest: '
print Gbest
def Vector_Velocidad(n, a, Pbest, Gbest, v):
for i in range(n):
#Velocity in X
v[0][i] = 0.7 * v[0][i] + (Pbest[0][i] - a[0][i]) * rand.random() * 1.47 + (Gbest[0][0] - a[0][i]) * rand.random() * 1.47
a[0][i] = a[0][i] + v[0][i]
v[1][i] = 0.7 * v[1][i] + (Pbest[1][i] - a[1][i]) * rand.random() * 1.47 + (Gbest[0][1] - a[1][i]) * rand.random() * 1.47
a[1][i] = a[1][i] + v[1][i]
def fitness(x, y):
return 100 * ((y - (x**2))**2) + ((1 - (x**2))**2)
def Order(Pbest, r, n):
for i in range(1, n):
for j in range(0, n - 1):
if r[j] > r[j + 1]:
#Order the fitness
tempRes = r[j]
r[j] = r[j + 1]
r[j + 1] = tempRes
#Order las X, Y
tempX = Pbest[0][j]
Pbest[0][j] = Pbest[0][j + 1]
Pbest[0][j + 1] = tempX
tempY = Pbest[1][j]
Pbest[1][j] = Pbest[1][j + 1]
Pbest[1][j + 1] = tempY
if '__main__' == main():
main()
I am working on an octant search to find the n-number(e.g. 8) of points (+) closest to my circular point (o) in each octant. This would mean that my points (+) are reduced to only 64 (8 per octant).
The first thing I did is to divide my region into octants with my point (o) as reference.
data = array containing (x, y, z) for all points (+)
gdata = array containing (x, y) for point (o)
import tkinter as tk
from tkinter import filedialog
import pandas as pd
import numpy as np
from scipy.spatial.distance import cdist
from collections import defaultdict
root = tk.Tk()
root.withdraw()
file_path = filedialog.askopenfilename()
data = pd.read_excel(file_path)
data = np.array(data, dtype=np.float)
nrow, cols = data.shape
file_path1 = filedialog.askopenfilename()
gdata = pd.read_excel(file_path1)
gdata = np.array(gdata, dtype=np.float)
pwangle = np.zeros(nrow)
for j in range(nrow):
delta_x = gdata[:,0]-data[:,0][j]
delta_y = gdata[:,1]-data[:,1][j]
if delta_x != 0:
pwangle[j] = np.rad2deg(np.arctan(delta_y/delta_x))
else:
if delta_y > 0:
pwangle[j] = 90
elif delta_y < 0:
pwangle[j] = 270
if (delta_x < 0)&(delta_y > 0):
pwangle[j] = 180 + pwangle[j]
elif (delta_x < 0)&(delta_y < 0):
pwangle[j] = 270 - pwangle[j]
elif (delta_x > 0)&(delta_y < 0):
pwangle[j] = 360 + pwangle[j]
vecangle = pwangle.ravel()
sortdata = defaultdict(list)
count = -1
get_anglesector = 45
N = 8
d = cdist(data[:,:2], gdata)
P = np.hstack((data, d))
for j in range(0, 360, get_anglesector):
count += 1
get_data = []
for k, dummy_val in enumerate(vecangle):
if j <= vecangle[k] < j + get_anglesector:
get_data.append(P[k,::])
sortdata[count] = np.array(get_data)
After data have been grouped into various octant, I then sort data in each octant to obtain the closest 8 data to the point (o).
for i, j in enumerate(sortdata):
octantsort = defaultdict(list)
for i in range(8):
octantsort[i] = np.array(sortdata[i][sortdata[i][:,3].argsort()[:N]])
Is there an efficient and pythonic way of doing this do increase performance?
This works fine but when i have more than one 'o' point (e.g. 10000 points 'o') and I have run the above code for each point, it would be time consuming.
The job gets a lot easier if you use arctan2 instead of arctan. Then vectorizing for speed we may get something like this:
import numpy as np
from scipy.spatial.distance import cdist
delta = gdata - data[:,:2]
angles = np.arctan2(delta[:,1], delta[:,0])
bins = np.linspace(-np.pi, np.pi, 9)
bins[-1] = np.inf # handle edge case
octantsort = []
for i in range(8):
data_i = data[(bins[i] <= angles) & (angles < bins[i+1])]
dist_order = np.argsort(cdist(data_i, gdata))
octantsort.append(data_i[dist_order[:N]])
Thank you #user7138814, apart from making some slight changes, your code is faster
N=8
delta = gdata - data[:,:2]
angles = np.arctan2(delta[:,1], delta[:,0])
bins = np.linspace(-np.pi, np.pi, 9)
bins[-1] = np.inf # handle edge case
octantsort = []
for i in range(8):
data_i = data[(bins[i] <= angles) & (angles < bins[i+1])]
dist_order = np.argsort(cdist(data_i[:,:2], gdata), axis=0)
[octantsort.append(data_i[dist_order[:N][j]]) for j in range(8)]
final = np.vstack(octantsort)
Time of execution of the previous code (code in the question):
---- 0.021449804306030273 seconds ------
Time of execution of the code in this post:
---- 0.0015172958374023438 seconds ------