Python only plots last curve in a loop - python

I have a curve that I want to rotate along the z-axis N times in a loop, and each time I want to plot it to the same figure. However I only get the last curve overdrawn multiple times. If instead, I use different figures in every iteration I get the expected result. Where is the mistake? This is the code, the comments are to test creating new figures in each iteration:
o = 2*pi/N
for m in range(N):
#fig = plt.figure()
#ax = fig.add_subplot(111, projection='3d')
#ax.view_init(45,)
#fig.set_size_inches(10,10)
for n in range(len(x1)):
x1[n],y1[n] = cos(o)*x1[n] - sin(o)*y1[n], sin(o)*x1[n] + cos(o)*y1[n]
ax.plot(x1,y1,z1,'k')
#plt.show()
This is what I want more or less, that I've achieved using a diferent method:
but instead i get:
Here is how I calculate x1,y1,z1 if someone wants to test it
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from numpy import array, linspace
from math import pi, cos, sin, atan2, sqrt
def pltcono(xo,yo,a):
N = 100
x1 = []
y1 = []
z1 = []
for t in linspace(0,1,N):
x = (xo[1]-xo[0])*t + xo[0]
y = (yo[1]-yo[0])*t + yo[0]
r = sqrt(x**2 + y**2)
if (r > 1.0000000001):
return x1,y1,z1
o = atan2(y,x)
x1 += [a*r/(2*pi)*cos(2*pi*o/a)]
y1 += [a*r/(2*pi)*sin(2*pi*o/a)]
z1 += [-r*sqrt(1-(a/(2*pi))**2)]
return x1,y1,z1
def cono(a):
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.view_init(45,)
fig.set_size_inches(10,10)
o = a/2
r = 1
N = 10
p = a/10
x = [r*cos(p)]
y = [r*sin(p)]
x += [r*sin(o-p)/sin(o)]
y += [0]
x1,y1,z1 = pltcono(x,y,a)
while (o + a < pi):
o+= a
x[0] = x[1]*cos(a)
y[0] = x[1]*sin(a)
x[1] = r*sin(a/2-p)/sin(o)
xt,yt,zt = pltcono(x,y,a)
x1 += xt
y1 += yt
z1 += zt
x[0] = x[1]*cos(a)
y[0] = x[1]*sin(a)
x[1] = x[0] - cos(o+a)
y[1] = y[0] - sin(o+a)
xt,yt,zt = pltcono(x,y,a)
x1 += xt
y1 += yt
z1 += zt
x1 = array(x1)
y1 = array(y1)
z1 = array(z1)
o = 2*pi/N
for m in range(N):
#fig = plt.figure()
#ax = fig.add_subplot(111, projection='3d')
#ax.view_init(45,)
#fig.set_size_inches(10,10)
for n in range(len(x1)):
x1[n],y1[n] = cos(o)*x1[n] - sin(o)*y1[n], sin(o)*x1[n] + cos(o)*y1[n]
ax.plot(x1,y1,z1,'k')
#plt.show()
cono(pi/6+pi/24+0.001)

Note that you need to create a figure every time or pyplot will plot in the first one created.
import math
import matplotlib.pyplot as plt
o = 2*pi/N
for m in range(N):
for n in range(len(x1)):
x1[n],y1[n] = math.cos(o)*x1[n] - math.sin(o)*y1[n], math.sin(o)*x1[n] + math.cos(o)*y1[n]
plt.figure()
plt.plot(x1,y1,z1,'k')
I assigned random values to x1,y1,z1,N and got the following output:
It is not the whole output, just signifies multiple plots.
Look here for more ways to do the same.

Related

Moving circle from point A to B

