How to draw a flat 3D rectangle in matplotlib? - python

How do I draw a rectangle in 3D ? The code below works but it draws a triangle
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [0,1,1,0]
y = [0,0,1,1]
z = [0,1,0,1]
verts = [list(zip(x,y,z))]
ax.add_collection3d(Poly3DCollection(verts))
plt.show()
I tried adding a 4th corner but I get an error
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [0,1,1,0]
y = [0,0,1,1]
z = [0,1,0,1]
a = [0,1,0,1]
verts = [list(zip(x,y,z,a))]
ax.add_collection3d(Poly3DCollection(verts))
plt.show()
Is there a function that accepts 4 3D-coordinates then draws a flat rectangle? e.g.
ax.draw_rectangle3d(tl=[0,0,0],tr=[0,0,1],bl=[0,1,0],br=[0,1,1])
This function Adding a Rectangle Patch and Text Patch to 3D Collection in Matplotlib draws a flat rectangle but it does not allow me to set my own x,y,z coordinate and the rectangle is projected onto the axes.

The Z axis is wrong should be [0,0,0,0], since each column is a point and the rectangle is on the 0 on Z axis.
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [0,1,1,0]
y = [0,0,1,1]
z = [0,0,0,0]
verts = [list(zip(x,y,z))]
ax.add_collection3d(Poly3DCollection(verts))
plt.show()
You can use this to plot multiple surfaces.
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
x = [0,1,1,0],[0,1,1,0]
y = [0,0,1,1],[0,0,1,1]
z = [0,0,0,0],[1,1,1,1]
surfaces = []
for i in range(len(x)):
surfaces.append( [list(zip(x[i],y[i],z[i]))] )
for surface in surfaces:
ax.add_collection3d(Poly3DCollection(surface))
plt.show()

import numpy as np
from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
import matplotlib.pyplot as plt
points = np.array([[-1, -1, -1],
[1, -1, -1 ],
[1, 1, -1],
[-1, 1, -1],
[-1, -1, 1],
[1, -1, 1 ],
[1, 1, 1],
[-1, 1, 1]])
Z = points
Z = 10.0*Z
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r = [-1,1]
X, Y = np.meshgrid(r, r)
ax.scatter3D(Z[:, 0], Z[:, 1], Z[:, 2])
verts = [[Z[0],Z[1],Z[2],Z[3]],
[Z[4],Z[5],Z[6],Z[7]],
[Z[0],Z[1],Z[5],Z[4]],
[Z[2],Z[3],Z[7],Z[6]],
[Z[1],Z[2],Z[6],Z[5]],
[Z[4],Z[7],Z[3],Z[0]]]
ax.add_collection3d(Poly3DCollection(verts, facecolors='cyan', linewidths=1, edgecolors='r', alpha=.20))
plt.show()

Related

Matplotlib drawing 3d Lines with solid of revolution

I want to draw a solid 3D line, I have drawn a 3D line, but I want to draw this line with solid of revolution, so my line creates with f.ex. diameter 10 mm along the 3D line. How could that be achieved?
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
x = np.linspace(0, 40, 1000)
y = np.sin(x)
z = np.cos(x)
fig = plt.figure(figsize=(8, 6))
ax = Axes3D(fig)
ax.plot(x, y, z, color="green")
ax.set(xlabel="X", ylabel="Y", zlabel="Z")
ax.set_yticks([-1, 0, 1])
ax.set_yticklabels(['min', 0, 'max'])
plt.show()

matplotlib 3D surface plot

Trying to create a 3D surface plot of a plane with jupyter notebook. However, this code is giving me a strange error:
# ValueError: Argument Z must be 2-dimensional.
%matplotlib
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
plt.clf()
ax = Axes3D(fig)
x=np.arange(-4,4,1)
y=np.arange(-4,4,1)
X = []
Y = []
Z = []
for ix in range(0, len(x)):
for iy in range(0, len(y)):
z = 2*x[ix] + 3*y[iy]
Z.append(z)
X.append(x[ix])
Y.append(y[iy])
ax.plot_surface(X, Y, Z)
plt.show()
%matplotlib inline
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
def plot():
fig = plt.figure()
ax = Axes3D(fig)
#ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z)
plt.show()
Z = 2*X + 3*Y
plot()

Way of plotting data into boxes instead of pyramids using mplot3d

