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

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.

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()

How to draw 3D curves by SciPy?

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:

Changing marker colour on selection in matplotlib

I'm using matplotlib and I am trying to change the colour of a marker when it is selected. So far I am plotting the markers and adding a pick_event listener that calls an on_pick function, which then modifies the plot's marker properties. This isn't working because I can't figure out how to access the marker's properties. How do I do this?
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
#-----------------------------------------------
# Plots several points with cubic interpolation
#-----------------------------------------------
fig = plt.figure()
ax = fig.add_subplot(111)
x = np.linspace(0, 10, num=6, endpoint=True)
y = abs(x**2)
xnew = np.linspace(0, 10, num=40, endpoint=True)
cubicInterp = interp1d(x, y, kind='cubic')
line, = ax.plot(x,y, 'o', picker=5) # 5 points tolerance
lineInterp = ax.plot(xnew,cubicInterp(xnew), '-')
#---------------
# Events
#---------------
def on_pick(event):
line.color='red'
thisline.color='red'
#-----------------------------
fig.canvas.mpl_connect('pick_event', on_pick)
plt.show()
You can use setp method to manipulate the plot elements and update the cavas. This works:
Code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
#-----------------------------------------------
# Plots several points with cubic interpolation
#-----------------------------------------------
fig = plt.figure()
ax = fig.add_subplot(111)
x = np.linspace(0, 10, num=6, endpoint=True)
y = abs(x**2)
xnew = np.linspace(0, 10, num=40, endpoint=True)
cubicInterp = interp1d(x, y, kind='cubic')
line = ax.plot(x,y, 'o', picker=5) # 5 points tolerance
lineInterp = ax.plot(xnew,cubicInterp(xnew), '-')
#---------------
# Events
#---------------
def on_pick(event):
print "clicked"
plt.setp(line,'color','red')
fig.canvas.draw()
#-----------------------------
fig.canvas.mpl_connect('pick_event', on_pick)
plt.show()
Ouput:
Before:
After:
This wasn't working because I didn't update the plot using plt.show() and used the incorrect getter method. Here's the correct code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
#-----------------------------------------------
# Plots several points with cubic interpolation
#-----------------------------------------------
fig = plt.figure()
ax = fig.add_subplot(111)
x = np.linspace(0, 10, num=6, endpoint=True)
y = abs(x**2)
xnew = np.linspace(0, 10, num=40, endpoint=True)
cubicInterp = interp1d(x, y, kind='cubic')
line, = ax.plot(x,y, 'o', picker=5) # 5 points tolerance
lineInterp = ax.plot(xnew,cubicInterp(xnew), '-')
#---------------
# Events
#---------------
def on_pick(event):
thisline = event.artist
thisline.set_markerfacecolor("red")
plt.show()
#-----------------------------
fig.canvas.mpl_connect('pick_event', on_pick)
plt.show()

Matplotlib line plot: coloring regions of high curvature

I want to plot a line in 3D Space and color regions of high curvature. Right now I have a workaround using a discrete scatter plot:
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cmx
mpl.rcParams['legend.fontsize'] = 10
data = np.loadtxt('data',usecols=range(0,4))
x = data[:,0]
y = data[:,1]
z = data[:,2]
cs = data[:,3]
colorsMap='jet'
cm = plt.get_cmap(colorsMap)
cNorm = mpl.colors.Normalize(vmin=min(cs), vmax=max(cs))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
scalarMap.set_array(cs)
fig.colorbar(scalarMap)
ax = fig.gca(projection='3d')
ax.scatter(x, y, z, c=scalarMap.to_rgba(cs), label='scatter curve')
ax.legend()
plt.show()
But I would rather have a continuous line plot.Is there a way to do that?
Depending on how many data points you have you might be able to get your way around this. For instance, consider the generated 3D spiral data below in substitution to your data.txt
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cmx
mpl.rcParams['legend.fontsize'] = 10
theta = np.linspace(-4 * np.pi, 4 * np.pi, 1000)
z = np.linspace(-2, 2, 1000)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
cs = 1/r
colorsMap='jet'
cm = plt.get_cmap(colorsMap)
cNorm = mpl.colors.Normalize(vmin=min(cs), vmax=max(cs))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
scalarMap.set_array(cs)
ax = fig.gca(projection='3d')
ax.scatter(x, y, z, c=scalarMap.to_rgba(cs), marker='_', s=1)
plt.colorbar(scalarMap)
plt.show()
If the sampling frequency of your data points is not as "tight", then this won't look as nice. However, you could use this accepted answer to improve upon this.

Categories