How to animate 3D graphs with python [duplicate] - python

I want to make 3D animation with matplotlib, but I don't know how to. Here is my non-working code.
from matplotlib import pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation
from math import *
fig = plt.figure()
ax = fig.add_subplot(111) #, projection='3d'
#setting
ax.set_xlim(-5,5)
ax.set_ylim(-5,5)
#ax.set_zlim(-5,5)
ax.set_xlabel('x')
ax.set_ylabel('y')
#ax.set_zlabel('z')
ax.grid()
f1, = ax.plot([], [], "r-", lw=1) #plot1
def gen():
for phi in np.linspace(0,2*pi,100):
yield np.cos(phi), np.sin(phi), phi
def update(data):
p1, q1, psi = data
f1.set_data(p1,q1)
#f1.set_3d_properties(psi)
ani = animation.FuncAnimation(fig, update, gen, blit=False, interval=100, repeat=True)
#ani.save('matplot003.gif', writer='imagemagick')
plt.show()

I used this example http://matplotlib.org/1.4.1/examples/animation/simple_3danim.html
and modified your code:
from matplotlib import pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
def gen(n):
phi = 0
while phi < 2*np.pi:
yield np.array([np.cos(phi), np.sin(phi), phi])
phi += 2*np.pi/n
def update(num, data, line):
line.set_data(data[:2, :num])
line.set_3d_properties(data[2, :num])
N = 100
data = np.array(list(gen(N))).T
line, = ax.plot(data[0, 0:1], data[1, 0:1], data[2, 0:1])
# Setting the axes properties
ax.set_xlim3d([-1.0, 1.0])
ax.set_xlabel('X')
ax.set_ylim3d([-1.0, 1.0])
ax.set_ylabel('Y')
ax.set_zlim3d([0.0, 10.0])
ax.set_zlabel('Z')
ani = animation.FuncAnimation(fig, update, N, fargs=(data, line), interval=10000/N, blit=False)
#ani.save('matplot003.gif', writer='imagemagick')
plt.show()

Here is the following code for a sphere moving to the right and off the screen.
You will have to run this code in a folder for tidiness, as it generates 26 .png images (and a .gif image):
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from numpy import sin, cos, pi, outer, ones, size, linspace
# Define x, y, z lists for sphere
a = linspace(0, 2 * pi)
b = linspace(0, pi)
x = 10 * outer(cos(a), sin(b))
y = 10 * outer(sin(a), sin(b))
z = 10 * outer(ones(size(a)), cos(b))
# The amount of frames in the animation
frames = 26
# Generate each frame
for n in range(frames):
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z, color=('b'))
ax.set_xticks([])
ax.set_yticks([])
ax.set_zticks([])
ax.set_xlim(-8,8)
ax.set_xlim(-8,8)
ax.set_xlim(-8,8)
plt.savefig(f"{n}.png")
plt.close()
# Add 1 to the x so the sphere moves right by 1
x += 1
# Use pillow to save all frames as an animation in a gif file
from PIL import Image
images = [Image.open(f"{n}.png") for n in range(frames)]
images[0].save('ball.gif', save_all=True, append_images=images[1:], duration=100, loop=0)
Output:

Related

How to use an image instead of a marker in an animated graph using Matplot.lib

I have been trying to use an image that moves in an animation instead of "ro" (red dots) or similar markers. image_1, image_2, image_3 So far I have a graph that has a little red dot moving over the dotted line. I want an image to be the one that moves through the dotted line instead of a red dot.
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
img = plt.imread("/Users/salomondabbah/Desktop/mar.jpg")
ax.imshow(img, extent=[0, 2 * np.pi, -1, 1])
xtrack = np.linspace(0, 2 * np.pi, 240)
ytrack = np.sin(xtrack)
ln, = plt.plot([], [], ***'ro'***, zorder=15)
ax.plot(xtrack, np.sin(xtrack), 'k', linewidth=25.0, zorder=5)
ax.plot(xtrack, ytrack, '--y',linewidth=2.0, zorder=10)
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
ln.set_data(frame, np.sin(frame))
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=False)
plt.show()
Thank you in advance for any solutions provided to my issue!
Similar to what you are doing, but using set_extent with imshow instead of set_data with a line:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots(figsize=(5,5))
xdata, ydata = [], []
xtrack = np.linspace(0, 2 * np.pi, 240)
ytrack = np.sin(xtrack)
img = plt.imread("car.png")
im = ax.imshow(img, zorder=10, aspect='auto')
ax.plot(xtrack, np.sin(xtrack), 'k', linewidth=25.0, zorder=5)
ax.plot(xtrack, ytrack, '--y',linewidth=2.0, zorder=10)
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
l = frame - 0.5
r = frame + 0.5
b = np.sin(frame) - 0.2
t = np.sin(frame) + 0.2
im.set_extent([l,r,b,t])
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=False)
ani.save('ani.gif', writer='pillow')
The only finnicky thing is getting the desired size & aspect ratio of the graph and size & aspect ratio of the car. The overall graph can be edited by using figsize when it is created as I have added. But if you don't set the aspect parameter of the imshow to auto, it will override the figure size and shape, in order to make the image have correct dimensions (it seems). So you may have to play around with the 0.5 and 0.2 values in the update to keep your image having approximately correct dimensions.

