Reputation: 1154
I am trying to create a 3D animation scatter plot where each point is plotted as a sphere with radius of r proportional to value M (please see the code below), I guess it should be done by using argument s
in ax.scatter
, but since this value is unique for each (x,y,z), I don't know how to pass that to graph._offsets3d
which accepts (x,y,z) touple. This is the first part of the task, the other part is that the data should appear at their specific time t
(please see the code below).
I am currently struggling to change the size of each point according to their corresponding value in M
, and color code the point with its corresponding time t, do you know how could I do this?
It would my next task to add a play/pause button to the figure and be able to rotate the the graph?
Does anyone have similar experiences that I could benefit from? Many thanks!
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
#####Data Generation####
# Space Coordinate
X = np.random.random((100,)) * 255 * 2 - 255
Y = np.random.random((100,)) * 255 * 2 - 255
Z = np.random.random((100,)) * 255 * 2 - 255
# Magnitude of each point
M = np.random.random((100,))*-1+0.5
# Time
t = np.sort(np.random.random((100,))*10)
#ID each point should be color coded. Moreover, each point belongs to a cluster `ID`
ID = np.sort(np.round([np.random.random((100,))*5]))
def update_lines(num):
for i in range (df_IS["EASTING [m]"].size):
dx = X[i]
dy = Y[i]
dz = Z[i]
text.set_text("{:d}: [{:.0f}] Mw[{:.2f}]".format(ID[i], t[i],ID[i])) # for debugging
x.append(dx)
y.append(dy)
z.append(dz)
graph._offsets3d = (x, y, z)
return graph,
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111, projection="3d")
graph = ax.scatter(X, Y, Z, color='orange') # s argument here
text = fig.text(0, 1, "TEXT", va='top') # for debugging
ax.set_xlim3d(X.min(), X.max())
ax.set_ylim3d(Y.min(), Y.max())
ax.set_zlim3d(Z.min(),Z.max())
# Creating the Animation object
ani = animation.FuncAnimation(fig, update_lines, frames=200, interval=500, blit=False)
plt.show()
Upvotes: 0
Views: 1476
Reputation: 35115
In the animation function was looped by the size of the data frame, but rewrote your code partly because the animation argument is linked to the number of frames. Please correct me if I'm wrong. You can also pass in the size with graph.set_sizes()
, which you can specify there. Your size variable had a negative value, so I'm recreating it as an integer. I've used a separate library in part because of my working environment.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
from IPython.display import HTML # Animation on jupyter lab
from matplotlib.animation import PillowWriter # For GIF animation
#####Data Generation####
# Space Coordinate
X = np.random.random((100,)) * 255 * 2 - 255
Y = np.random.random((100,)) * 255 * 2 - 255
Z = np.random.random((100,)) * 255 * 2 - 255
# Magnitude of each point
# M = np.random.random((100,))*-1+0.5
M = np.random.randint(1,70, size=100)
# Time
t = np.sort(np.random.random((100,))*10)
#ID each point should be color coded. Moreover, each point belongs to a cluster `ID`
ID = np.sort(np.round([np.random.random((100,))*5]))
x = []
y = []
z = []
m = []
def update_lines(i):
# for i in range (df_IS["EASTING [m]"].size):
dx = X[i]
dy = Y[i]
dz = Z[i]
dm = M[i]
# text.set_text("{:d}: [{:.0f}] Mw[{:.2f}]".format(ID[i], t[i],ID[i])) # for debugging
x.append(dx)
y.append(dy)
z.append(dz)
m.append(dm)
graph._offsets3d = (x, y, z)
graph.set_sizes(m)
return graph,
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111, projection="3d")
graph = ax.scatter(X, Y, Z, s=M, color='orange') # s argument here
text = fig.text(0, 1, "TEXT", va='top') # for debugging
ax.set_xlim3d(X.min(), X.max())
ax.set_ylim3d(Y.min(), Y.max())
ax.set_zlim3d(Z.min(), Z.max())
# Creating the Animation object
ani = animation.FuncAnimation(fig, update_lines, frames=100, interval=500, blit=False, repeat=False)
# plt.show()
ani.save('test3Dscatter.gif', writer='pillow')
plt.close()
HTML(ani.to_html5_video())
Edit:
# Time
t = np.sort(np.random.random((100,))*10)
# datapoint for color
cm_name = 'jet'
cm = plt.get_cmap(cm_name, 100)
C = [cm(n) for n in range(cm.N)]
# list for colors add
x = []
y = []
z = []
m = []
c = []
# animation function update
dm = M[i]
dc = C[i] # update
m.append(dm)
c.append(dc) # update
graph._facecolor3d = c # scatter color defined
return graph,
Upvotes: 2