Search code examples
pythonmatplotlibmplot3d

Matplotlib: multiple 3D lines all get drawn using the final y-value in my loop


I am trying to plot multiple lines in a 3D figure. Each line represents a month: I want them displayed parallel in the y-direction.

My plan was to loop over a set of Y values, but I cannot make this work properly, as using the ax.plot command (see working code below) produces a dozen lines all at the position of the final Y value. Confusingly, swapping ax.plot for ax.scatter does produce a set of parallel lines of data (albeit in the form of a set of dots; ax.view_init set to best display the parallel aspect of the result).

How can I use a produce a plot with multiple parallel lines? My current workaround is to replace the loop with a dozen different arrays of Y values, and that can't be the right answer.

from mpl_toolkits.mplot3d.axes3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

# preamble
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
cs = ['r','g','b','y','r','g','b','y','r','g','b','y']

# x axis
X = np.arange(24)

# y axis
y = np.array([15,45,75,105,135,165,195,225,255,285,315,345])
Y = np.zeros(24)

# data - plotted against z axis
Z = np.random.rand(24)

# populate figure
for step in range(0,12):
    Y[:] = y[step]
#    ax.plot(X,Y,Z, color=cs[step])
    ax.scatter(X,Y,Z, color=cs[step])

ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
# set initial view of plot
ax.view_init(elev=80., azim=345.)
plt.show()

I'm still learning python, so simple solutions (or, preferably, those with copious explanatory comments) are greatly appreciated.


Solution

  • Use

    ax.plot(X, np.array(Y), Z, color=cs[step])
    

    or

    Y = [y[step]] * 24
    

    This looks like a bug in mpl where we are not copying data when you hand it in so each line is sharing the same np.array object so when you update it all of your lines.