I am using the solution proposed here to plot an image in 3D using matplotlib. However, even for very reasonable image sizes (128x128), the refresh rate is annoyingly slow. On my computer, the following cannot go higher than 2 frames/s.
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
import numpy as np
X, Y = np.meshgrid(np.arange(128), np.arange(128))
Z = np.zeros_like(X)
im = np.sin(X/10 + Y/100)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=plt.cm.BrBG(im), shade=False)
plt.show()
Is there any way to accelerate the above plot? I understand that mplot3d does not support hardware acceleration, but I feel the simple plot above ought to be faster even on CPU.
You can try mayaVi library for better interactive data visualization.
#import matplotlib.pyplot as plt
#from mpl_toolkits import mplot3d
import numpy as np
from mayavi import mlab
X, Y = np.meshgrid(np.arange(128), np.arange(128))
Z = np.zeros_like(X)
im = np.sin(X/10 + Y/100)
#fig = plt.figure()
#x = fig.add_subplot(111, projection='3d')
src = mlab.pipeline.array2d_source(im)
warp = mlab.pipeline.warp_scalar(src)
normals = mlab.pipeline.poly_data_normals(warp)
surf = mlab.pipeline.surface(normals)
mlab.show()
#ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=plt.cm.BrBG(im), shade=False)
#plt.show()
MayaVi Documentation
Related
How can I plot the paraboloid after fitting it using Python? in order to get that plot
import numpy as np
import scipy.optimize as opt
import matplotlib.pyplot as plt
doex = [0.4,0.165,0.165,0.585,0.585]
doey = [.45, .22, .63, .22, .63]
doez = np.array([1, .99, .98,.97,.96])
def paraBolEqn(data,a,b,c,d):
x,y = data
return -(((x-b)/a)**2+((y-d)/c)**2)+1.0
popt,pcov=opt.curve_fit(paraBolEqn,np.vstack((doex,doey)),doez,p0=[1.5,0.4,1.5,0.4])
print(popt)
Everything you need to know is documented at the mplot3d tutorial, where the different methods to make 3d plots in matplotlib are presented.
Your desired plot can be reproduced using the methods Axes3D.plot_wireframe and Axes3D.scatter:
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111, projection='3d')
x, y = np.meshgrid(np.linspace(np.min(doex), np.max(doex),10), np.linspace(np.min(doey),np.max(doey), 10))
ax.plot_wireframe(x, y, paraBolEqn((x,y), *popt))
ax.scatter(doex, doey, doez, color='b')
which results in the following plot:
I use matplotlib to simulate Y^2 + Z^2 = (SinX)^2
That is,the sine graph rotate 360 degrees based on x axis.
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
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
t = np.arange(-5, 5, 0.25)
X,Y = np.meshgrid(t,t)
Z = np.sin(t)**2
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Following is the image
However,that seems not fit my expectation.
Is my way reasonable?
Or is there any way can implement in vpython?
Here is a VPython program that plots a function in 3D, which may be related to what you want to do.
http://www.glowscript.org/#/user/GlowScriptDemos/folder/Examples/program/Plot3D
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.
I'd like to generate surface plots in Python using matplotlib with around 100x100 points. I'm using the code below just to test it out:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 10, 0.1)
Y = np.arange(0, 10, 0.1)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=True)
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
plt.show()
It all works fine, except for the fact that rotating the plot is very slow - the view changes around once per second, which is less than ideal. Using a wireframe plot instead of a surface plot gives acceptable performance, but it makes the data harder to see and means a colourmap can't be used. (Turning off anti-aliasing actually makes little difference.)
Is there anything I can do to speed it up, even if it's only a little?
I'm using the mpl_toolkits to plot surfaces in 3d using Axes3D and plot_surface.
I visualize the output in the following way,
You can clearly see that there is a grey tint to the entire surface when the colors are supposed to resemble the colorbar on the right.
I see this behavior in several other plots out there doing similar things. For example here https://stackoverflow.com/a/20475233/2495342
I am using the latest anaconda distribution of python and running my code within spyder which uses the Qt4Agg backend. I get the same behavior under linux and windows. Using a different colormap does not help either. The visualization is always tinted grey.
I haven't found much help through google, so any help is appreciated.
Here is a quick demo
import numpy as np
from matplotlib import pyplot
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
X, Y = np.meshgrid(np.arange(-1, 1, 0.1), np.arange(-1, 1, 0.1))
Z = np.zeros_like(X)
F = np.sqrt(X**2 + Y**2)
F -= np.min(F)
F /= np.max(F)
fig = pyplot.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=cm.coolwarm(F))
Which returns
use shade argument:
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
facecolors=cm.coolwarm(F), shade=False)