How to draw 3D curves by SciPy? - python

I draw a 2D curve with the code
c = 11
x = np.arange(0, 5, 0.1)
y = np.exp(c)/x
plt.plot(x,y)
How can I draw a series of the x,y curves while the z axis is c? The first line will be changed to
c = np.arange(1, 70, 1)
How can I draw the 70 x,y curves along the z axis?

You could use matplotlibs Axes3D, a tutorial can be found here:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
c = np.arange(1, 10, 1) # made this 10 so that the graph is more readable
x = np.arange(0, 5, 0.1)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for i in c:
y = np.exp(i) / x
ax.plot(x, y, i)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
plt.show()
Which gives the figure:

Related

Plot 3d points (x,y,z) in 2d plot with colorbar

I have computed a lot (~5000) of 3d points (x,y,z) in a quite complicated way so I have no function such that z = f(x,y). I can plot the 3d surface using
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
X = surface_points[:,0]
Y = surface_points[:,1]
Z = surface_points[:,2]
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
surf = ax.plot_trisurf(X, Y, Z, cmap=cm.coolwarm, vmin=np.nanmin(Z), vmax=np.nanmax(Z))
I would like to plot this also in 2d, with a colorbar indicating the z-value. I know there is a simple solution using ax.contour if my z is a matrix, but here I only have a vector.
Attaching the plot_trisurf result when rotated to xy-plane. This is what I what like to achieve without having to rotate a 3d plot. In this, my variable surface_points is an np.array with size 5024 x 3.
I had the same problems in one of my codes, I solved it this way:
import numpy as np
from scipy.interpolate import griddata
import matplotlib.pylab as plt
from matplotlib import cm
N = 10000
surface_points = np.random.rand(N,3)
X = surface_points[:,0]
Y = surface_points[:,1]
Z = surface_points[:,2]
nx = 10*int(np.sqrt(N))
xg = np.linspace(X.min(), X.max(), nx)
yg = np.linspace(Y.min(), Y.max(), nx)
xgrid, ygrid = np.meshgrid(xg, yg)
ctr_f = griddata((X, Y), Z, (xgrid, ygrid), method='linear')
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.contourf(xgrid, ygrid, ctr_f, cmap=cm.coolwarm)
plt.show()
You could use a scatter plot to display a projection of your z color onto the x-y axis.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
N = 10000
surface_points = np.random.rand(N,3)
X = surface_points[:,0]
Y = surface_points[:,1]
Z = surface_points[:,2]
# fig = plt.figure()
# ax = fig.add_subplot(projection='3d')
# surf = ax.plot_trisurf(X, Y, Z, cmap=cm.coolwarm, vmin=np.nanmin(Z), vmax=np.nanmax(Z))
fig = plt.figure()
cmap = cm.get_cmap('coolwarm')
color = cmap(Z)[..., :3]
plt.scatter(X,Y,c=color)
plt.show()
Since you seem to have a 3D shape that is hollow, you could split the projection into two like if you cur the shape in two pieces.
fig = plt.figure()
plt.subplot(121)
plt.scatter(X[Z<0.5],Y[Z<0.5],c=color[Z<0.5])
plt.title('down part')
plt.subplot(122)
plt.scatter(X[Z>=0.5],Y[Z>=0.5],c=color[Z>+0.5])
plt.title('top part')
plt.show()

matplotlib 3d: moving tick's label

Is there a way to move tick labels in Matplot3dlib like this?
from mpl_toolkits import mplot3d
import numpy as np
import matplotlib.pyplot as plt
x = np.outer(np.linspace(-2, 2, 30), np.ones(30))
y = x.copy().T # transpose
z = np.cos(x ** 2 + y ** 2)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot_surface(x, y, z,cmap='viridis', edgecolor='none')
ax.set_title('Surface plot')
plt.show()
There are some ways using pad parameters.
However, I want to move more precisely like figure in the link above.
Any help appreciated.
-- Addition --
When I changing PAD parameter like the code below, the tick's label is more closer to the axis. However, I want to move it a little bit more to -x direction.
tick's label position changing
from mpl_toolkits import mplot3d
import numpy as np
import matplotlib.pyplot as plt
x = np.outer(np.linspace(-2, 2, 30), np.ones(30))
y = x.copy().T # transpose
z = np.cos(x ** 2 + y ** 2)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot_surface(x, y, z,cmap='viridis', edgecolor='none')
ax.set_title('Surface plot')
ax.tick_params(axis='x', which='major', pad=-5)
plt.show()

Multiple 2D contour plots in one 3D figure in python

