Matplotlib - Plot 3D with for loop - python

I want to plot several 3D points with matplotlib. My coordinates are stored in 2D arrays because i got multiple cases and so i would like to plot all the cases in a same 3D plot with a "for loop" but when i do that, the results appeared on different plots...
As example :
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
X = np.array([[3,2,1],[4,5,6]])
Y = np.array([[1,2,1],[2,3,4]])
Z = np.array([[10,11,12],[13,12,16]])
for i in range(0,X.shape[0]):
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X[i,:], Y[i,:], Z[i,:], c='r', marker='o')
ax.set_xlabel('Z')
ax.set_ylabel('X')
ax.set_zlabel('Y')
plt.show()

You create a new figure each iteration and plot it each iteration. Also you always create the first suplot of a 1x1 subplot-grid.
You probably want a x.shape[0] x 1 grid or 1 x x.shape[0] grid:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
X = np.array([[3,2,1],[4,5,6]])
Y = np.array([[1,2,1],[2,3,4]])
Z = np.array([[10,11,12],[13,12,16]])
# Create figure outside the loop
fig = plt.figure()
for i in range(0,X.shape[0]):
# Add the i+1 subplot of the x.shape[0] x 1 grid
ax = fig.add_subplot(X.shape[0], 1, i+1, projection='3d')
ax.scatter(X[i,:], Y[i,:], Z[i,:], c='r', marker='o')
ax.set_xlabel('Z')
ax.set_ylabel('X')
ax.set_zlabel('Y')
# Show it outside the loop
plt.show()
EDIT:
If you want to plot them all into the same plot use:
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
ax.set_xlabel('Z')
ax.set_ylabel('X')
ax.set_zlabel('Y')
for i in range(0,X.shape[0]):
# Only do the scatter inside the loop
ax.scatter(X[i,:], Y[i,:], Z[i,:], c='r', marker='o')
plt.show()

Related

How do you plot vertical 3D planes?

see picture
Hey, I want to plot a function in 3d matplotlib python. The functions I want to plot are x = i where i stretches from 0 to 1 with increments of 0.20. So basically 4 vertical planes just as in the picture I shared.
You can create the planes as surface plots.
Here's an example:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
X, Y = np.meshgrid(np.arange(-6, 6), np.arange(-6, 6))
Z = 0*X
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, alpha=0.5) # the horizontal plane
ax.plot_surface(Z, Y, X, alpha=0.5) # the vertical plane

Labeling first and last data point in matplotlib 3D

I have plotted a set of data points in a 3D figure and I would like to label the first and last data point with a different color and label them by a legend. How do I do that?
The code I have used is
from mpl_toolkits.mplot3d import Axes3D
x = np.array([0,1,2,3])
y = np.array([0,1,2,3])
z = np.array([0,1,2,3])
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot(x,y,z,'o-',markersize=5)
plt.show()
You can redraw the first and last point on the plot and label them as you give them color.
from mpl_toolkits.mplot3d import Axes3D
x = np.array([0,1,2,3])
y = np.array([0,1,2,3])
z = np.array([0,1,2,3])
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot(x[:1], y[:1], z[:1], 'o-',c='green', label="first", zorder=2)
ax.plot(x[-1:], y[-1:], z[-1:], 'o-',c='coral', label="last", zorder=2)
ax.plot(x,y,z,'o-',markersize=5, zorder=1)
ax.legend()
plt.show()
Output:

Superimpose independent plots in python

I want to work with only one figure, with multiples, different and modifiable plots, whithout the subplots formalism.
Is there a way to superimpose two differents plots, in the same way as text boxes, i.e anywhere on the figure ?
Here a "gimp made" example :
Thanks !
You can use figure.add_axes to place an axes at an arbitrary location.
fig = plt.figure()
fig.add_axes([0.1,0.2,0.3,0.4])
places an axes at x=0.1, y=0.2, width=0.3, height=0.4 in figure coordinates.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_axes([0.4,0.1,0.5,0.6], projection='3d')
X, Y = np.meshgrid(np.arange(-5, 5, 0.25), np.arange(-5, 5, 0.25))
Z = np.sin(np.sqrt(X**2 + Y**2))
surf = ax.plot_surface(X, Y, Z, cmap="plasma")
ax = fig.add_axes([0.3,0.4,0.3,.4])
plt.plot([1,2,3])
plt.show()

