Why can't a quiver be drawn over a surface in matplotlib? - python

I am trying to draw 3 arrows over a surface using quiver. The arrows seem to always be draw behind the surface. This is the result:
And this is the code to generate this result:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
def fun(x, y):
return x ** 2 - y ** 2
if __name__ == '__main__':
fig = plt.figure(dpi=160)
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(-3.0, 3.0, 0.05)
X, Y = np.meshgrid(x, y)
zs = np.array(fun(np.ravel(X), np.ravel(Y)))
Z = zs.reshape(X.shape)
ax.plot_surface(X, Y, Z, cmap=plt.get_cmap('Blues'))
ax.quiver([0], [0], [1], [0, -1, 0], [-1, 0, 0], [0, 0, 2.5], lw=4, color=['r', 'g', 'b']) # The z is 1 unit above the surface
ax.set_xlim3d(-3.5, 3.5)
ax.set_ylim3d(-3.5, 3.5)
ax.set_zlim3d(-8.5, 8.5)
plt.show()
How do I draw these arrows over a surface? I am using matplotlib 3.1.1, which is the latest version at the time of this question.

A hacky you solution you can use, while not ideal, is reduce the alpha of the surface.
ax.plot_surface(X, Y, Z, cmap=plt.get_cmap('Blues'), alpha=0.5)

Related

Changing the position of x-y plane [duplicate]

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

How could I get the desired matplotlib 3d plot style?

I copied a snippet from here and run it but didn't get the desired style.
Code for reproduction
#!/usr/bin/evn python
import numpy as np
import scipy.linalg
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
# some 3-dim points
mean = np.array([0.0, 0.0, 0.0])
cov = np.array([[1.0, -0.5, 0.8], [-0.5, 1.1, 0.0], [0.8, 0.0, 1.0]])
data = np.random.multivariate_normal(mean, cov, 50)
# regular grid covering the domain of the data
X, Y = np.meshgrid(np.arange(-3.0, 3.0, 0.5), np.arange(-3.0, 3.0, 0.5))
XX = X.flatten()
YY = Y.flatten()
order = 1 # 1: linear, 2: quadratic
if order == 1:
# best-fit linear plane
A = np.c_[data[:, 0], data[:, 1], np.ones(data.shape[0])]
C, _, _, _ = scipy.linalg.lstsq(A, data[:, 2]) # coefficients
# evaluate it on grid
Z = C[0] * X + C[1] * Y + C[2]
# or expressed using matrix/vector product
#Z = np.dot(np.c_[XX, YY, np.ones(XX.shape)], C).reshape(X.shape)
elif order == 2:
# best-fit quadratic curve
A = np.c_[np.ones(data.shape[0]), data[:, :2],
np.prod(data[:, :2], axis=1), data[:, :2]**2]
C, _, _, _ = scipy.linalg.lstsq(A, data[:, 2])
# evaluate it on a grid
Z = np.dot(np.c_[np.ones(XX.shape), XX, YY, XX * YY, XX**2, YY**2],
C).reshape(X.shape)
# plot points and fitted surface
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.2)
ax.scatter(data[:, 0], data[:, 1], data[:, 2], c='r', s=50)
plt.xlabel('X')
plt.ylabel('Y')
ax.set_zlabel('Z')
ax.axis('equal')
ax.axis('tight')
plt.show()
Actual outcome
see this link
Expected outcome
see this link
The two styles are very different: the grid color, the wireframe, the surface color, etc. Is the style of this image from previous version of matplotlib? If so, how could I get that style?
Matplotlib version
Operating system: Linux Mint 18.3
Matplotlib version: 2.2.2
Matplotlib backend: Qt4Agg
Python version: 2.7.12
I installed matplotlib via pip in a virtual environment.
in my Python 3.5, matplotlib 2.2.2 installation plt.style.use('classic') seems to work
Why matplotlib graphs and icons look different on two computers with the same OS? is similar but the Q was about icons

How to plot a point inside a surface in 3d in python (matplotlib)?

