xnx
xnx

Reputation: 25550

matplotlib: filling under line in 3d polar plot

I'd like to plot a sine wave on a circle: that is, the circle is in the x,y-plane and the sine wave wraps around it perpendicular to that plane (sticking up the z-axis). I can do this, but when I try to fill the areas between the circle and the sine wave with a polygon (ie paint on the surface of the imaginary cylinder on which my sine wave lives), I can't get it quite right - matplotlib seems to XOR the regions that overlap in a view of the plot instead of giving me a view in which the ones in front occlude those behind. Here's the relevant bit of my code:

fig = plt.figure()
ax = fig.gca(projection='3d')
ax._axis3don = False
theta = np.linspace(0., 2 * np.pi, 1000)
r = 1.
x = r * np.sin(theta)
y = r * np.cos(theta)
sinez = N * np.sin(theta * m)
ax.plot(x, y, sinez, color='r')
xv = np.append(x, x[::-1])
yv = np.append(y, y[::-1])
zv = np.append(sinez, np.zeros(n))
verts = [zip(xv,yv,zrev),]
poly = Poly3DCollection(verts, facecolors = [cc('r'), cc('b')],
                        edgecolor='None')
poly.set_alpha(0.7)
ax.add_collection3d(poly)

Here's what it looks like: enter image description here

Upvotes: 2

Views: 1111

Answers (2)

tacaswell
tacaswell

Reputation: 87536

matplotlib's main reason for existence is 2D plotting, the 3D stuff is just some clever transforms and can be buggy/hacky. One of the inherent limitations is that matplotlib draws in layers, so it has no notion of 'in front' or 'behind', it only knows the order in which in draws the curves to the canvas (which is confusingly called z-order).

If you want to get this to look right with out re-writing the 3D code, split the sine wave up into pieces and make sure you set the z-order right by hand (see How to draw intersecting planes? for a simpler version of this), but you won't be able to rotate the image.

If you need real 3D, I would suggest looking into mayavi from enthought which is OpenGL based.

Upvotes: 2

danodonovan
danodonovan

Reputation: 20373

In the docs, the devs claim that Poly3DCollection

does a bit of magic with the _facecolors and _edgecolors properties.

which I believe is the XOR effect that you can see here, and looking at the code it's the function do_3d_projection that seems to be doing the magic.

As I see it, you could either subclass Poly3DCollection and rewrite do_3d_projection to get what you want, or maybe think of another way to plot this (perhaps treating the sinusoid and circle as separate objects somehow).

Upvotes: 1

Related Questions