Multiple 3D plots in one window - python

Is there a way to plot multiple plots in one window (graphics are displayed qt)?

Sure.
The keyword is subplot. Read this for a basic overview.
Just look at this official example from here:
from mpl_toolkits.mplot3d.axes3d import Axes3D
import matplotlib.pyplot as plt
# imports specific to the plots in this example
import numpy as np
from matplotlib import cm
from mpl_toolkits.mplot3d.axes3d import get_test_data
# Twice as wide as it is tall.
fig = plt.figure(figsize=plt.figaspect(0.5))
#---- First subplot
ax = fig.add_subplot(1, 2, 1, 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_zlim3d(-1.01, 1.01)
fig.colorbar(surf, shrink=0.5, aspect=10)
#---- Second subplot
ax = fig.add_subplot(1, 2, 2, projection='3d')
X, Y, Z = get_test_data(0.05)
ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)
plt.show()
Output

Related

Python - Plotting two 3D graphs with a contour map

I am trying to plot a figure in Python with two 3D graphs (same function, different angles) and a 2D contour map of the same function and I'm not sure why but the two first figures are okay and the contour map is weird, it appears at the bottom of the two first figures and the sizing is all weird (see the picture attached). Is there a way to place the map at the right of the 2 other figures and to resize it to make it more like a square?
Thank you for your help.
Here's my code :
import numpy as np
import matplotlib.pylab as plt
import matplotlib.cm as cm
from mpl_toolkits.mplot3d import Axes3D
x = np.arange(-5, 5, 0.01)
y = np.arange(-5, 5, 0.01)
X, Y = np.meshgrid(x, y)
Z = 5 + (10 * X**2 + 20 * Y**2) * np.exp((-X**2)-(Y**2)) + 3 *np.sin(X) - np.sin(Y)
fig = plt.figure(figsize=(15,5))
ax1 = plt.subplot(131, projection='3d')
surf1 = ax1.plot_surface(X, Y, Z, cmap=cm.coolwarm)
ax2 = plt.subplot(132, projection='3d')
surf2 = ax2.plot_surface(X, Y, Z, cmap=cm.coolwarm)
for angle in range(0,360):
ax2.view_init(20, angle)
plt.pause(.001)
ax3 = plt.subplot(133)
surf3 = ax3.contour(X, Y, Z, colors='black', linestyles='dashed')
plt.clabel(surf3, fmt = '%.0f', inline=True, fontsize=8)
ax1.set_xlabel('X')
ax2.set_xlabel('X')
ax3.set_xlabel('X')
ax1.set_ylabel('Y')
ax2.set_ylabel('Y')
ax3.set_ylabel('Y')
ax1.set_zlabel('Z')
ax2.set_zlabel('Z')
plt.show()
Got it:
import numpy as np
import matplotlib.pylab as plt
import matplotlib.cm as cm
from mpl_toolkits.mplot3d import Axes3D
x = np.arange(-5, 5, 0.01)
y = np.arange(-5, 5, 0.01)
X, Y = np.meshgrid(x, y)
Z = 5 + (10 * X**2 + 20 * Y**2) * np.exp((-X**2)-(Y**2)) + 3 *np.sin(X) - np.sin(Y)
fig = plt.figure(figsize=(15,5))
ax1 = fig.add_subplot(1, 3, 1, projection='3d')
surf1 = ax1.plot_surface(X, Y, Z, cmap=cm.coolwarm)
ax3 = fig.add_subplot(1, 3, 2)
surf3 = ax3.contour(X, Y, Z, colors='black', linestyles='dashed')
plt.clabel(surf3, fmt = '%.0f', inline=True, fontsize=8)
ax2 = fig.add_subplot(1, 3, 3, projection='3d')
surf2 = ax2.plot_surface(X, Y, Z, cmap=cm.coolwarm)
for angle in range(0,360):
ax2.view_init(20, angle)
plt.pause(.001)
ax1.set_xlabel('X')
ax2.set_xlabel('X')
ax3.set_xlabel('X')
ax1.set_ylabel('Y')
ax2.set_ylabel('Y')
ax3.set_ylabel('Y')
ax1.set_zlabel('Z')
ax2.set_zlabel('Z')
plt.show()

How to plot horizontal stack of heatmaps or a stack of grid?

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)

How do I plot 3 contours in 3D in matplotlib

