I got a .dat file which contains the coordinates of a segment in 3d space.
The file has several lines, each single line characterizes the position at a particular time.
I tried this code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
dati = np.loadtxt('dati.dat')
t=0
p1=[dati[t,1],dati[t,2],dati[t,3]]
p2=[dati[t,4],dati[t,5],dati[t,6]]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
seg,=ax.plot(p1,p2)
def updateFigure(t,dati,seg):
p1=[dati[t,1],dati[t,2],dati[t,3]]
p2=[dati[t,4],dati[t,5],dati[t,6]]
seg.set_data(p1,p2)
return seg,
ani=animation.FuncAnimation(fig, updateFigure,iMax, fargs=(dati,seg), interval=100, blit=True)
plt.show()
The program doesn't report errors but the figure doesn't move.
The same code, a bit modified, in the 2d space works..
Instead of calling set_data, you could set seg._verts3d directly, though note that manipulating the private variable _verts3d is relying on an implementation detail, not part of the Line3D public interface:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
iMax = N = 500
theta = np.linspace(0, 6*np.pi, N)
x = np.cos(theta)
y = np.sin(theta)
z = np.linspace(0, 1, N)
step = 10
dati = np.column_stack(
[theta, x, np.roll(x, -step), np.roll(x, -2*step)
, y, np.roll(y, -step), np.roll(y, -2*step)
, z, np.roll(z, -step), np.roll(z, -2*step)])
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
seg, = plt.plot([], [])
ax.set_xlim3d(-1, 1)
ax.set_ylim3d(-1, 1)
ax.set_zlim3d(0, 1)
def init():
return seg,
def updateFigure(t):
p1 = dati[t, 1:4]
p2 = dati[t, 4:7]
p3 = dati[t, 7:10]
seg._verts3d = (p1, p2, p3)
return seg,
ani = animation.FuncAnimation(
fig, updateFigure
, init_func=init
, frames=iMax
, interval=5, blit=True)
plt.show()
Related
I am using matplotlib and I am struggling with style attributes.
How to add a marker only to the start point or end point of a 3D line and not on both sides?
Use the markevery parameter when plotting.
Example from the Parametric Curve example in the Gallery (version 2.2.5).
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
# Prepare arrays x, y, z
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
l = ax.plot(x, y, z, marker='o', label='parametric curve both ends', markevery=[0,-1])
l = ax.plot(x+1, y+1, z, 'r', marker='o', label='parametric curve one end', markevery=[0])
ax.legend()
plt.show()
plt.close()
I used the example from version 2.2.5 because I don't have 3.2 installed. Making a 3d axis changed in 3.something - 3.2 example link.
Axes.plot markevery parameter
I am trying to use matplotlib.animation to animate the time evolution of a surface. A working example is found on this stackexchange question/answer. Using plt.show() I can see the animation fine. The problem is when I try to save it. When saving as either a gif or mp4 I get only one from of the animation. I do not get this problem if I am doing 1d animations, for example using plt.plot(). Below is what I am trying:
from mpl_toolkits.mplot3d import axes3d
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import cm
def generate(X, Y, phi):
R = 1 - np.sqrt(X**2 + Y**2)
return np.cos(2 * np.pi * X + phi) * R
fig = plt.figure()
ax = axes3d.Axes3D(fig)
xs = np.linspace(-1, 1, 50)
ys = np.linspace(-1, 1, 50)
X, Y = np.meshgrid(xs, ys)
Z = generate(X, Y, 0.0)
wframe = ax.plot_surface(X, Y, Z, rstride=2, cstride=2, cmap=cm.coolwarm )
ax.set_zlim(-1,1)
def update(i, ax, fig):
ax.cla()
phi = i * 360 / 2 / np.pi / 100
Z = generate(X, Y, phi)
wframe = ax.plot_surface( X, Y, Z, rstride=2,
cstride=2, cmap=cm.coolwarm )
ax.set_zlim(-1,1)
return wframe,
ani = animation.FuncAnimation( fig, update, frames=10,
fargs=(ax, fig), interval=100 )
ani.save('plottest3d2.mp4', fps=30)
ani.save('plottest3d3.gif', fps=30, writer='imagemagick')
plt.show()
Any help explaining the discrepancy between showing the plot and saving would be great.
I'm trying to create an animation with two subplots--one 3D and another 2D. I can't seem to figure out if there is a way to get better font rendering from the 2D axes however. I tried playing around with various settings with font_manager, and even changing the frame_format to raw, but I've had no success. Does anyone have any ideas how to fix this? I get the same results with mpeg4.
The strange thing is that the 3D figure seems to render the font properly.
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
w, h = matplotlib.figure.figaspect(.5)
fig = plt.figure(figsize=(w,h))
ax3d = fig.add_subplot(121, projection='3d')
ax2d = fig.add_subplot(122)
ax3d.set_xlim(-3, 3)
ax3d.set_ylim(-3, 3)
ax3d.azim = -90
ax3d.elev = 0
ax3d.set_title('Car on Parking Ramp')
ax2d.set_xlim(-20,20)
ax2d.set_ylim(-20,20)
ax2d.set_ylabel('y')
ax2d.set_xlabel('x')
ax2d.set_title('Intersection with z=0')
''' Helix '''
K = 3 ## Angular velocity
H = 2*np.pi ## Height
t = np.linspace(0, H, 100, endpoint=True)
x = np.cos(K*t)
y = np.sin(K*t)
z = H - t
ax3d.plot(x, y, z, color='k')
''' z = 0 Plane '''
xx, yy = np.meshgrid([-20,20], [-20,20])
ax3d.plot_surface(xx, yy, 0, alpha=0.3, facecolor='b', rstride=1, cstride=1, shade=True)
ax3d.set_axis_off()
''' Tangent Line Data '''
xdata = np.array([ np.cos(K*t), np.cos(K*t) - K*(H - t)*np.sin(K*t) ])
ydata = np.array([ np.sin(K*t), np.sin(K*t) + K*(H - t)*np.cos(K*t) ])
''' Graph Lines '''
proj, = ax2d.plot([],[])
tangent, = ax3d.plot([], [], [], color='b')
def update_graph(n, tangent, proj, xdata, ydata):
tangent.set_data(xdata[:,n],
ydata[:,n])
tangent.set_3d_properties([H - t[n], 0])
proj.set_xdata(xdata[1,:n])
proj.set_ydata(ydata[1,:n])
ani = animation.FuncAnimation(fig, update_graph, len(t),
fargs=(tangent, proj, xdata, ydata), interval=75, blit=True)
ani.save('im.gif', writer='imagemagick', fps=10)
#ani.save('im.mp4', extra_args=['-vcodec', 'libx264'])
For people who face the same issue, it's indeed related to matplotlib backend.
Using different backend might help. In my case, the
%matplotlib nbagg
solved it (thanks to the linked question: Pixelated fonts when plot is saved as jpeg) .
I can't find a way to draw errorbars in a 3D scatter plot in matplotlib.
Basically, for the following piece of code
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X, Y, Z = axes3d.get_test_data(1)
ax.scatter(X, Y, zs = Z, zdir = 'z')
I am looking for something like
ax.errorbar(X,Y, zs = Z, dY, dX, zserr = dZ)
Is there a way to do this in mplot3d? If not, are there other libraries with this function?
There is clearly example on forum http://mple.m-artwork.eu/home/posts/simple3dplotwith3derrorbars
Here is the code but is not built-in functionality:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as axes3d
fig = plt.figure(dpi=100)
ax = fig.add_subplot(111, projection='3d')
#data
fx = [0.673574075,0.727952994,0.6746285]
fy = [0.331657721,0.447817839,0.37733386]
fz = [18.13629648,8.620699842,9.807536512]
#error data
xerror = [0.041504064,0.02402152,0.059383144]
yerror = [0.015649804,0.12643117,0.068676131]
zerror = [3.677693713,1.345712547,0.724095592]
#plot points
ax.plot(fx, fy, fz, linestyle="None", marker="o")
#plot errorbars
for i in np.arange(0, len(fx)):
ax.plot([fx[i]+xerror[i], fx[i]-xerror[i]], [fy[i], fy[i]], [fz[i], fz[i]], marker="_")
ax.plot([fx[i], fx[i]], [fy[i]+yerror[i], fy[i]-yerror[i]], [fz[i], fz[i]], marker="_")
ax.plot([fx[i], fx[i]], [fy[i], fy[i]], [fz[i]+zerror[i], fz[i]-zerror[i]], marker="_")
#configure axes
ax.set_xlim3d(0.55, 0.8)
ax.set_ylim3d(0.2, 0.5)
ax.set_zlim3d(8, 19)
plt.show()
I ended up writing the method for matplotlib: official example for 3D errorbars:
import matplotlib.pyplot as plt
import numpy as np
ax = plt.figure().add_subplot(projection='3d')
# setting up a parametric curve
t = np.arange(0, 2*np.pi+.1, 0.01)
x, y, z = np.sin(t), np.cos(3*t), np.sin(5*t)
estep = 15
i = np.arange(t.size)
zuplims = (i % estep == 0) & (i // estep % 3 == 0)
zlolims = (i % estep == 0) & (i // estep % 3 == 2)
ax.errorbar(x, y, z, 0.2, zuplims=zuplims, zlolims=zlolims, errorevery=estep)
ax.set_xlabel("X label")
ax.set_ylabel("Y label")
ax.set_zlabel("Z label")
plt.show()
I have the following code :
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
from matplotlib import animation
fig = plt.figure()
p3.autoscale = True
ax = p3.Axes3D(fig)
ax.grid(True)
ax.set_xlim(-100, 100)
ax.set_ylim(-100, 100)
ax.set_zlim(-100, 100)
u = np.r_[0:2*np.pi:100j]
v = np.r_[0:np.pi:100j]
scale = 15
x = scale * np.outer(np.cos(u),np.sin(v))
y = scale * np.outer(np.sin(u),np.sin(v))
z = scale * np.outer(np.ones(np.size(u)),np.cos(v))
Line3DCollection_1 = ax.plot_wireframe(x,y,z, rstride=50, cstride=50)
Line3DCollection_2 = ax.plot_wireframe(x + 50,y,z, rstride=50, cstride=50)
# initialization function: plot the background of each frame
def init():
return Line3DCollection_1,
def animate(i):
print("frame :" + str(i))
x = 50 * np.sin(np.radians(i))
y = 50 * np.cos(np.radians(i))
path = plt.plot([x],[y],[0], 'bo')
return path
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=360, interval=0.1, blit=True)
plt.show()
This will produce 2 spheres and a path that I want one of the spheres to take, but I'm not sure how to include this in the animation, I can animate the path, but not the 'Line3DCollection_2' sphere.
Does anyone have any ideas?
Thanks.