from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d import proj3d
import matplotlib.pyplot as plt
from matplotlib import offsetbox
import numpy as np
xs = [1,1.5,2,2]
ys = [1,2,3,1]
zs = [0,1,2,0]
c = ["b","r","g","gold"]
fig = plt.figure()
ax = fig.add_subplot(111, projection=Axes3D.name)
ax.scatter(xs, ys, zs, c=c, marker="o")
# Create a dummy axes to place annotations to
ax2 = fig.add_subplot(111,frame_on=False)
ax2.axis("off")
ax2.axis([0,1,0,1])
def proj(X, ax1, ax2):
""" From a 3D point in axes ax1,
calculate position in 2D in ax2 """
x,y,z = X
x2, y2, _ = proj3d.proj_transform(x,y,z, ax1.get_proj())
return ax2.transData.inverted().transform(ax1.transData.transform((x2, y2)))
def image(ax,arr,xy):
""" Place an image (arr) as annotation at position xy """
im = offsetbox.OffsetImage(arr, zoom=2)
im.image.axes = ax
ab = offsetbox.AnnotationBbox(im, xy, xybox=(-30., 30.),
xycoords='data', boxcoords="offset points",
pad=0.3, arrowprops=dict(arrowstyle="->"))
ax.add_artist(ab)
for s in zip(xs,ys,zs):
x,y = proj(s, ax, ax2)
image(ax2,np.random.rand(10,10),[x,y])
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()
2条答案
按热度按时间5kgi1eie1#
matplotlib.offsetbox在3D中不起作用。作为变通方案,可以使用覆盖3D绘图的2D轴,并且将对该2D轴的图像注解放置在与3D轴中的位置相对应的位置处。
为了计算这些位置的坐标,可以参考How to transform 3d data units to display units with matplotlib?。然后,可以使用这些显示坐标的逆变换来获得覆盖轴中的新坐标。
上述解决方案是静态的。这意味着,如果打印被旋转或缩放,注解将不再指向正确的位置。为了同步注解,可以连接到绘制事件并检查限制或视角是否已经改变并相应地更新注解坐标。(2019年编辑:较新的版本还需要将事件从顶部2D轴传递到底部3D轴;代码更新)
o4tp2gmn2#
您可以使用Tensorboard embedding projector作为matplotlib的替代品。Example代码