I am trying to plot function f(x,y)=(x+2)*y^2 with some iso level curves projected on x-y plane. The code I used is this:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d, Axes3D
import pylab as p
fig = plt.figure()
ax = Axes3D(fig)
X = np.arange(0, 2.5, 0.1)
Y = np.arange(0, 2.5, 0.1)
X, Y = np.meshgrid(X, Y)
Z = ((X+2))*(Y**2)
surf = ax.plot_surface(X, Y, Z,rstride=1, cstride=1, alpha=0.3, cmap=cm.jet)
cset=plt.contour(X,Y,Z,zdir='z',offset=0)
ax.clabel(cset, fontsize=9, inline=1)
ax.set_zlim3d(0, 30)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
My problem is that zdir doesn't work, that is the contour lines are on the surface and not on x-y plane.
Any ideas?
Thanks in advance
Your code works fine for me (matplotlib 1.0.1).
Btw: It seems that this example was added to gallery with matplotlib 1.0. Maybe this is a problem the previous version?
zdir defines the direction to project. (zdir='x' projects along the x axis) offset defines the location of the plane to be projected onto (along the axis defined by zdir)
Example
I'm going to guess what you want is:
cset=plt.contour(X,Y,Z,zdir='z',offset=30)
-> xs and ys: These are coordinates for x and y axes
-> zs: This is the value(s) for z axis. It can be one for all points or one for each point
--> zdir: This will choose what will be the z-axis dimension (usually this is zs, but can
be xs or ys)
Related
I am trying to plot a 1D line along with a 2D surface in matplotlib with Axes3D:
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-1., 1.1, 0.1)
y = x.copy()
X, Y = np.meshgrid(x, y)
Z = np.abs(X) + np.abs(Y)
plt.close('all')
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(np.zeros_like(y), y, 1, color='k')
ax.plot(x, np.zeros_like(x), 1, color='k')
surf = ax.plot_surface(X, Y, Z, color='w')
plt.show(block=False)
but the 2D plot somehow hides the lines:
If I comment the surf = plot_surface(...) code line, the 1D lines show correctly:
How can I have the lines showing correctly along with the surface?
Axes3D.plot_surface() apparently accepts a transparency (alpha) argument, which actually gets forwarded to a base class, Poly3DCollection.
And of course the line plot() calls accept a linewidth argument.
So if you render the line plots with thicker lines and you render the surface with some transparency, you should be able to find a combination of settings which let you see both the lines and the surface in a balanced way.
https://matplotlib.org/tutorials/toolkits/mplot3d.html#mpl_toolkits.mplot3d.Axes3D.plot_surface
https://matplotlib.org/api/_as_gen/mpl_toolkits.mplot3d.art3d.Poly3DCollection.html#mpl_toolkits.mplot3d.art3d.Poly3DCollection
You can also achieve this by using the zorder in the plot_surface and plot commands to make the lines sit on top of the surface. E.g.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-1., 1.1, 0.1)
y = x.copy()
X, Y = np.meshgrid(x, y)
Z = np.abs(X) + np.abs(Y)
plt.close('all')
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, color='w', zorder=1)
ax.plot(np.zeros_like(y), y, 1, color='k', zorder=10)
ax.plot(x, np.zeros_like(x), 1, color='k', zorder=11)
plt.show(block=False)
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")
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
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()
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.