Plot serial port 3d points data on 3d coordinate system using python

I have searched for this in google, but found solutions for 2d points in real time.How can I achieve this for stream of 3d point.
Here I should be able to add new points to plot.
I tried this, its just plots series of data. How to update?
You could just plot in interactive mode, for example the following keeps adding new points,
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
plt.ion()
plt.show()
x = np.linspace(0.,np.pi*4.,100)
ax.set_xlim([0.,13.])
ax.set_ylim([-1.5,1.5])
ax.set_zlim([-1.5,1.5])
for i in x:
ax.scatter(i, np.sin(i), np.cos(i))
print(i)
plt.pause(0.01)
UPDATE: added example of labelling
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
plt.ion()
plt.show()
lsp = np.linspace(0.,np.pi*4.,100)
ax.set_xlim([0.,13.])
ax.set_ylim([-1.5,1.5])
ax.set_zlim([-1.5,1.5])
for i, x in enumerate(lsp):
y = np.sin(x)
z = np.cos(x)
ax.scatter(x, y, z)
if i%10 == 0:
ax.text(x, y, z, str(np.round(x,3))+", "
+str(np.round(y,3))+", "
+str(np.round(z,3)))
plt.pause(0.01)

Updating a pyplot 3d scatter plot in a loop, grid lines overlap points

I am updating a 3d scatter plot with every iteration of a loop. When the plot is redrawn, the gridlines "go through" or "cover" the points, which makes my data more difficult to visualize. If I build a single 3d plot (no loop updating) this does not happen. The code below demonstrates the simplest case:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import time
X = np.random.rand(100, 3)*10
Y = np.random.rand(100, 3)*5
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X[:, 0], X[:, 1], X[:, 2])
plt.draw()
for i in range(0, 20):
time.sleep(3) #make changes more apparent/easy to see
Y = np.random.rand(100, 3)*5
ax.cla()
ax.scatter(Y[:, 0], Y[:, 1], Y[:, 2])
plt.draw()
Has anyone else encountered this problem?
It looks like MaxNoe is right in the sense that the problem is in the ax.cla()or plt.cla() call. In fact it seems it is something like a known issue.
Then there is a problem, since the clear axes method doesn't work in 3D plots and for 3D scatters there is no clean way to change the coordinates of the data points (a la sc.set_data(new_values)), as discussed in this mail list (I didn't find anything more recent).
In the mail list, however, Ben Roon points to a workaround that might be useful for you, too.
Workaround:
You need to set the new coordinates of the datapoints in the internal _ofsets3d variable of the Line3DCollectionobject returned by the scatter function.
Your example adapted would look like:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import time
X = np.random.rand(100, 3)*10
Y = np.random.rand(100, 3)*5
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
sc = ax.scatter(X[:, 0], X[:, 1], X[:, 2])
fig.show()
for i in range(0, 20):
plt.pause(1)
Y = np.random.rand(100, 3)*5
sc._offsets3d = (Y[:,0], Y[:,1], Y[:,2])
plt.draw()
I could narrow it down to the use of cla():
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x, y = np.meshgrid(np.linspace(-2,2), np.linspace(-2,2))
ax.plot_surface(x,y, x**2+y**2)
fig.savefig("fig_a.png")
ax.cla()
ax.plot_surface(x,y, x**2+y**2)
fig.savefig("fig_b.png")
these are the resulting plots:
This is but a workaround, as it does not resolve the issue with ax.cla() pointed out by MaxNoe. It is also not particularly pretty since it clears the entire figure, however it does the desired task:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig1 = plt.figure()
ax1 = fig1.add_subplot(111, projection='3d')
x, y = np.meshgrid(np.linspace(-2,2), np.linspace(-2,2))
ax1.plot_surface(x,y, x**2+y**2)
fig1.savefig("fig_a.png")
fig1.clf()
ax1 = fig1.add_subplot(111, projection='3d')
ax1.plot_surface(x,y, x**2+y**2)
fig1.savefig("fig_b.png")
I'd suggest using ax = fig.gca(projection='3d') instead of ax = fig.add_subplot(111, projection='3d') .

Categories

Resources