I need to make the blue circle move in a straight line with animation.
The straight line code needs to stay as is. I just can't figure out the code for object animation.
The circle can be in any shape and colour it just need to move from point A to point B in a straight line.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import pyplot as plt, patches
img=np.ones((200,200,3))
c=plt.Circle((50, 100))
def DrawLine(x1,y1,x2,y2):
dx = abs(x2-x1)
dy = abs(y2-y1)
if x1<x2:
xs=1
else:
xs=-1
if y1<y2:
ys=1
else:
ys=-1
x=x1
y=y1
p=2*dy-dx
if dx>dy:
while x!=x2:
x=x+xs
if p > 0:
y=y+ys
p=p+2*dy-2*dx
else:
p=p+2*dy
img[y,x]= 0
DrawLine(150,100,50,100)
fig = plt.figure()
plt.imshow(img)
plt.gca().add_artist(c)
plt.show()
Matplotlib has animations for this purpose:
import numpy as np
from matplotlib import pyplot as plt, animation
img = np.ones((200, 200, 3))
def DrawLine(x1, y1, x2, y2):
dx = abs(x2 - x1)
dy = abs(y2 - y1)
if x1 < x2:
xs = 1
else:
xs = -1
if y1 < y2:
ys = 1
else:
ys = -1
x = x1
y = y1
p = 2 * dy - dx
if dx > dy:
while x != x2:
x = x + xs
if p > 0:
y = y + ys
p = p + 2 * dy - 2 * dx
else:
p = p + 2 * dy
img[y, x] = 0
DrawLine(150, 100, 50, 100)
fig, ax = plt.subplots()
ax.imshow(img)
# define animation function
def animate(i):
c = plt.Circle((50+i % 100, 100))
circle = ax.add_artist(c)
return circle,
# define animation properties, see
# https://matplotlib.org/stable/api/_as_gen/matplotlib.animation.FuncAnimation.html
ani = animation.FuncAnimation(fig, animate, interval=20, blit=True)
plt.show()

Simulate a rotating equal triangle by Python

can anyone help me, i stuck at the last step
[]
this is my code. then for the last step to rotate it, i didnt know what should i do to rotate the triangle
This is the perfect case for an animation:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
from matplotlib.animation import FuncAnimation
# Enter x and y coordinates of points and colors
a=(0,0.5);b=(0.43,-0.25);c=(-0.43,-0.25)
center=(0,0)
n = 3;r=1.0
theta = np.arange(0,360+(360/(n)),360/(n))
to=np.arange(0,2*np.pi,0.01)
x = r * np.cos(np.radians(theta))
y = r * np.sin(np.radians(theta))
xo = r * np.cos(to); yo = r * np.sin(to)
fig, ax = plt.subplots()
ax.plot(xo,yo)
# create artists: they will be used to update the position
# of the points being rendered
triangle, = ax.plot(x,y)
vertices = ax.scatter(x,y)
lim = r * 1.25
ax.set_xlim([-lim, lim]);ax.set_ylim([-lim, lim])
ax.set_aspect("equal")
w = 2
T = 2 * np.pi / w
# this defines the time steps of the animation
dt = np.linspace(0, 10 * T, num=500)
def animate(i):
x = r * np.cos(np.radians(theta) + w * dt[i])
y = r * np.sin(np.radians(theta) + w * dt[i])
# update the position of the points to be rendered
triangle.set_data(x, y)
vertices.set_offsets(np.stack([x, y]).T)
ax.set_title("Rotation #%s" % int(w * dt[i] / (2 * np.pi) + 1))
ani = FuncAnimation(fig, animate, frames=len(dt), repeat=False)
plt.show()
Check this out..
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
# Enter x and y coordinates of points and colors
a=(0,0.5);b=(0.43,-0.25);c=(-0.43,-0.25)
center=(0,0)
n = 3;r=1.0
theta = np.arange(0,360+(360/(n)),360/(n))
w = 2
T = 2*np.pi/w
dt = np.linspace(0, 10*T, num=10) #increase num for more finely distributed rotations.
for d in dt:
to=np.arange(0,2*np.pi,0.01)
x = r*np.sin(np.radians(theta + d))
y=r*np.cos(np.radians(theta + d))
xo=r*np.sin(to);yo=r*np.cos(to)
plt.plot(xo,yo)
plt.plot(x,y)
plt.scatter(x,y)
plt.xlim([-1, 1]);plt.ylim([-1,1])

Pyplot how to plot math art

