I have this following code which attempts to plot a function +/- f which defines the graphene dispersion in the momentum space.
# 3D Plot of graphene dispersion
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
def sqrt(x):
return np.sqrt(x)
def cos(x):
return np.cos(x)
# Constants
a = 1.0
d = a*np.sqrt(3)
t = 2.7
t2 = 0.5
print "The display is not up to the mark! Modification needed.\n"
fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.arange(-2.0*np.pi, 2.0*np.pi, 0.1)
y = np.arange(-2.0*np.pi, 2.0*np.pi, 0.1)
x, y = np.meshgrid(x, y)
f=t*sqrt(3.0+2.0*cos(a*x)+4.0*cos(a/2.0*x)*cos(d/2.0*y))
surf = ax.plot_surface(x, y, f, rstride=1, cstride=1, cmap=cm.jet, linewidth=0, antialiased=False)
f=-f
surf = ax.plot_surface(x, y, f, rstride=1, cstride=1, cmap=cm.jet, linewidth=0, antialiased=False)
ax.set_zlim3d(-3.0, 3.0)
fig.colorbar(surf, shrink=1.0, aspect=5)
plt.show()
which gives me a plot that overflows the z-axis boundary :
However, keeping the same function definition and using gnuplot or Mathematica I was able to produce this
and this
Can any of the last two be reproduced by using python with matplotlib?
I'm not quite sure what you want, since you explicitly set the z-limits inside the range of the data (ax.set_zlim3d(-3.0, 3.0)), but I get a similar plot simply by commenting out this line (and picking a nicer colormap):
# 3D Plot of graphene dispersion
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
sqrt = np.sqrt
cos = np.cos
# Constants
a = 1.0
d = a*np.sqrt(3)
t = 2.7
t2 = 0.5
fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.arange(-2.0*np.pi, 2.0*np.pi, 0.1)
y = np.arange(-2.0*np.pi, 2.0*np.pi, 0.1)
x, y = np.meshgrid(x, y)
f=t*sqrt(3.0+2.0*cos(a*x)+4.0*cos(a/2.0*x)*cos(d/2.0*y))
surf = ax.plot_surface(x, y, f, rstride=1, cstride=1, cmap=plt.get_cmap('PuOr'),
linewidth=0, antialiased=False)
f=-f
surf = ax.plot_surface(x, y, f, rstride=1, cstride=1, cmap=plt.get_cmap('PuOr'),
linewidth=0, antialiased=False)
#ax.set_zlim3d(-3.0, 3.0)
fig.colorbar(surf, shrink=1.0, aspect=5)
plt.show()
(Note also that you don't need to define a wrapper function to create an alias to np.sqrt, etc. Functions are first class objects in Python and you can simply assign a name: sqrt = np.sqrt.)
Related
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:
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?
The following python code was in a reader from my university for a python course. It should plot a 3D figure but when I try to run the program it doesn't show anything.
from numpy import exp,arange,meshgrid
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import axes3d, Axes3D
def z_func(x,y):
return (1-(x**2+y**3))*exp(-(x**2+y**2)/2)
x = arange(-3.0,3.0,0.1)
y = arange(-3.0,3.0,0.1)
X,Y = meshgrid(x,y)
Z = z_func(X,Y)
fig = plt.figure()
ax = Axes3D(fig)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.RdBu,
linewidth=0, antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show
It doesn't give an error or anything.
plt.show is a function. You need to call it: plt.show().
This code found here is an example of a 3d surface plot:
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(-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)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, 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'))
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
and yields
Is there a way to set the plot view so that it is perfectly normal to the x-y axis? This basically turns the 3-d plot into a 2-d one, where you can use the colourmap to judge the magnitude of the z-variable, rather than its displacement from the z=0 datum.
What you want is the ax.view_init function, with elev=90. See this answer
Edit:
after adding ax.view_init(azim=0, elev=90) to your script, I get this:
You need pcolor for that:
import matplotlib.pyplot as plt
import numpy as np
dx, dy = 0.25, 0.25
y, x = np.mgrid[slice(-5, 5 + dy, dy),
slice(-5, 5 + dx, dx)]
R = np.sqrt(x**2 + y**2)
z = np.sin(R)
z = z[:-1, :-1]
z_min, z_max = -np.abs(z).max(), np.abs(z).max()
plt.subplot()
plt.pcolor(x, y, z, cmap='RdBu', vmin=z_min, vmax=z_max)
plt.axis([x.min(), x.max(), y.min(), y.max()])
plt.colorbar()
plt.show()
Additional demos are here
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.