Properly rendered 3d plot_surface in matplotlib - python

I am trying to render a surface, but I do not manage to get a pretty visualisation. The plot_surface function from matplotlib gives me the following figure:
produced by the code below. How do I get rid of this transparency and the wireframe that is still visible if you look carefully?
import numpy as np
import matplotlib.pyplot as pl
from mpl_toolkits.mplot3d import Axes3D
pl.ion()
nx = 512
ny = 512
Lx = 2.e6
Ly = 2.e6
x = np.linspace(0., Lx, nx)
y = np.linspace(0., Ly, ny)
xx, yy = np.meshgrid(x,y)
Ld = 6.e4
h = np.exp(-( (xx - 0.5*Lx)**2 + (yy - 0.5*Ly)**2) / Ld**2 )
pl.figure()
ax = pl.subplot(111, projection='3d')
ax.plot_surface(xx/1000., yy/1000., h, alpha=1., cstride=1, rstride=1, linewidth=0)
ax.set_zlim3d(-0.2, 1.)

It's only a workaround, but this works for most matplotlib routines like e.g. contourf (where I had the same problem before); calling the plot routine (in this case plot_surface) twice solves both problems:
The left figure is with calling plot_surface once, the right one calling it twice.
For a non-transparent surface, setting antialiased=False helps (left figure below), with transparency antialiased=True produces very thin lines at the polygon edges (I suspect because the polygons slightly overlap), but they are hardly visible (right figure below).
fig = pl.figure()
ax = pl.subplot(121, projection='3d')
surf = ax.plot_surface(xx/1000., yy/1000., h, alpha=1.0, cstride=1, rstride=1, linewidth=0, antialiased=False)
ax = pl.subplot(122, projection='3d')
surf = ax.plot_surface(xx/1000., yy/1000., h, alpha=0.3, cstride=1, rstride=1, linewidth=0, antialiased=True)

Related

matplotlib 3D surface - gaps / holes in surface

A grid is interpolated with scipy's griddata() and contains values and NaNs. However, when the grid is plotted with mplot3d's plot_surface() there are gaps in the surface (see upper plot). The lower the view height, the more of such gaps are rendered. When the grid is plotted in 2D with imshow() there are no gaps (see lower plot).
Comparison plot_surface and imshow
Here is a close-up:
I couldn't find an answer to this problem and I am wondering whether this is a known issue.
This small example reproduces the problem: (data.txt)
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
Z = np.loadtxt('data.txt')
X = np.linspace(0,3,301)
Y = np.linspace(0,3,301)
X = np.array([X,]*(301)).transpose()
Y = np.array([Y,]*(301))
fig = plt.figure(figsize=(15,15), dpi=100)
ax = fig.add_subplot(2, 1, 1, projection='3d')
plt.hold(True)
ax.view_init(40,300)
surf = ax.plot_surface(X, Y, Z, cmap='jet', rstride=1, cstride=1, antialiased=False, shade=False, alpha=1.0, linewidth=0, vmin=0.25, vmax=0.35);
ax.invert_yaxis()
ax.dist = 11
ax = fig.add_subplot(2, 1, 2)
plt.hold(True)
plt.imshow(Z, cmap='jet', vmin=0.25, vmax=0.35, origin='lower');
plt.show()

create stereoscopic 3d plot with matplotlib

