for loop plotting in python - python

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.

Related

Could someone help me with creating a single output after a delay from my code?

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

How do you smoothen matplotlib animations?

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:

How to make points in plt.scatter() appear one at a time on display?

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()

What is the cause of the artifacts of this convoluted signal?

I am trying to find out the cause of the artifacts that appear after convolution, they are to be seen in the plot arround x = -.0016 and x= .0021 (please see the code below). I am convoluting the "lorentzian" function (or the derivative of the langevin function) which I define in the code, with 2 Dirac impulses in the function "ditrib".
I would appreciate your help.
Thank you
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
def Lorentzian(xx):
if not hasattr(xx, '__iter__'):
xx = [ xx ]
res = np.zeros(len(xx))
for i in range(len(xx)):
x = xx[i]
if np.fabs(x) < 0.1:
res[i] = 1./3. - x**2/15. + 2.* x**4 / 189. - x**6/675. + 2.* x**8 / 10395. - 1382. * x**10 / 58046625. + 4. * x**12 / 1403325.
else:
res[i] = (1./x**2 - 1./np.sinh(x)**2)
return res
amp = 18e-3
a = 1/.61e3
b = 5.5
t_min = 0
dt = 1/5e6
t_max = (10772) * dt
t = np.arange(t_min,t_max,dt)
x_min = -amp/b
x_max = amp/b
dx = dt*(x_min-x_max)/(t_min-t_max)
x = np.arange(x_min,x_max,dx)
func1 = lambda x : Lorentzian(b*(x/a))
def distrib(x):
res = np.zeros(np.size(x))
res[int(np.floor(np.size(x)/3))] = 1
res[int(3*np.floor(np.size(x)/4))] = 3
return res
func2 = lambda x,xs : np.convolve(distrib(x), func1(xs), 'same')
plt.plot(x, func2(x,x))
plt.xlabel('x (m)')
plt.ylabel('normalized signal')
try removing the "pedestal" of func1
func1(x)[0], func1(x)[-1]
Out[7]: (0.0082945964013920719, 0.008297677313152443)
just subtract
func2 = lambda x,xs : np.convolve(distrib(x), func1(xs)-func1(x)[0], 'same')
gives a smooth convolution curve
depending on the result you want you may have to add it back in after, weighted by the Dirac sum

How to pack spheres in python?

I am trying to model random closed packing spheres of uniform size in a square using python. And the spheres should not overlap but I do not know how to do this
I have so far:
Code:
import random, math, pylab
def show_conf(L, sigma, title, fname):
pylab.axes()
for [x, y] in L:
for ix in range(-1, 2):
for iy in range(-1, 2):
cir = pylab.Circle((x + ix, y + iy), radius=sigma, fc='r')
pylab.gca().add_patch(cir)
pylab.axis('scaled')
pylab.xlabel('eixo x')
pylab.ylabel('eixo y')
pylab.title(title)
pylab.axis([0.0, 1.0, 0.0, 1.0])
pylab.savefig(fname)
pylab.close()
L = []
N = 8 ** 2
for i in range(N):
posx = float(random.uniform(0, 1))
posy = float(random.uniform(0, 1))
L.append([posx, posy])
print L
N = 8 ** 2
eta = 0.3
sigma = math.sqrt(eta / (N * math.pi))
Q = 20
ltilde = 5*sigma
N_sqrt = int(math.sqrt(N) + 0.5)
titulo1 = '$N=$'+str(N)+', $\eta =$'+str(eta)
nome1 = 'inicial'+'_N_'+str(N) + '_eta_'+str(eta) + '.png'
show_conf(L, sigma, titulo1, nome1)
This is a very hard problem (and probably np-hard). There should be a lot of ressources available.
Before i present some more general approach, check out this wikipedia-site for an overview of the currently best known packing-patterns for some N (N circles in a square).
You are lucky that there is an existing circle-packing implementation in python (heuristic!) which is heavily based on modern optimization-theory (difference of convex-functions + Concave-convex-procedure).
The method used is described here (academic paper & link to software; 2016!)
The software package used is here
There is an example directory with circle_packing.py (which is posted below together with the output)
The following example also works for circles of different shapes
Example taken from the above software-package (example by Xinyue Shen)
__author__ = 'Xinyue'
from cvxpy import *
import numpy as np
import matplotlib.pyplot as plt
import dccp
n = 10
r = np.linspace(1,5,n)
c = Variable(n,2)
constr = []
for i in range(n-1):
for j in range(i+1,n):
constr.append(norm(c[i,:]-c[j,:])>=r[i]+r[j])
prob = Problem(Minimize(max_entries(max_entries(abs(c),axis=1)+r)), constr)
#prob = Problem(Minimize(max_entries(normInf(c,axis=1)+r)), constr)
prob.solve(method = 'dccp', ccp_times = 1)
l = max_entries(max_entries(abs(c),axis=1)+r).value*2
pi = np.pi
ratio = pi*sum_entries(square(r)).value/square(l).value
print "ratio =", ratio
print prob.status
# plot
plt.figure(figsize=(5,5))
circ = np.linspace(0,2*pi)
x_border = [-l/2, l/2, l/2, -l/2, -l/2]
y_border = [-l/2, -l/2, l/2, l/2, -l/2]
for i in xrange(n):
plt.plot(c[i,0].value+r[i]*np.cos(circ),c[i,1].value+r[i]*np.sin(circ),'b')
plt.plot(x_border,y_border,'g')
plt.axes().set_aspect('equal')
plt.xlim([-l/2,l/2])
plt.ylim([-l/2,l/2])
plt.show()
Output
Modification for your task: equal-sized circles
Just replace:
r = np.linspace(1,5,n)
With:
r = [1 for i in range(n)]
Output
Fun example with 64 circles (this will take some time!)
If you would like a more updated version of #leopold.talirz solution, I suggest you use the following:
from cvxpy import *
import numpy as np
import matplotlib.pyplot as plt
import dccp
n = 10
r = np.linspace(1,5,n)
c = Variable(shape=(n,2))
constr = []
for i in range(n-1):
for j in range(i+1,n):
constr.append(norm(c[i,:]-c[j,:])>=r[i]+r[j])
prob = Problem(Minimize(max(max(abs(c),axis=1)+r)), constr)
#prob = Problem(Minimize(max_entries(normInf(c,axis=1)+r)), constr)
prob.solve(method = 'dccp', ccp_times = 1)
l = max(max(abs(c),axis=1)+r).value*2
pi = np.pi
ratio = pi*sum(square(r)).value/square(l).value
print("ratio =", ratio)
print(prob.status)
# plot
plt.figure(figsize=(5,5))
circ = np.linspace(0,2*pi)
x_border = [-l/2, l/2, l/2, -l/2, -l/2]
y_border = [-l/2, -l/2, l/2, l/2, -l/2]
for i in range(n):
plt.plot(c[i,0].value+r[i]*np.cos(circ),c[i,1].value+r[i]*np.sin(circ),'b')
plt.plot(x_border,y_border,'g')
plt.axes().set_aspect('equal')
plt.xlim([-l/2,l/2])
plt.ylim([-l/2,l/2])
plt.show()

Categories

Resources