I intend to plot an axis-aligned view on 3d objects with projection="ortho" side by side with 2d (profile) data, but I just cannot figure out how to make the vertical axes match.
In the following example I would like to have the second and the third subplot share the vertical axes:
Here is the corresponding code:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
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 3d view
fig = plt.figure(figsize=(16,4))
ax1 = fig.add_subplot(131, projection='3d')
ax1.view_init(40, 60)
surf = ax1.plot_surface(X, Y, Z, cmap=cm.viridis,linewidth=0)
# plot one side
ax2 = fig.add_subplot(132, projection='3d', proj_type = 'ortho')
ax2.view_init(0, 0)
surf = ax2.plot_surface(X, Y, Z, cmap=cm.viridis, linewidth=0)
ax2.set_zlim([-0.2,1])
# plot some 2d information
ax3 = fig.add_subplot(133)
ax3.set_ylim([-0.2,1])
plt.show()
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 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)
I'm very new in Python and trying to plot a single curve on a surface.
Here is where I came so far and plotted a surface in s domain:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import cmath
x = np.linspace(-400, 0, 100)
y = np.linspace(-100, 100, 100)
X, Y = np.meshgrid(x,y)
fc=50
wc=2*np.pi*fc
s = X + Y*1j
Z= abs(1/(1+s/wc))
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z)
ax.plot(X, Y, Z)
plt.ylabel('Im')
plt.show()
I now need to plot the curve for X = 0 in different color which means the curve on the same surface along the imaginary axis. surf = ax.plot_surface(0, Y, Z) did not work. Does anybody have experience with such plot?
I'm assuming you meant you wanted to plot y=0 instead of x=0 (since x=0 would be pretty boring).
Since you want to plot a single slice of your data, you can't use the meshgrid format (or if you can, it would require some weird indexing that I don't want to figure out).
Here's how I would plot the y=0 slice:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import cmath
x = np.linspace(-400, 0, 100)
y = np.linspace(-100, 100, 100)
X, Y = np.meshgrid(x,y)
fc=50
wc=2*np.pi*fc
s = X + Y*1j
Z= abs(1/(1+s/wc))
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z)
# create data for y=0
z = abs(1/(1+x/wc))
ax.plot(x,np.zeros(np.shape(x)),z)
plt.ylabel('Im')
plt.show()
I am using mplot3d from the mpl_toolkits library. When displaying the 3D surface on the figure I'm realized the axis were not positioned as I wished they would.
Let me show, I have added to the following screenshot the position of each axis:
Is there a way to change the position of the axes in order to get this result:
Here's the working code:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
ax = Axes3D(plt.figure())
def f(x,y) :
return -x**2 - y**2
X = np.arange(-1, 1, 0.02)
Y = np.arange(-1, 1, 0.02)
X, Y = np.meshgrid(X, Y)
Z = f(X, Y)
ax.plot_surface(X, Y, Z, alpha=0.5)
# Hide axes ticks
ax.set_xticks([-1,1])
ax.set_yticks([-1,1])
ax.set_zticks([-2,0])
ax.set_yticklabels([-1,1],rotation=-15, va='center', ha='right')
plt.show()
I have tried using xaxis.set_ticks_position('left') statement, but it doesn't work.
No documented methods, but with some hacking ideas from https://stackoverflow.com/a/15048653/1149007 you can.
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = ax = fig.add_subplot(111, projection='3d')
ax.view_init(30, 30)
def f(x,y) :
return -x**2 - y**2
X = np.arange(-1, 1, 0.02)
Y = np.arange(-1, 1, 0.02)
X, Y = np.meshgrid(X, Y)
Z = f(X, Y)
ax.plot_surface(X, Y, Z, alpha=0.5)
# Hide axes ticks
ax.set_xticks([-1,1])
ax.set_yticks([-1,1])
ax.set_zticks([-2,0])
ax.xaxis._axinfo['juggled'] = (0,0,0)
ax.yaxis._axinfo['juggled'] = (1,1,1)
ax.zaxis._axinfo['juggled'] = (2,2,2)
plt.show()
I can no idea of the meaning of the third number in triples. If set zeros nothing changes in the figure. So should look in the code for further tuning.
You can also look at related question Changing position of vertical (z) axis of 3D plot (Matplotlib)? with low level hacking of _PLANES property.
Something changed, code blow doesn't work, all axis hide...
ax.xaxis._axinfo['juggled'] = (0,0,0)
ax.yaxis._axinfo['juggled'] = (1,1,1)
ax.zaxis._axinfo['juggled'] = (2,2,2)
I suggest using the plot function to create a graph
There is a 'color' argument to Axes3D's bar3d function which can accept arrays to color individual bars different colors - but how would I apply a color map (i.e. cmap = cm.jet) in the same way as a plot_surface function for example ? This would make a bar of a certain height a color which reflects its height.
http://matplotlib.sourceforge.net/examples/mplot3d/hist3d_demo.html
http://matplotlib.sourceforge.net/mpl_toolkits/mplot3d/api.html
Following up the answer provided by Ferguzz, here is a more complete/up-to-date solution:
import matplotlib.colors as colors
import matplotlib.cm as cm
dz = height_values
offset = dz + np.abs(dz.min())
fracs = offset.astype(float)/offset.max()
norm = colors.Normalize(fracs.min(), fracs.max())
color_values = cm.jet(norm(fracs.tolist()))
ax.bar3d(xpos,ypos,zpos,1,1,dz, color=color_values)
Please pay attention to the following points:
You should have all variables (such as xpos, ypos) defined similar to the code in https://matplotlib.org/examples/pylab_examples/hist_colormapped.html
normalize() is now Normalize()
fracs is in type Series (from pandas) and must be converted to list
Here is my solution:
offset = dz + np.abs(dz.min())
fracs = offset.astype(float)/offset.max()
norm = colors.normalize(fracs.min(), fracs.max())
colors = cm.jet(norm(fracs))
ax.bar3d(xpos,ypos,zpos,1,1,dz, color=colors)
The first line is only required if your data goes negative.
Code adapted from here http://matplotlib.sourceforge.net/examples/pylab_examples/hist_colormapped.html.
You can pass a color array to the facecolors argument, it can set every patches in the surface a color.
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)
colors = np.random.rand(40, 40, 4)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=colors,
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()