[英]Add background image to 3d plot
This topic has been touched here , but no indications were given as to how to create a 3D plot and insert an image in the (x,y)
plane, at a specified z
height. 此处已触及此主题,但未给出有关如何创建 3D 绘图并在(x,y)
平面中以指定z
高度插入图像的指示。
So to come up with a simple and reproducible case, let's say that I create a 3D plot like this with mplot3d
:因此,为了提出一个简单且可重复的案例,假设我使用mplot3d
创建了一个像这样的 3D 绘图:
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)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.winter,
linewidth=0, antialiased=True)
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
plt.show()
At the level z=min(z)-1
, where -1
is a visual offset to avoid overlapping, I want to insert an image representing the elements for which the curve shows a certain value.在z=min(z)-1
级别,其中-1
是避免重叠的视觉偏移,我想插入一个图像,表示曲线显示特定值的元素。 How to do it?怎么做?
In this example I don't care about a perfect matching between the element and its value, so please feel free to upload any image you like.在这个例子中,我不关心元素与其值之间的完美匹配,所以请随意上传您喜欢的任何图像。 Also, is there a way of letting that image rotate, in case one is not happy with the matching?另外,有没有办法让图像旋转,以防万一匹配不满意?
EDIT编辑
This is a visual example of something similar made for a 3D histogram.这是为 3D 直方图制作的类似内容的视觉示例。 The grey shapes at the level z=0
are the elements for which the bars show a certain z
value. z=0
级别的灰色形状是条形显示特定z
值的元素。 Source. 来源。
Use plot_surface
to draw image via facecolors
argument.使用plot_surface
通过facecolors
参数绘制图像。
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
from matplotlib._png import read_png
from matplotlib.cbook import get_sample_data
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, .25)
Y = np.arange(-5, 5, .25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.winter,
linewidth=0, antialiased=True)
ax.set_zlim(-2.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
fn = get_sample_data("./lena.png", asfileobj=False)
arr = read_png(fn)
# 10 is equal length of x and y axises of your surface
stepX, stepY = 10. / arr.shape[0], 10. / arr.shape[1]
X1 = np.arange(-5, 5, stepX)
Y1 = np.arange(-5, 5, stepY)
X1, Y1 = np.meshgrid(X1, Y1)
# stride args allows to determine image quality
# stride = 1 work slow
ax.plot_surface(X1, Y1, -2.01, rstride=1, cstride=1, facecolors=arr)
plt.show()
If you need to add values use PathPatch
:如果您需要添加值,请使用PathPatch
:
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
from mpl_toolkits.mplot3d import Axes3D
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.text import TextPath
from matplotlib.transforms import Affine2D
from matplotlib.patches import PathPatch
def text3d(ax, xyz, s, zdir="z", size=None, angle=0, usetex=False, **kwargs):
x, y, z = xyz
if zdir == "y":
xy1, z1 = (x, z), y
elif zdir == "y":
xy1, z1 = (y, z), x
else:
xy1, z1 = (x, y), z
text_path = TextPath((0, 0), s, size=size, usetex=usetex)
trans = Affine2D().rotate(angle).translate(xy1[0], xy1[1])
p1 = PathPatch(trans.transform_path(text_path), **kwargs)
ax.add_patch(p1)
art3d.pathpatch_2d_to_3d(p1, z=z1, zdir=zdir)
# main
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, .25)
Y = np.arange(-5, 5, .25)
Xg, Yg = np.meshgrid(X, Y)
R = np.sqrt(Xg**2 + Yg**2)
Z = np.sin(R)
surf = ax.plot_surface(Xg, Yg, Z, rstride=1, cstride=1, cmap=cm.winter,
linewidth=0, antialiased=True)
ax.set_zlim(-2.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# add pathces with values
for i,x in enumerate(X[::4]):
for j,y in enumerate(Y[::4]):
text3d(ax, (x, y, -2.01), "{0:.1f}".format(Z[i][j]), zdir="z", size=.5, ec="none", fc="k")
plt.show()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.