Is there any way available in python to plot multiple 2D contour plots in one 3D plot in python. I am currently using matplotlib for contouring, but not finding any option for what I am searching for. A sample image I have added. But I want to do it on Z-axis.
You can try this.
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.linspace(0, 1, 100)
X, Y = np.meshgrid(x, x)
levels = np.linspace(-0.1, 0.4, 100) #(z_min,z_max,number of contour),
a=0
b=1
c=2
Z1 = a+.1*np.sin(2*X)*np.sin(4*Y)
Z2 = b+.1*np.sin(3*X)*np.sin(4*Y)
Z3 = c+.1*np.sin(4*X)*np.sin(5*Y)
plt.contourf(X, Y,Z1, levels=a+levels,cmap=plt.get_cmap('rainbow'))
plt.contourf(X, Y,Z2, levels=b+levels,cmap=plt.get_cmap('rainbow'))
plt.contourf(X, Y,Z3, levels=c+levels,cmap=plt.get_cmap('rainbow'))
ax.set_xlim3d(0, 1)
ax.set_ylim3d(0, 1)
ax.set_zlim3d(0, 2)
plt.show()
In order to plot true 2-D contour plots in one 3D plot, try this:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.linspace(0, 1, 100)
X, Y = np.meshgrid(x, x)
Z1 = .1*np.sin(2*X)*np.sin(4*Y)
Z2 = .1*np.sin(3*X)*np.sin(4*Y)
Z3 = .1*np.sin(4*X)*np.sin(5*Y)
levels=np.linspace(Z1.min(), Z1.max(), 100)
ax.contourf(X, Y,Z1, levels=levels, zdir='z', offset=0, cmap=plt.get_cmap('rainbow'))
levels=np.linspace(Z2.min(), Z2.max(), 100)
ax.contourf(X, Y,Z2, levels=levels, zdir='z', offset=1, cmap=plt.get_cmap('rainbow'))
levels=np.linspace(Z3.min(), Z3.max(), 100)
ax.contourf(X, Y,Z3, levels=levels, zdir='z', offset=2, cmap=plt.get_cmap('rainbow'))
ax.set_xlim3d(0, 1)
ax.set_ylim3d(0, 1)
ax.set_zlim3d(0, 2)
plt.show()
enter image description here

How to set zdir in Axes3D of matplotlib to get better waterfall

I am planning to plot waterfall like figures from multi-text data files, x is the wavelength, y are the responses, z is the frame number. x and y have the same dimensions(e.x. 5000 data). Basically, simplified my code is something like the following, I find I can not get the right view. What I want is the z-axis and y-axis be exchanged,
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from numpy import arange, sin, pi
x = arange(0.0, 10, 0.04)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for z in range(0,8):
y = sin(2*x*pi*z)
ax.plot(x, y, z )
plt.xlabel(' x', fontsize = 12, color = 'black')
plt.ylabel(' y', fontsize = 12, color = 'black')
plt.show()
with the "zdir='y'"
Without zdir='y'
What I want is Z-axis and y-axis be exchanged in Fig2. Thanks a lot!
In principle using zdir="y" seems the correct approach. That would however mean to supply the y argument as last one in the call,
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from numpy import arange, sin, pi
x = arange(0.0, 10, 0.04)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for y in list(range(0,8))[::-1]:
z = sin(2*x*pi*y)
ax.plot(x, z ,y, zdir="y")
plt.xlabel(' x', fontsize = 12, color = 'black')
plt.ylabel(' y', fontsize = 12, color = 'black')
ax.set_ylim(0,9)
ax.set_zlim(-1,1)
plt.show()
Not sure, you can achieve this with np.arange, but you can define x and y with np.linspace
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from numpy import sin, pi, linspace
x = linspace(0.0, 10, 100)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for k in range(1, 4):
#sine wave with amplitude modulation by k
z = sin(2 * x * pi) * k + k
#keeping y constant for each k
y = linspace(k, k, 100)
ax.plot(x, y, z )
plt.xlabel(' x', fontsize = 12, color = 'black')
plt.ylabel(' y', fontsize = 12, color = 'black')
plt.show()
Difference here is that np.linspace has as parameter number of steps, while np.arange uses the step size.

Python plotting 2d data on to 3d axes

I've had a look at matplotlib's examples of 3d plots, but none of these give me what I want to plot, something like:
The plot shows a series of measurements on the y-axis (N) and each measurement has an intensity spectrum (p/2hk_L), i.e. N is fixed for each line you see in the graph. What is the easiest function to use to plot data like this?
Here is a try:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.linspace(-50,50,100)
y = np.arange(25)
X,Y = np.meshgrid(x,y)
Z = np.zeros((len(y),len(x)))
for i in range(len(y)):
damp = (i/float(len(y)))**2
Z[i] = 5*damp*(1 - np.sqrt(np.abs(x/50)))
Z[i] += np.random.uniform(0,.1,len(Z[i]))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1000, color='w', shade=False, lw=.5)
ax.set_zlim(0, 5)
ax.set_xlim(-51, 51)
ax.set_zlabel("Intensity")
ax.view_init(20,-120)
plt.show()

Categories