I'm able to plot a surface in 3d in matplotlib, but I also need to plot a line, and a point on the surface. The surface that the line are fine, but the point does not show up on the surface for some reason, though. Here is the code:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-2.0, 2.0, 0.05)
Y = np.arange(-1.0, 3.0, 0.05)
X, Y = np.meshgrid(X, Y)
Z = (np.ones([np.shape(X)[0],np.shape(X)[1]])-X)**2+100*(Y-(X)**2)**2
Gx, Gy = np.gradient(Z) # gradients with respect to x and y
G = (Gx**2+Gy**2)**.5 # gradient magnitude
N = G/G.max() # normalize 0..1
surf = ax.plot_surface(
X, Y, Z, rstride=1, cstride=1,
facecolors=cm.jet(N),
linewidth=0,
antialiased=False,
shade=False)
plt.hold(True)
ax.hold(True)
# add the unit circle
x_1 = np.arange(-1.0, 1.0, 0.005)
x_2 = np.arange(-1.0, 1.0, 0.005)
y_1 = np.sqrt(np.ones(len(x_1)) - x_1**2)
y_2 = -np.sqrt(np.ones(len(x_2)) - x_2**2)
x = np.array(x_1.tolist() + x_2.tolist())
y = np.array(y_1.tolist() + y_2.tolist())
z = (np.ones(len(x))-x)**2+100*(y-(x)**2)**2
ax.plot(x, y, z, '-k')
plt.hold(True)
ax.hold(True)
ax.scatter(np.array([0.8]),
np.array([0.6]),
np.array([0.045]),
color='red',
s=40
)
# Get current rotation angle
print 'rotation angle is ', ax.azim
# Set rotation angle to 60 degrees
ax.view_init(azim=60)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
The issue is that the point does not show up on the surface. Now, when I replace this code:
ax.scatter(np.array([0.8]),
np.array([0.6]),
np.array([0.045]),
color='red',
s=40
)
...with this code (i.e. just adding to the last value)...
ax.scatter(np.array([0.8]),
np.array([0.6]),
np.array([0.045+800]),
color='red',
s=40
)
...then it shows up. But I can't think of a reason why it is not showing up when I want to plot the actual value in the surface. Does someone know how to fix this?
(As an aside, I'd love to get rid of the weird line in the middle of the unit circle that I plot on the surface. I can't seem to get rid of it.)
Much obliged!

Probability surface plot matplotlib

I have 2d values of x and y which span from x - [ 1 , 5 ] and y - [0.1 - 0.5]
How can I plot the 3d surface where the axis are x , y and P(y) in matplotlib ?
I found out the code for doing so in matlab on net but I am unable to understand it and consequently convert it into matplotlib... ( the range of values is completely different for below written code as to what I require )
mu = [1 -1]; Sigma = [.9 .4; .4 .3];
[X1,X2] = meshgrid(linspace(-1,3,25)', linspace(-3,1,25)');
X = [X1(:) X2(:)];
p = mvnpdf(X, mu, Sigma);
surf(X1,X2,reshape(p,25,25));
Can someone help me out in doing the exact same thing for matplotlib ( plot_surface perhaps ? )
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.mlab as mlab
import numpy as np
def P(X, Y):
return mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
fig = plt.figure()
ax = fig.gca(projection = '3d')
jet = plt.get_cmap('jet')
x = np.linspace(-2, 2, 60)
y = np.linspace(-2, 2, 60)
X, Y = np.meshgrid(x, y)
Z = P(X, Y)
surf = ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, cmap = jet, linewidth = 0)
ax.set_zlim3d(0, Z.max())
plt.show()
yields

axis limits for scatter plot not holding in matplotlib

I am trying to overlay a scatter plot onto a contour plot using matplotlib, which contains
plt.contourf(X, Y, XYprof.T, self.nLevels, extent=extentYPY, \
origin = 'lower')
if self.doScatter == True and len(xyScatter['y']) != 0:
plt.scatter(xyScatter['x'], xyScatter['y'], \
s=dSize, c=myColor, marker='.', edgecolor='none')
plt.xlim(-xLimHist, xLimHist)
plt.ylim(-yLimHist, yLimHist)
plt.xlabel(r'$x$')
plt.ylabel(r'$y$')
What ends up happening is the resulting plots extend to include all of the scatter points, which can exceed the limits for the contour plot. Is there any way to get around this?
I used the following example to try and replicate your problem. If left to default, the range for x and y was -3 to 3. I input the xlim and ylim so the range for both was -2 to 2. It worked.
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
# the random data
x = np.random.randn(1000)
y = np.random.randn(1000)
fig = plt.figure(1, figsize=(5.5,5.5))
X, Y = meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10 * (Z1 - Z2)
origin = 'lower'
CS = contourf(x, y, Z, 10, # [-1, -0.1, 0, 0.1],
cmap=cm.bone,
origin=origin)
title('Nonsense')
xlabel('x-stuff')
ylabel('y-stuff')
# the scatter plot:
axScatter = plt.subplot(111)
axScatter.scatter(x, y)
# set axes range
plt.xlim(-2, 2)
plt.ylim(-2, 2)
show()

Categories