将背景图像添加到 3d 绘图 [英] Add background image to 3d plot

查看:27
本文介绍了将背景图像添加到 3d 绘图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此主题已在

z=min(z)-1 层,其中 -1 是避免重叠的视觉偏移,我想插入一个图像,代表曲线显示特定值的元素.怎么做?

在这个例子中,我不关心元素与其值之间的完美匹配,所以请随意上传您喜欢的任何图像.另外,有没有办法让图像旋转,以防万一匹配不满意?

编辑

这是为 3D 直方图制作的类似内容的视觉示例.z=0 级别的灰色形状是条形显示特定 z 值的元素.

解决方案

使用 plot_surface 通过 facecolors 参数绘制图像.

from mpl_toolkits.mplot3d 导入 Axes3D从 matplotlib 导入 cm从 matplotlib.ticker 导入 LinearLocator,FormatStrFormatter导入 matplotlib.pyplot 作为 plt将 numpy 导入为 np从 matplotlib._png 导入 read_png从 matplotlib.cbook 导入 get_sample_datafig = 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)冲浪 = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.winter,线宽=0,抗锯齿=真)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 是表面的 x 轴和 y 轴的等长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 允许确定图像质量# stride = 1 工作缓慢ax.plot_surface(X1, Y1, -2.01, rstride=1, cstride=1, facecolors=arr)plt.show()

如果您需要添加值,请使用 PathPatch:

from mpl_toolkits.mplot3d 导入 Axes3D从 matplotlib 导入 cm从 matplotlib.ticker 导入 LinearLocator,FormatStrFormatter导入 matplotlib.pyplot 作为 plt将 numpy 导入为 np从 mpl_toolkits.mplot3d 导入 Axes3D将 mpl_toolkits.mplot3d.art3d 导入为 art3d从 matplotlib.text 导入 TextPath从 matplotlib.transforms 导入 Affine2D从 matplotlib.patches 导入 PathPatchdef text3d(ax, xyz, s, zdir="z", size=None, angle=0, usetex=False, **kwargs):x, y, z = xyz如果 zdir == "y":xy1, z1 = (x, z), yelif zdir == "y":xy1, z1 = (y, z), x别的:xy1, z1 = (x, y), ztext_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)# 主要的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)冲浪 = ax.plot_surface(Xg, Yg, Z, rstride=1, cstride=1, cmap=cm.winter,线宽=0,抗锯齿=真)ax.set_zlim(-2.01, 1.01)ax.zaxis.set_major_locator(LinearLocator(10))ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))# 添加带有值的路径对于 enumerate(X[::4]) 中的 i,x:对于 enumerate(Y[::4]) 中的 j,y:text3d(ax, (x, y, -2.01), "{0:.1f}".format(Z[i][j]), zdir="z", size=.5, ec="none",fc="k")plt.show()

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.

So to come up with a simple and reproducible case, let's say that I create a 3D plot like this with mplot3d:

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

Visually we have:

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. 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. The grey shapes at the level z=0 are the elements for which the bars show a certain z value. Source.

解决方案

Use plot_surface to draw image via facecolors argument.

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:

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

这篇关于将背景图像添加到 3d 绘图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