So I have an array of values that I am trying to plot using the plot_surface command. Specifically I have a 30x30 array with one in the middle and zeros elsewhere. When I plot it this is what I obtain:
I would like however for the value to be represented as a cuboid. Is that possible?
Thank you
edit: Code that shows the figure
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
N=30
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(0, N)
z = np.zeros((N,N))
z[15,15] = 1
X, Y = np.meshgrid(x, y)
ax.plot_surface(X, Y, z, cmap='YlOrBr')
plt.show(block=False)
I think a 3D bar plot will give what you're looking for.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
N=30
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(0, N)
z_bottom = np.zeros((N,N))
z_top = z_bottom.copy()
z_top[15,15] = 1
X, Y = np.meshgrid(x, y)
ax.bar3d(X.ravel(), Y.ravel(), z_bottom.ravel(), 1, 1, z_top.ravel())
plt.show(block=False)
The full documentation is here if you want to play with the colors and so forth.

Gridlines Above 3D Scatter Plot in matplotlib

When making a 3D scatter plot with matplotlib I cannot seem to control whether the axes are above or below the plot. For example the following code will always have the x and y axes above the plot if ax1.elev < 0
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
fig = plt.figure('Test')
X = np.random.rand(1,100)
Y = np.random.rand(1,100)
Z = np.random.rand(1,100)
ax1 = fig.add_subplot(111, projection = '3d')
ax1.scatter(X,Y,Z)
ax1.view_init(-10,45)
Is it possible to force the x and y axes and the gridlines and planes to be below the plot even though ax1.elev < 0?
I take as an example the code of this question (thanks crayzeewulf). Except for the z-axis, we do it for the x- and y-axis
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
fig = plt.figure('Test')
X = np.random.rand(1,100)
Y = np.random.rand(1,100)*10
Z = np.random.rand(1,100)
ax1 = fig.add_subplot(111, projection = '3d')
ax1.scatter(X,Y,Z)
ax1.view_init(-10,45)
tmp_planes = ax1.zaxis._PLANES
ax1.xaxis._PLANES = ( tmp_planes[3], tmp_planes[2],
tmp_planes[1], tmp_planes[0],
tmp_planes[5], tmp_planes[4])
ax1.yaxis._PLANES = ( tmp_planes[3], tmp_planes[2],
tmp_planes[1], tmp_planes[0],
tmp_planes[5], tmp_planes[4])
view_1 = (25, -135)
view_2 = (-10, 45)
init_view = view_2
ax1.view_init(*init_view)

plot rotation of a parametrised algebraic surface

I'd like to plot a rotated parabolic cylinder. Like holding one point of the plane of symmetry with two fingers and let this plane rotate about this point.
There is the rotation matrix (for the y-axis).
And the parametrised surface is:
(u,v,u**2)
I've already plotted this surface for rotations about the x-axis:
Below is the modified(!) code to plot the rotations about the y-axis.
from math import cos,sin,pi
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.auto_scale_xyz([0, 500], [0, 500], [0, 0.15])
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
Us = np.arange(-1, 1, 0.005)
Vs = np.arange(-1, 1, 0.005)
for ch in [0.2*i*pi for i in range(3)]:
Xs = Us*cos(ch) + sin(ch)*(Us**2)
Ys = Vs
Xs, Ys = np.meshgrid(Xs, Ys)
Zs = -Us*sin(ch) + cos(ch)*(Us**2)
Axes3D.plot3D(ax,Xs,Ys,Zs, alpha=0.05)
And it doesn't work. It produces nonsense. This is the output i get:
The operations are identical, so i really can't see why it doesn't work. Can anyone tell me what i'm doing wrong?
I need to make this work in order to just look at the way algebraic surfaces transform when subjected to certain rotations. The code above is a crudely simplified snippet of what i am currently debugging. So the answer i am hoping for regards this particular code.
Here is another version which uses your explicit rotation equations:
import matplotlib as mpl
mpl.use('TkAgg')
from math import cos,sin,pi
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.auto_scale_xyz([0, 500], [0, 500], [0, 0.15])
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
U = np.arange(-1, 1, 0.005)
V = np.arange(-1, 1, 0.005)
def animate():
for ch in [0.2*i*pi for i in range(3)]:
Us, Vs = np.meshgrid(U, V)
Xs = Us*cos(ch) + sin(ch)*(Us**2)
Ys = Vs
Zs = -Us*sin(ch) + cos(ch)*(Us**2)
tmp = ax.plot_surface(Xs,Ys,Zs, alpha=0.05)
fig.canvas.draw()
tmp.remove()
win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate)
plt.show()
The rotate_axes3d_demo does it with ax.view_init this way:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
plt.ion()
sin = np.sin
cos = np.cos
pi = np.pi
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.auto_scale_xyz([0, 500], [0, 500], [0, 0.15])
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
Us, Vs = np.meshgrid(np.linspace(-1, 1, 200), np.linspace(-1, 1, 200))
ax.plot_surface(Us,Vs,Us**2)
for angle in range(0, 360):
ax.view_init(angle, 30)
plt.draw()

Categories

Resources