I would like to be able to make 3d plots in matplotlib that can be displayed in stereoscopic 3d, like this:
The camera of the left image is slightly translated with respect to the right. If you practice for a bit, you can trick your brain into having your left eye look at the left image and your right eye at the right image and see 3D on any screen!
Anyway, I would like to be able to make any matplotlib 3d plot show up twice, with one camera slightly translated. I've managed to get just the plot itself in stereo, simply by translating the data:
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(10,5))
axl = fig.add_subplot(1,2,1,projection='3d')
axr = fig.add_subplot(1,2,2,projection='3d')
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
axr.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
axl.plot_surface(X, Y-5, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
for ax in [axr,axl]:
ax.set_zlim(-1.01, 1.01)
ax.set_ylim(-10,10)
ax.view_init(azim=10)
ax.set_axis_off()
This gives the desired effect, but I would like to be able to also show the axes themselves in stereoscopic 3d. I can only find how to set the elevation and azimuth of the camera, using the view_init method of the Axes object. There doesn't seem to be a 'nice' way of translating the camera.
Does anyone know how to do it?

matplotlib : project 3d surface on 2d plot

Is there an equivalent to "Axes3DSubplot.plot_surface" in 2D ?
I am trying to plot the projection of a mesh on the XY-plane in matplotlib (so not in '3d' mode).
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Data (wireframe sphere)
theta, phi = np.meshgrid( np.linspace(0, np.pi/2, 10), np.linspace(0, np.pi/2, 10) )
x = np.sin(theta) * np.cos(phi)
y = np.sin(theta) * np.sin(phi)
z = np.cos(theta)
fig = plt.figure()
# Subplot 3D
ax1 = fig.add_subplot(1, 2, 1, projection='3d', aspect='equal')
colors = matplotlib.cm.jet(np.hypot(x,y))
surface = ax1.plot_surface(x, y, z, rstride=1, cstride=1, facecolors = colors, alpha=0.5 )
projection = ax1.plot_surface(0, y, z, rstride=1, cstride=1, facecolors = colors )
projection.set_edgecolor('k')
# Subplot 2D
ax2 = fig.add_subplot(1, 2, 2, aspect='equal')
ax2.plot(y, z, 'k')
ax2.plot(y.T, z.T, 'k')
I am trying to produce a similar result than :
ax1.plot_surface(0, y, z, rstride=1, cstride=1, facecolors = colors )
But in the 2D subplot. I cannot find an equivalent for plot_surface in the doc of AxesSubplot. The only thing I managed to do is plot the wireframe (but not the facecolors) with :
ax2.plot(y, z, 'k')
ax2.plot(y.T, z.T, 'k')
I cannot upload an image, but basically, I want to put the "colors" in the second subplot.
Thanks,
EDIT:
#Tim
Yeah, I suppose, in this case, I managed to do it with :
ax2.contourf(y, z, np.hypot(x,y), levels=np.hypot(x,y)[0], cmap=matplotlib.cm.jet)
In a more generic case, you'll need the right level-function and a bit of tweaking with the levels and colormap, but it seems doable.
Another solution would be to use matplotlib.patches.Polygon to draw each projected face.
You can use contourf to produce coloured 2D contours:
# Subplot 2D
ax2 = fig.add_subplot(1, 2, 2, aspect='equal')
ax2.contourf(x, y, z, facecolors=colors)
Although this doesn't seem to be exactly what you need, it's a step in the right direction.

mplot3d narrow spline surface missing from output

I have setup mplot3d to provide a 3D surface plot per the example.
When I plot my data I am seeing that the surface is missing from a ridge running through the surface (see image). I noticed that surface filling appears to follow the stride but the grid-lines make viewing difficult at lower step sizes.
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm, pyplot
import numpy
Z = data[-300::]
X,Y = numpy.mgrid[:len(Z), :len(Z[0])]
fig = pyplot.figure(figsize=(20, 10), dpi=800)
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X,
Y,
Z,
rstride=len(Z)/5,
cstride=len(Z[0])/10,
alpha=.6,
linewidths=(.5,),
antialiased=True,
cmap=cm.coolwarm,
vmin=124,
vmax=186
)
cset = ax.contourf(X, Y, Z, zdir='z', offset=130, cmap=cm.coolwarm, vmin=124, vmax=186)
ax.set_xlim(len(Z) * 1.2, 0)
ax.set_ylim(0, len(Z[0]) * 1.2)
ax.elev = 25
ax.azim = 20
cb = fig.colorbar(surf, shrink=0.5, aspect=5)
Is there a way to fill the missing surface?
The only way i have found to accomplish this is by setting the stride to one and linewidth to 0. The downside to this is that I appear to lose the grid overlay.
surf = ax.plot_surface(X,
Y,
Z,
shade=True,
rstride=1, cstride=1, linewidth=0,
linewidths=(.5,),
antialiased=True,
)

How to disable perspective in mplot3d?

Is it possible to disable the perspective when plotting in mplot3d, i.e. to use the orthogonal projection?
This is now official included since matplot version 2.2.2 Whats new | github
So for plotting a perspective orthogonal plot you have to add proj_type = 'ortho' then you should have something like that:
fig.add_subplot(121, projection='3d', proj_type = 'ortho')
Example Picture
]2
Example is taken from the official example script and edited
'''
======================
3D surface (color map)
======================
Demonstrates plotting a 3D surface colored with the coolwarm color map.
The surface is made opaque by using antialiased=False.
Also demonstrates using the LinearLocator and custom formatting for the
z axis tick labels.
'''
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
fig = plt.figure(figsize=(16,4))
ax.view_init(40, 60)
ax = fig.add_subplot(121, projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
ax = fig.add_subplot(122, projection='3d', proj_type = 'ortho')
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.viridis, linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
plt.show()
NOTE: This has been updated see this answer instead.
Sort of, you can run this snippet of code before you plot:
import numpy
from mpl_toolkits.mplot3d import proj3d
def orthogonal_proj(zfront, zback):
a = (zfront+zback)/(zfront-zback)
b = -2*(zfront*zback)/(zfront-zback)
return numpy.array([[1,0,0,0],
[0,1,0,0],
[0,0,a,b],
[0,0,0,zback]])
proj3d.persp_transformation = orthogonal_proj
It is currently an open issue found here.

Categories

Resources