I want to plot (filled) polygons that are given by a sequence of points that define the boundary in 3d. Unfortunately these polygons intersect eachother.
Here is a minimal example that shows two squares that intersect, with the issue that they are not plotted correctly. In my actual application these polygons are generated on the fly, so it is also not possible to manually define a triangulation of the polygon. I'm aware that with Poly3DCollection, there is no chance of doing this correctly as the polygons will only be filled after the projection.
Can anyone recommend another method that allows drawing polygons in 3d with correct intersections?
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
verts1 = np.array([
[0, 0, 0.5],
[1, 0, 0.5],
[1, 1, 0.5],
[0, 1, 0.5]
])
verts2 = verts1[:, [1, 2, 0]]
verts = [verts1, verts2]
ax.add_collection3d(p3c := Poly3DCollection(verts))
p3c.set_facecolor([(1, 0, 0), (0, 1, 0)])
plt.show()
Related
This seems like a common graphics problem, but I don't seem to find anything that does what I want in python:
I have many 4-vertex polygons in 3D space and need to calculate for a given ray which of the polygons is intercepted first and where. So it is basically ray-tracing of those surfaces to see which is in front. I want to do that for a x-y grid of rays to calculate an image. Below is some simple sample data and I would want to basically see two squares where one overlaps the other. I can do that with a 3D plot, but I need the actual values for a given ray, so for example for a y-directed ray from x=0.75, z=0.75, I need to find the y value where the foremost polygon is hit.
Hope this problem is clear. Ideally only common libraries like scipy, numpy, ... are used, but any help is appreciated!
The 5th point in the example-polygons below is just to plot a closed shape.
square1 = np.array([
[0, 0, 0],
[1, 0, 0],
[1, 0.5, 1],
[0, 0.5, 1],
[0, 0, 0]])
square2 = square1 + 0.5 * np.ones_like(square1)
# 3D plot of this projection
fig = plt.figure(figsize=(4,4))
ax = fig.add_subplot(projection='3d', proj_type='ortho')
ax.set_xlim(-1, 2)
ax.set_ylim(-1, 2)
ax.set_zlim(-1, 2)
#ax.axis('off')
ax.plot(*square1[:,:].T)
ax.plot(*square2[:,:].T)
ax.view_init(elev=0., azim=-90)
# 2D plot of the projection
f, ax = plt.subplots()
ax.set_aspect('equal')
ax.plot(*square1[:,[0,2]].T)
ax.plot(*square2[:,[0,2]].T)
ax.set_xlim(-1, 2)
ax.set_ylim(-1, 2)
I have 6 points in the (x,y) plane: x=[x1,x2,x3,x4,x5,x6] and y=[y1,y2,y3,y4,y5,y6]
import matplotlib.pyplot as plt
x = [0, 2, 4, 0, 2, 4, 0, 2, 4]
y = [0, 0, 0, 3, 3, 3, 7, 7, 7]
plt.scatter(x, y)
plt.show()
I want to between the points, draw entirely parallel lines on each axis x,y(like photo). and how to hide x and y axis on diagram. I want to draw a 2D view of the beams and columns of 3 story building; does matplotlib bring me to my goal or should I go to other libraries?
Absolutely matplotlib can do this. Take a look at their Rectangle Patch:
Example usage (you'll have to modify this to your needs):
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig = plt.figure()
ax = fig.add_subplot()
rect = patches.Rectangle(
(0.1, 0.1),
0.5,
0.5,
fill=False
)
ax.add_patch(rect)
fig.show()
I would like to draw some text behind a Poly3DCollection object, unfortunately using the zorder keyword doesn't seem to produce the effect requested.
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from matplotlib.pyplot import figure, show
canvas = figure()
axes = Axes3D(canvas)
axes.text(0.5, 0.5, 0.5, 'I would like to be behind!', 'x', zorder=0)
x = [0, 1, 1, 0]
y = [0, 0, 0.5, 0.5]
z = [0, 0, 1, 1]
axes.add_collection3d(Poly3DCollection([zip(x, y, z)], zorder=1))
show()
I have this problem. I try to triangulate points cloud by scipy.spatial.Delaunay. I used:
tri = Delaunay(points) # points: np.array() of 3d points
indices = tri.simplices
vertices = points[indices]
But, this code return tetrahedron. How is it possible return triangle of surface only?
Thanks
To get it to work as in code form, you have to parametrize the surface to 2D. For example in the case of ball (r,theta, psi), radius is constant (drop it out) and points are given by (theta,psi) which is 2D.
Scipy Delaunay is N-dimensional triangulation, so if you give 3D points it returns 3D objects. Give it 2D points and it returns 2D objects.
Below is a script that I used to create polyhedra for openSCAD. U and V are my parametrization (x and y) and these are the coordinates that I give to Delaunay. Note that now the "Delaunay triangulation properties" apply only in u,v coordinates (angles are maximized in uv -space not xyz -space, etc).
The example is a modified copy from http://matplotlib.org/1.3.1/mpl_toolkits/mplot3d/tutorial.html which originally uses Triangulation function (maps to Delaunay eventually?)
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.tri as mtri
from scipy.spatial import Delaunay
# u, v are parameterisation variables
u = np.array([0,0,0.5,1,1])
v = np.array([0,1,0.5,0,1])
x = u
y = v
z = np.array([0,0,1,0,0])
# Triangulate parameter space to determine the triangles
#tri = mtri.Triangulation(u, v)
tri = Delaunay(np.array([u,v]).T)
print 'polyhedron(faces = ['
#for vert in tri.triangles:
for vert in tri.simplices:
print '[%d,%d,%d],' % (vert[0],vert[1],vert[2]),
print '], points = ['
for i in range(x.shape[0]):
print '[%f,%f,%f],' % (x[i], y[i], z[i]),
print ']);'
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
# The triangles in parameter space determine which x, y, z points are
# connected by an edge
#ax.plot_trisurf(x, y, z, triangles=tri.triangles, cmap=plt.cm.Spectral)
ax.plot_trisurf(x, y, z, triangles=tri.simplices, cmap=plt.cm.Spectral)
plt.show()
Below is the (slightly more structured) text output:
polyhedron(
faces = [[2,1,0], [3,2,0], [4,2,3], [2,4,1], ],
points = [[0.000000,0.000000,0.000000],
[0.000000,1.000000,0.000000],
[0.500000,0.500000,1.000000],
[1.000000,0.000000,0.000000],
[1.000000,1.000000,0.000000], ]);
It looks like you want to compute the convex hull of your point cloud. I think this is what you want to do:
from scipy.spatial import ConvexHull
hull = ConvexHull(points)
indices = hull.simplices
vertices = points[indices]
Following Jaime's answer, but elaborating a bit more with an example:
import matplotlib as mpl
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d as a3
import numpy as np
import scipy as sp
from scipy import spatial as sp_spatial
def icosahedron():
h = 0.5*(1+np.sqrt(5))
p1 = np.array([[0, 1, h], [0, 1, -h], [0, -1, h], [0, -1, -h]])
p2 = p1[:, [1, 2, 0]]
p3 = p1[:, [2, 0, 1]]
return np.vstack((p1, p2, p3))
def cube():
points = np.array([
[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1],
[1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1],
])
return points
points = icosahedron()
# points = cube()
hull = sp_spatial.ConvexHull(points)
indices = hull.simplices
faces = points[indices]
print('area: ', hull.area)
print('volume: ', hull.volume)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.dist = 30
ax.azim = -140
ax.set_xlim([0, 2])
ax.set_ylim([0, 2])
ax.set_zlim([0, 2])
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
for f in faces:
face = a3.art3d.Poly3DCollection([f])
face.set_color(mpl.colors.rgb2hex(sp.rand(3)))
face.set_edgecolor('k')
face.set_alpha(0.5)
ax.add_collection3d(face)
plt.show()
Which should depict the following figure:
How can we plot 2D math vectors with matplotlib? Does anyone have an example or suggestion about that?
I have a couple of vectors stored as 2D numpy arrays, and I would like to plot them as directed edges.
The vectors to be plotted are constructed as below:
import numpy as np
# a list contains 3 vectors;
# each list is constructed as the tail and the head of the vector
a = np.array([[0, 0, 3, 2], [0, 0, 1, 1], [0, 0, 9, 9]])
Edit:
I just added the plot of the final answer of tcaswell for anyone interested in the output and want to plot 2d vectors with matplotlib:
The suggestion in the comments by halex is correct, you want to use quiver (doc), but you need to tweak the properties a bit.
import numpy as np
import matplotlib.pyplot as plt
soa = np.array([[0, 0, 3, 2], [0, 0, 1, 1], [0, 0, 9, 9]])
X, Y, U, V = zip(*soa)
plt.figure()
ax = plt.gca()
ax.quiver(X, Y, U, V, angles='xy', scale_units='xy', scale=1)
ax.set_xlim([-1, 10])
ax.set_ylim([-1, 10])
plt.draw()
plt.show()
It's pretty straightforward. Hope this example helps.
import matplotlib.pyplot as plt
import numpy as np
x = np.random.normal(10,5,100)
y = 3 + .5*x + np.random.normal(0,1,100)
myvec = np.array([x,y])
plt.plot(myvec[0,],myvec[1,],'ro')
plt.show()
Will produce:
To plot the arrays you can just slice them up into 1D vectors and plot them. I'd read the full documentation of matplotlib for all the different options. But you can treat a numpy vector as if it were a normal tuple for most of the examples.