How would one plot these circle structures:
https://blogs.scientificamerican.com/guest-blog/making-mathematical-art/
in pyplot? I tried this:
x = np.arange(1,11)
def f(x):
return np.cos((10*np.pi*x)/14000)*(1-(1/2)*(np.square(np.cos((16*np.pi*x)/16000))))
def z(x):
return np.sin((10*np.pi*x)/14000)*(1-(1/2)*(np.square(np.cos((16*np.pi*x)/16000))))
def w(x):
return 1/200 + 1/10*np.power((np.sin(52*np.pi*x)/14000),4)
plt.ylim(-10, 10)
plt.title("Matplotlib demo")
plt.xlabel("x axis caption")
plt.ylabel("y axis caption")
x1=np.linspace(0,14000)
results=f(x1)
results2 = z(x1)
results3 = w(x1)
plt.plot(results)
plt.plot(results2)
plt.plot(results3)
plt.show()
But only get this:
Take the first example in the reported link:
So you have to do a for loop with k from 1 to N = 14000, in each iteration you draw a circle of radius R and center in (X, Y) defined in the above equations:
N = 14000
for k in range(1, N + 1):
X = cos(10*pi*k/N)*(1 - 1/2*(cos(16*pi*k/N))**2)
Y = sin(10*pi*k/N)*(1 - 1/2*(cos(16*pi*k/N))**2)
R = 1/200 + 1/10*(sin(52*pi*k/N))**4
At this point you have the coordinates of the circle's center and its radius, but not the circle iteself yet, so you you have to compute it. First of all you have to define an angle theta from 0 to 2*pi, then compute the cirle's points with:
N = 14000
theta = np.linspace(0, 2*pi, 361)
for k in range(1, N + 1):
X = cos(10*pi*k/N)*(1 - 1/2*(cos(16*pi*k/N))**2)
Y = sin(10*pi*k/N)*(1 - 1/2*(cos(16*pi*k/N))**2)
R = 1/200 + 1/10*(sin(52*pi*k/N))**4
x = R*np.cos(theta) + X
y = R*np.sin(theta) + Y
Finally, you can draw the circles in each iteration.
Complete code
import numpy as np
import matplotlib.pyplot as plt
from math import sin, cos, pi
N = 14000
theta = np.linspace(0, 2*pi, 361)
fig, ax = plt.subplots(figsize = (10, 10))
for k in range(1, N + 1):
X = cos(10*pi*k/N)*(1 - 1/2*(cos(16*pi*k/N))**2)
Y = sin(10*pi*k/N)*(1 - 1/2*(cos(16*pi*k/N))**2)
R = 1/200 + 1/10*(sin(52*pi*k/N))**4
x = R*np.cos(theta) + X
y = R*np.sin(theta) + Y
ax.plot(x, y, color = 'blue', linewidth = 0.1)
plt.show()

How to extract a 2D plane from a 3D numpy meshgrid

[TLDR]:
Essentially my question boils down to how one can extract the 2d data of a plane from a 3D numpy meshgrid
[Detailed Description]:
I am calculating the electric field of two (or more) point charges. I did this in 2D and can plot the results via matplotlib using quiver or streamplot
import numpy as np
from matplotlib import pyplot as plt
eps_0 = 8e-12
fac = (1./(4*np.pi*eps_0))
charges = [1.0,-1.0]
qx = [-2.0,2.0]
qy = [0.0,0.0]
# GRID
gridsize = 4.0
N = 11
X,Y = np.meshgrid( np.linspace(-gridsize,gridsize,N),
np.linspace(-gridsize,gridsize,N))
# CALC E-FIELD
sumEx = np.zeros_like(X)
sumEy = np.zeros_like(Y)
for q, qxi, qyi in zip(charges,qx,qy):
dist_vec_x = X - qxi
dist_vec_y = Y - qyi
dist = np.sqrt(dist_vec_x**2 + dist_vec_y**2)
Ex = fac * q * (dist_vec_x/dist**3)
Ey = fac * q * (dist_vec_y/dist**3)
sumEx += Ex
sumEy += Ey
# PLOT
fig = plt.figure()
ax = fig.add_subplot(111)
ax.streamplot(X,Y,sumEx,sumEy)
plt.show()
This produces the correct results
I can easily extend this to 3D
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
eps_0 = 8e-12
fac = (1./(4*np.pi*eps_0))
charges = [1.0,-1.0]
qx = [-2.0,2.0]
qy = [0.0,0.0]
qz = [0.0,0.0]
# GRID
gridsize = 4.0
N = 11
X,Y,Z = np.meshgrid( np.linspace(-gridsize,gridsize,N),
np.linspace(-gridsize,gridsize,N),
np.linspace(-gridsize,gridsize,N))
# CALC E-FIELD
sumEx = np.zeros_like(X)
sumEy = np.zeros_like(Y)
sumEz = np.zeros_like(Z)
for q, qxi, qyi, qzi in zip(charges,qx,qy,qz):
dist_vec_x = X - qxi
dist_vec_y = Y - qyi
dist_vec_z = Z - qzi
dist = np.sqrt(dist_vec_x**2 + dist_vec_y**2 + dist_vec_z**2)
Ex = fac * q * (dist_vec_x/dist**3)
Ey = fac * q * (dist_vec_y/dist**3)
Ez = fac * q * (dist_vec_z/dist**3)
sumEx += Ex
sumEy += Ey
sumEz += Ez
# PLOT
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.quiver(X,Y,Z,sumEx,sumEy,sumEz, pivot='middle', normalize=True)
plt.show()
This also yields the correct result when plotted in 3D (as far as I can tell)
But for some reason I can not figure out how to extract the data from one x-y plane from the generated 3D numpy mesh. I thought I could just do something like
zplane = round(N/2)
ax.quiver(X,Y,sumEx[:,:,zplane],sumEy[:,:,zplane])
but this does not do the trick. Does anyone know the proper way here?
Remove projection='3d' and index X and Y:
fig = plt.figure()
ax = fig.gca()
zplane = round(N / 2)
ax.quiver(X[:, :, zplane], Y[:, :, zplane], sumEx[:, :, zplane], sumEy[:, :, zplane])
plt.show()
If you select a specific zplane your plot is no longer a 3D-plot.

