I have an issue with smoothing out the mesh representation of my 3D surface with matplotlib. Below, please see my example. I am having a hard time figuring out how to make the plot look nicer/smoother if possible. Thank you for your time in advance!
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import LightSource
import numpy as np
X = [1,1,1,1,1,1,50,50,50,50,50,50]
Y = [3,5,7,8,9,10,3,5,7,8,9,10]
Z = [5.23,3.11,17.54,0.93,40.11,10.15,1.47,14.32,5.46,55.93,40.8,10.2]
x = np.reshape(X, (2, 6))
y = np.reshape(Y, (2, 6))
z = np.reshape(Z, (2, 6))
X, Y = np.meshgrid(x, y)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z)
ax.set_xlabel('Persistence Length')
ax.set_ylabel('Complexity')
ax.set_zlabel('Relative number of configurational states')
surf = ax.plot_surface(x, y, z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
To obtain smooth line/surface you can set antialiased=True on the surface plot. Note that you were plotting two identical surface: in the following example I have eliminated the first.
To obtain a smoother mesh, you probably want to interpolate between your data points. One way to do that is to use griddata from the scipy.interpolate module.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.interpolate import griddata
X = [1,1,1,1,1,1,50,50,50,50,50,50]
Y = [3,5,7,8,9,10,3,5,7,8,9,10]
Z = [5.23,3.11,17.54,0.93,40.11,10.15,1.47,14.32,5.46,55.93,40.8,10.2]
points = np.array([X, Y]).T
# create a grid of coordinates between the minimum and
# maximum of your X and Y. 50j indicates 50 discretization
# points between the minimum and maximum.
X_grid, Y_grid = np.mgrid[1:50:50j, 3:10:50j]
# interpolate your values on the grid defined above
Z_grid = griddata(points, Z, (X_grid, Y_grid), method='cubic')
fig = plt.figure(constrained_layout=True)
ax = fig.add_subplot(111, projection='3d')
ax.set_xlabel('Persistence Length')
ax.set_ylabel('Complexity')
ax.set_zlabel('Relative number of configurational states')
surf = ax.plot_surface(X_grid, Y_grid, Z_grid, cmap=cm.coolwarm,
linewidth=0, antialiased=True)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Here is an example of antialiased=False on the left, vs antialiased=True on the right:
Related
I have some points and I plot the surface of them using the code below:
import matplotlib.pyplot as plt
from matplotlib import cm, colors
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# Create a sphere
r = 1
pi = np.pi
cos = np.cos
sin = np.sin
phi, theta = np.mgrid[0.0:pi:20j, 0.0:2.0*pi:20j]
radis=np.random.normal(1,0.2,(20,20))
x = radis*sin(phi)*cos(theta)
y = radis*sin(phi)*sin(theta)
z = radis*cos(phi)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(
x, y, z, rstride=1, cstride=1, color='c', alpha=0.3, linewidth=0)
ax.scatter3D(x,y,z, c='r')
ax.set_xlim([-1,1])
ax.set_ylim([-1,1])
ax.set_zlim([-1,1])
# ax.set_aspect("equal")
plt.tight_layout()
plt.show()
Then I get the 3d plot result:
The thing I want to do is that get the image of any plane, like z=0.
Is there any method or library can cover this problem?
I want to plot a stack of heatmaps, contour, or grid computed over time. The plot should like this,
I have tried this:
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.linspace(0, 1, 100)
X, Z = np.meshgrid(x, x)
Y = np.sin(X)*np.sin(Z)
levels = np.linspace(-1, 1, 40)
ax.contourf(X, Y, Z, zdir='y')
ax.contourf(X, Y+3, Z, zdir='y')
ax.contourf(X, Y+7, Z, zdir='y')
ax.legend()
ax.view_init(15,155)
plt.show()
For one my plot looks ugly. It also does not look like what I want. I cannot make a grid there, and the 2d surfaces are tilted.
Any help is really appreciated! I am struggling with this.
Related stackoverflow:
[1] Python plot - stacked image slices
[2] Stack of 2D plot
How about making a series of 3d surface plots, with the data your wish to present in contour plotted as facecolor?
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, 0.25)
Z = np.arange(-5, 5, 0.25)
X, Z = np.meshgrid(X, Z)
C = np.random.random(size=40*40*3).reshape((40, 40, 3))
ax.plot_surface(X, np.ones(shape=X.shape)-1, Z, facecolors=C, linewidth=0)
ax.plot_surface(X, np.ones(shape=X.shape), Z, facecolors=C, linewidth=0)
ax.plot_surface(X, np.ones(shape=X.shape)+1, Z, facecolors=C, linewidth=0)
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()
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'm new to python and after installing it I've accomplished to plot my 3d data using matplotlib. Sadly the only thing I don't know how to get done is the color part. My image just shows the surface but doesn't use the color bar at all. Here is my code.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
from matplotlib.mlab import griddata
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
data = np.genfromtxt('Uizq.txt')
x = data[:,0]
y = data[:,1]
z = data[:,2]
xi = np.linspace(min(x), max(x))
yi = np.linspace(min(y), max(y))
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('U')
X, Y = np.meshgrid(xi, yi)
Z = griddata(x, y, z, xi, yi)
ax.set_zlim3d(np.min(Z), np.max(Z))
surf = ax.plot_surface(X, Y, Z, rstride=2, cstride=2, cmap=cm.jet,
linewidth=0.5, antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
you can obviously see that it is all blue, and I want to relate the color with "U" using the full cm.jet spectrum. This might be a very noob question, so sorry if you rolled your eyes.
Add the line
surf.set_clim([np.min(Z),np.max(Z)])
before you add the color bar.
It seems that the 3D plotting does not take into account the masking, so you are including NaN in the data, which confuses the automatic color limits.