I have 3 contours, generated by the following:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy import stats
mean0 = [ 3.1627717, 2.74815376]
cov0 = [[0.44675818, -0.04885433], [-0.04885433, 0.52484173]]
mean1 = [ 6.63373967, 6.82700035]
cov1 = [[ 0.46269969, 0.11528141], [0.11528141, 0.50237073]]
mean2 = [ 7.20726944, 2.61513787]
cov2 = [[ 0.38486096, -0.13042758], [-0.13042758, 0.40928813]]
x = np.linspace(0, 10, 100)
y = np.linspace(0, 10, 100)
X, Y = np.meshgrid(x, y)
Z0 = np.random.random((len(x),len(y)))
Z1 = np.random.random((len(x),len(y)))
Z2 = np.random.random((len(x),len(y)))
def pdf0(arg1,arg2):
return (stats.multivariate_normal.pdf((arg1,arg2), mean0, cov0))
def pdf1(arg1,arg2):
return (stats.multivariate_normal.pdf((arg1,arg2), mean1, cov1))
def pdf2(arg1,arg2):
return (stats.multivariate_normal.pdf((arg1,arg2), mean2, cov2))
for i in range (0, len(x)):
for j in range(0,len(y)):
Z0[i,j] = pdf0(x[i],y[j])
Z1[i,j] = pdf1(x[i],y[j])
Z2[i,j] = pdf2(x[i],y[j])
Z0=Z0.T
Z1=Z1.T
Z2=Z2.T
fig3 = plt.figure()
ax3 = fig3.add_subplot(111)
ax3.contour(X,Y,Z0)
ax3.contour(X,Y,Z1)
ax3.contour(X,Y,Z2)
plt.show()
Which, visually, is plotted as the following:
I am wishing to plot all of these in a 3D plot, but when I try do so with:
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
# 3D plots for each contour.
surf1 = ax.plot_surface(X, Y, Z0, cmap=cm.coolwarm, linewidth=0, antialiased=False)
surf2 = ax.plot_surface(X, Y, Z1, cmap=cm.coolwarm, linewidth=0, antialiased=False)
surf3 = ax.plot_surface(X, Y, Z2, cmap=cm.coolwarm, linewidth=0, antialiased=False)
ax.contour(X, Y, Z0, zdir='z', offset=-0.5)
ax.contour(X, Y, Z1, zdir='z', offset=-0.5)
ax.contour(X, Y, Z2, zdir='z', offset=-0.5)
ax.set_zlim(-0.5, 0.31)
plt.show()
The resulting graph is this:
How can I get the other two 3D contours to show nicely?
There is no general solution to this problem. Matplotlib cannot decide to show part of an object more in front than another part of it. See e.g. the FAQ, or other questions, like How to obscure a line behind a surface plot in matplotlib?
One may of course split up the object in several parts if necessary. Here, however, it seems sufficient to add the functions up.
surf1 = ax.plot_surface(X, Y, Z0+Z1+Z2, cmap=plt.cm.coolwarm,
linewidth=0, antialiased=False)
ax.contour(X, Y, Z0+Z1+Z2, zdir='z', offset=-0.5)

Surface and 3d contour in matplotlib

I would like to plot a surface with a colormap, wireframe and contours using matplotlib. Something like this:
Notice that I am not asking about the contours that lie in the plane parallel to xy but the ones that are 3D and white in the image.
If I go the naïve way and plot all these things I cannot see the contours (see code and image below).
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
X, Y = np.mgrid[-1:1:30j, -1:1:30j]
Z = np.sin(np.pi*X)*np.sin(np.pi*Y)
ax.plot_surface(X, Y, Z, cmap="autumn_r", lw=0.5, rstride=1, cstride=1)
ax.contour(X, Y, Z, 10, lw=3, cmap="autumn_r", linestyles="solid", offset=-1)
ax.contour(X, Y, Z, 10, lw=3, colors="k", linestyles="solid")
plt.show()
If a add transparency to the surface facets then I can see the contours, but it looks really cluttered (see code and image below)
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
X, Y = np.mgrid[-1:1:30j, -1:1:30j]
Z = np.sin(np.pi*X)*np.sin(np.pi*Y)
ax.plot_surface(X, Y, Z, cmap="autumn_r", lw=0.5, rstride=1, cstride=1, alpha=0.5)
ax.contour(X, Y, Z, 10, lw=3, cmap="autumn_r", linestyles="solid", offset=-1)
ax.contour(X, Y, Z, 10, lw=3, colors="k", linestyles="solid")
plt.show()
Question: Is there a way to obtain this result in matplotlib? The shading is not necessary, though.
Apparently it is a bug, if you try this
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
X, Y = np.mgrid[-1:1:30j, -1:1:30j]
Z = np.sin(np.pi*X)*np.sin(np.pi*Y)
ax.plot_surface(X, Y, Z, cmap="autumn_r", lw=0, rstride=1, cstride=1)
ax.contour(X, Y, Z+1, 10, lw=3, colors="k", linestyles="solid")
plt.show()
And rotate around, you will see the contour lines disappearing when they shouldn't
I think you want to set the offset to the contour :
ax.contour(X, Y, Z, 10, offset=-1, lw=3, colors="k", linestyles="solid", alpha=0.5)
See this example for more:
http://matplotlib.org/examples/mplot3d/contour3d_demo3.html
And the docs here:
http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#contour-plots
offset: If specified plot a projection of the contour lines on this position in plane normal to zdir
Note, zdir = 'z' by default, but you can project in the x or y direction be setting the zdir accordingly.

Set matplotlib view to be normal to the x-y plane in Python

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

Categories

Resources