How to animate a complex function with matplotlib?

I want to make an animation with the function ((phi^n)-((-1/phi)^n))/(5^0.5) (Binet's formula) as n ∈ ℝ,
so that the graph starts as a straight line on the real axes then shifts into the actual graph.
I have tried to add
from matplotlib.animation import FuncAnimation
.
.
.
def g(val):
main_graph.set_ydata(imag(f(x))*val)
return main_graph,
animation = FuncAnimation(main_graph, func=g, frames=arange(0, 10, 0.1), interval=10)
plt.show
However, it did not work and I have no clue why I followed various tutorials and all of them had the same result (An error)
I also tried
import matplotlib.animation as animation
.
.
.
def init():
main_graph.set_ydata([np.nan] * len(real(f(x))))
return main_graph,
def g(val):
main_graph.set_ydata(imag(f(x))*val)
return main_graph,
ani = animation.FuncAnimation(main_graph, g, init_func=init, interval=2, blit=True, save_count=50)
The error, in both cases, is AttributeError: 'Line2D' object has no attribute 'canvas'. Here is the full code
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from numpy import arange, real, imag
phi = (1+(5**0.5))/2
x = arange(0,5,0.01)
def f(x):
return ((phi**(x+0j))-((-1/phi)**(x+0j)))/(5**0.5)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.spines['left'].set_position(('data', 0.0))
ax.spines['bottom'].set_position(('data', 0))
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
#labels for x and y axes
plt.xlabel('real')
plt.ylabel('imag')
plt.grid(alpha=.4,linestyle=':')
main_graph, = plt.plot(real(f(x)),imag(f(x)), label='((phi**(x+0j))-((-1/phi)**(x+0j)))/(5**0.5)')
plt.legend()
def g(val):
main_graph.set_ydata(imag(f(x))*val)
return main_graph,
animation = FuncAnimation(main_graph, func=g, frames=arange(0, 10, 0.1), interval=10)
plt.show()
To see the final graph use this code
import matplotlib.pyplot as plt
from numpy import arange, real, imag
phi = (1+(5**0.5))/2
x = arange(0,5,0.01)
def f(x):
return ((phi**(x+0j))-((-1/phi)**(x+0j)))/(5**0.5)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.spines['left'].set_position(('data', 0.0))
ax.spines['bottom'].set_position(('data', 0))
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
#labels for x and y axes
plt.xlabel('real')
plt.ylabel('imag')
plt.grid(alpha=.4,linestyle=':')
main_graph, = plt.plot(real(f(x)),imag(f(x)), label='((phi**(x+0j))-((-1/phi)**(x+0j)))/(5**0.5)')
plt.legend()
plt.show()
I have adapted the example from matplotlib's animation documentation. Here's how the code has been modified to allow for the modification of axis elements (in this case, the legend) by setting blit=False
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from numpy import arange, real, imag
phi = (1+(5**0.5))/2
x = arange(0,5,0.01)
def f(x):
return ((phi**(x+0j))-((-1/phi)**(x+0j)))/(5**0.5)
fig = plt.figure()
main_graph, = plt.plot(real(f(x)),imag(f(x)), label='((phi**(x+0j))-((-1/phi)**(x+0j)))/(5**0.5)')
#labels for x and y axes
plt.xlabel('real')
plt.ylabel('imag')
plt.grid(alpha=.4,linestyle=':')
#plt.legend(loc=4)
def init():
global legs
ax = fig.add_subplot(1, 1, 1)
ax.spines['left'].set_position(('data', 0.0))
ax.spines['bottom'].set_position(('data', 0))
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.set_ylim(-4,4)
legs=ax.legend(loc=4, prop={'size': 12})
return main_graph,
def g(val):
main_graph.set_ydata(imag(f(x))*val)
label = '((phi**(x+0j))-((-1/phi)**(x+0j)))/(5**0.5)x{}'.format(val)
legs.texts[0].set_text(label)
return main_graph,
#Note that blit has been set to False, because axes elements are being modified
animation = FuncAnimation(fig, func=g,frames=arange(0, 10, 0.1), init_func=init,interval=10,blit=False)
animation.save('animation.gif', writer='imagemagick', fps=30)
plt.show()
Here's how the animation is:

Matplotlib animation not showing any plot

I am trying to make an animation in 3D using Matplotlib and mpl_toolkits. For starter, I am trying to make an animation of a shifting cos wave. But when I run the program, the plot is completely empty. I have just started learning matplotlib animations, so I don't have in-depth knowledge of it. Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import math
import matplotlib.animation as animation
fig = plt.figure()
ax = Axes3D(fig)
line, = ax.plot([],[])
print(line)
X = np.linspace(0, 6*math.pi, 100)
def animate(frame):
line.set_data(X-frame, np.cos(X-frame))
return line
anim = animation.FuncAnimation(fig, animate, frames = 100, interval = 50)
plt.show()
Here is the output:
What is wrong with my code? Why am I not getting any output?
There are two issues with your code:
use set_data_3d to update the data of a Line3D object instead of set_data
initialize the Axes3D scales before starting the animation
This should work:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import math
import matplotlib.animation as animation
fig = plt.figure()
ax = Axes3D(fig)
# initialize scales
ax.set_xlim3d(0, 6 * math.pi)
ax.set_ylim3d(-1, 1)
ax.set_zlim3d(0, 100)
X = np.linspace(0, 6 * math.pi, 100)
line, = ax.plot([], [], [])
def animate(frame):
# update Line3D data
line.set_data_3d(X, np.cos(X - frame), frame)
return line,
anim = animation.FuncAnimation(fig, animate, frames = 20, interval = 50)
plt.show()
and yield an animation like this (I have truncated the number of frames to reduce image file size).

Plot a graph point to point python

I wonder if there is some way to plot a waveform point to point at a certain rate through the matplotlib so that the graph appears slowly in the window. Or another method to graph appears at a certain speed in the window and not all the points simultaneously. I've been tried this but I can only plot a section of points at a time
import numpy as np
import matplotlib.pyplot as plt
import time
x = np.arange(0,5,0.001)
y = np.sin(2*np.pi*x)
ind_i = 0
ind_f = 300
while ind_f <= len(x):
xtemp = x[ind_i:ind_f]
ytemp = y[ind_i:ind_f]
plt.hold(True)
plt.plot(xtemp,ytemp)
plt.show()
time.sleep(1)
ind_i = ind_f
ind_f = ind_f + 300
You can also do this with Matplotlib's FuncAnimation function. Adapting one of the matplotlib examples:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
x = np.arange(0,5,0.001)
y = np.sin(2*np.pi*x)
def update_line(num, data, line):
line.set_data(data[..., :num])
return line,
fig = plt.figure()
data = np.vstack((x,y))
l, = plt.plot([], [], 'r-')
plt.xlim(0, 5)
plt.ylim(-1, 1)
line_ani = animation.FuncAnimation(fig, update_line, frames=1000,
fargs=(data, l), interval=20, blit=False)
plt.show()

removing shades from surface plot in python

When I run the attached python code (some of it is junk that is left over from the figure I try to generate), I get a surface with two shades. (dark and light red), is there a way to turn this into a single shade?
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import sys
from math import sqrt,exp,log, sin
from pylab import rcParams
rcParams['figure.figsize'] = 30,26
fig = plt.figure()
ax = fig.add_subplot(211, projection='3d')
l = 7
sigma = 1.0/277.450924284104 #You are stupid so have found the charge density for surface potentail of exactly 62mV
pi = 3.14159
b = 1.0/(2*pi*sigma*l)
lambdaD = 9.5
X0, Y0 = np.mgrid[0:1:100j, 0:1:100j]
Z0 = np.zeros_like(X0)
for i in range(0,len(X0)):
for j in range (0, len(X0[i])):
Z0[i][j] = 10*sin(X0[i][j]*2*pi)
ax.plot_surface(X0,Y0,Z0,color='red', linewidth=0, rstride=10, cstride=10, antialiased=False)
ax.set_axis_off()
Sure, just specify shade=False to ax.plot_surface.
Also, there's absolutely no need to use nested for loops or to specify the figure size through rcParams.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(30, 26))
ax = fig.add_subplot(111, projection='3d')
X0, Y0 = np.mgrid[0:1:100j, 0:1:100j]
Z0 = 10 * np.sin(X0 * 2 * np.pi)
ax.plot_surface(X0,Y0,Z0,color='red', linewidth=0, rstride=10, cstride=10,
antialiased=False, shade=False)
ax.set_axis_off()
plt.show()

Categories