Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
831 views
in Technique[技术] by (71.8m points)

python - Matplotlib 3DPlot Extra Lines when Dimensions not Equal

Consider this MWE:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib import cm

n = 15
m = 12

x = np.linspace(-5, 5, n)
y = np.linspace(-5, 5, m)

Z = np.zeros((m, n))
for i in xrange(m):
    for j in xrange(n):
        Z[i, j] = x[j]**2 + y[i]**2


### Plot surface ###
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X, Y = np.meshgrid(x, y)
ax.plot_surface(X, Y, Z)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('Z')
plt.show()

Note in particular that the dimensions n and m are not equal. The resulting plot has some weird lines hanging down, as well as strange coloring: plot

What's going on here, and how can I prevent this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Unlike 2D, 3D plots in matplotlib have a lot of shortcomings. Let me quote one of the answers in matplotlib FAQ:

This is probably the most commonly reported issue with mplot3d. The problem is that – from some viewing angles – a 3D object would appear in front of another object, even though it is physically behind it. This can result in plots that do not look “physically correct.”

Unfortunately, while some work is being done to reduce the occurance of this artifact, it is currently an intractable problem, and can not be fully solved until matplotlib supports 3D graphics rendering at its core.

The problem occurs due to the reduction of 3D data down to 2D + z-order scalar. A single value represents the 3rd dimension for all parts of 3D objects in a collection. Therefore, when the bounding boxes of two collections intersect, it becomes possible for this artifact to occur. Furthermore, the intersection of two 3D objects (such as polygons or patches) can not be rendered properly in matplotlib’s 2D rendering engine.

This problem will likely not be solved until OpenGL support is added to all of the backends (patches are greatly welcomed). Until then, if you need complex 3D scenes, we recommend using MayaVi.

For your particular problem (and notice that I don't think this has anything to do with different sizes in each direction) I would advise you to increase your surface shape (even if artificially) and play around with the number of strides until you obtain something that is satisfactory:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib import cm

n = 150
m = 120

x = np.linspace(-5, 5, n)
y = np.linspace(-5, 5, m)

Z = np.zeros((m, n))
for i in range(m):
    for j in range(n):
        Z[i, j] = x[j]**2 + y[i]**2


### Plot surface ###
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X, Y = np.meshgrid(x, y)
ax.plot_surface(X, Y, Z,rstride=1, cstride=1)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('Z')
plt.show()

,which results in this:

Matplotlib surface with rstrides and cstrides == 10

The example above give rstrides and cstrides a value of 10. Should you increase it too much (let's say 80) and the problem becomes obvious:

Matplotlib surface with rstrides and cstrides == 80

Other option is for you to follow the recommendation of matplotlib FAQ itself and check Mayavi. Notice, however, that mayavi still does not support Python 3. Personally, if you need something quick to work with, I would recommend PyQtGraph.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...