Questions:
- Is there a way to add color to a 3D curve plot more effectively than I am currently doing (e.g. avoiding the loop)?
- Is there a way to update the color of a graph without plotting it all over again?
- Is there a way to update one or more coordinate vectors without plotting it all over again?
Explanation:
I am making plots of 3D curves with color similar to the one in the example below. The number of points in my actual graphs is high, like n > 10000
, which makes this approach very slow.
Also, the coordinates and colors are associated with the fixed number of points, which makes up the curves depend on another variable (i.e. time). Therefore I would like to plot the points once and then update one or all of the vectors (x
, y
, z
, c
) to speed up the plotting of each time step.
EDIT: In Matlab you can do something like the following to update the coordinates of vertices/points already plotted. The example is with patches and not line segments, but the concept is the same:
v = [2 4; 2 8; 8 4; 5 0; 5 2; 8 0];
f = [1 2 3; 4 5 6];
col = [0; 1];
figure
p = patch('Faces',f,'Vertices',v,'FaceVertexCData',col,'FaceColor','flat');
colorbar
pause(1)
v = [1 3; 1 9;9 1; 5 0; 5 2; 8 0];
p.Vertices = v; % this updates the point coordinates which I would like to do for the line segments in my python plot.
drawnow
Code used:
import numpy as np
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
n = 100
x = np.arange(n)
y = np.arange(n)
z = np.arange(n)
colors = np.arange(n)/n
fig = plt.figure()
ax = fig.gca(projection='3d')
for i in range(1,len(x)-1):
ax.plot(x[i-1:i+1], \
y[i-1:i+1], \
z[i-1:i+1], \
c = plt.cm.jet(colors[i]))
plt.show()
EDIT: regarding my question 1: After gboffi's suggestion I looked into matplotlib.collections.LineCollection and can now plot the line segments much faster. I also used this answer Matplotlib Line3DCollection for time-varying colors.
from mpl_toolkits.mplot3d.art3d import Line3DCollection
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.axes(projection='3d')
n = 100
x = np.arange(n)/n
y = np.arange(n)/n
z = np.arange(n)/n
colors = np.arange(n)/n
# "points" is used to restructere the coordinates array such that the first
# dimension is the point number and the third contains x, y and z of the point
points = np.array([x, y, z]).T.reshape(-1, 1, 3)
# "segs" is an array of lines between consecutive points in "points". So
# there is one line less than the number of points. The first dimension is
# the line number, second dimension is the start and end point, and the
# third dimension is the coordinates of the point.
segs = np.concatenate([points[:-1], points[1:]], axis=1)
cmap = plt.get_cmap('jet')
segment_color = cmap(colors)
ax.add_collection(Line3DCollection(segs, colors=segment_color))
plt.show()