How can I speed up rendering of surface plots in matplotlib? - python

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?

Related

Set 3d plot linewidth in matplotlib 2.x

I'm using a newer version of matplotlib and the argument that sets the linewidth was removed. They seem to have changed it so I set it in Collections object, but I can't find a way of doing this.
I tried their example with a different linewidth:
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.
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.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=10, 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()
But as the figure shows, it doesn't add lines to my surface.
What is the new method for setting linewidths?
Thanks!
The linewidth can of course only take effect if there is actually a line to be shown. So one would need to specify the color of the lines to show in order to see them.
surf = ax.plot_surface(X, Y, Z, cmap="RdYlGn", linewidth=2, edgecolor="limegreen")

Python Simulate Y^2 + Z^2 = (SinX)^2

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

Matplotlib 3D: axis bounds always too large (doesn't set lims correctly)

I have an issue (bug?) with 3D plotting in matplotlib that I wonder if anyone may be able to help with please?
As can be seen by the matplotlib gallery example plots (e.g. from: https://matplotlib.org/examples/mplot3d/surface3d_demo.html), when the user sets the axis limits manually, and a tick is placed at the limit, the axis bound is extended a little:
I want the axis to show the 1.01 tick label, but this should be the vertex of the cube (with no grey space / black axis line above it). Is this possible please?
As a separate, more minor request, I'd then like to draw a solid black line around the edge of the grid to make it stand out. This is less important than fixing the bounds, however.
For reference, here is the code that makes the above plot:
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.
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.
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()

Plotting an image in 3D resulting in very slow interaction

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

Set aperture in 3D plot in Python [duplicate]

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