Plotting multiple 2d curves with matplotlib in 3d

I'm trying to plot a fourier series of a triangular wave with matplotlib.
I've managed to plot the elements on top of each other in 2d, but I'd like to plot them in 3d instead, as that makes it more easy to see.
Here's the plot my current code generates
triangular wave
Here's an image of what I'd like to plot, but for the triangular wave instead of a square wave.
square wave
Here's the current code
%matplotlib inline
import numpy as np
from matplotlib import pyplot as plt
import scipy as sp
x1 = np.arange(0, L / 2.0, 0.01)
x2 = np.arange(L/2.0,L,0.01)
x = np.concatenate((x1,x2))
y1 = 2* x1
y2 = 2*(1 - x2)
triangle_y = np.concatenate((y1,y2))
L = 1;
def triangle_function(x, L):
'''given x, returns y as defined by the triangle function defined in the range 0 <= x <= L
'''
if x< 0:
print 'Error: the value of x should be between 0 and L'
y = None
elif x<L/2.0:
y = 2*x
elif x <= L:
y = 2*(1 - x)
else:
print 'Error: the value of x should be between 0 and L'
y = None
return y
def projection_integrand(x, n, L):
'''The inputs to the function are:
x ---> vector of x values.
n ---> the n-number associated to the sine functions
L --> L, upper limit of integration
'''
sine_function = np.sin(n * np.pi * x / np.double(L)) # this is the sine function sin(n*pi*x/L)
integrand = (2.0 / L) * sine_function * triangle_function(x, L) # this is the product of the two functions, with the 2/L factor
#return(sine_function*f_x)
return integrand
from scipy.integrate import quad
n_max = 5
x = np.arange(0, L, 0.01) # x vector
triangle_approx = np.zeros(len(x))
func_list = []
for n in range(1, n_max + 1):
c_n = quad(projection_integrand, 0, L, (n, L))
sin_arg = n* np.pi*x/np.double(L)
current = c_n[0]* np.sin(sin_arg)
triangle_approx += current
func_list.append(current)
from mpl_toolkits.mplot3d import Axes3D
plt.hold(True)
plt.plot(x, func_list[0])
plt.plot(x, func_list[1])
plt.plot(x, func_list[2])
plt.plot(x, func_list[3])
plt.plot(x, func_list[4])
plt.plot(x, triangle_approx)
plt.plot(x, triangle_y)
plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('approximating the triangle function as a sum of sines, n = 1 ...' + str(n_max))
plt.legend(['approximation', 'triangle function'])
plt.show()
I have found a way based on this matplotlib official example.
Add this code below your code and you will get something close to what you want:
fig = plt.figure()
ax = fig.gca(projection='3d')
z = np.array([1.0 for point in x])
for n, armonic in enumerate(func_list):
ax.plot(x, armonic, z*n, label='armonic{}'.format(n))
ax.legend()
plt.show()

Categories

Resources