我一直在尝试注释3d散点图中的各个点,并使它们动态更新。
参考此:Matplotlib: Annotating a 3D scatter plot
但是我使用FuncAnimation来动态更新我的点,上面的链接没有一个解决方案,该解决方案可以让您知道如何在每个funcanimation间隔不断更改文本的位置。
这里的问题是,尽管我可以一开始就画出文字,但随后的间隔不会更新我的文字的位置。
下面是代码
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
class Simulator:
def __init__(self):
s_1 = ((0.5, 0.5, 0.0), (0.5,0.5,0.2), (0.5,0.5,1.0), (1.9,0.5,2.0))
s_2 = ((1.9, 0.5, 0.0), (1.9,0.5,0.2), (1.9,0.5,1.0), (1.9,1.9,2.0))
s_3 = ((1.2, 1.2, 0.0), (1.2,1.2,0.2), (1.2,1.2,1.0), (1.2,1.2,2.5))
s_4 = ((0.5, 1.9, 0.0), (0.5,1.9,0.2), (0.5,1.9,1.0), (0.5,0.5,2.0))
s_5 = ((1.9, 1.9, 0.0), (1.9,1.9,0.2), (1.9,1.9,1.0), (0.5,1.9,2.0))
self.data = {
's_1': {'raw': s_1},
's_2': {'raw': s_2},
's_3': {'raw': s_3},
's_4': {'raw': s_4},
's_5': {'raw': s_5}
}
###### Setup ######
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111, projection='3d')
# Setting the axes properties
self.ax.set_xlim3d([0.0, 3.0])
self.ax.set_xlabel('X')
self.ax.set_ylim3d([0.0, 3.0])
self.ax.set_ylabel('Y')
self.ax.set_zlim3d([0.0, 3.0])
self.ax.set_zlabel('Z')
for point,dic in self.data.items():
dic['x'] = []
dic['y'] = []
dic['z'] = []
dic['length'] = len(dic['raw'])
for coords in dic['raw']:
dic['x'].append(coords[0])
dic['y'].append(coords[1])
dic['z'].append(coords[2])
# Interval in milliseconds
self.anim = animation.FuncAnimation(self.fig, self.update, init_func=self.setup, interval=1000)
plt.show()
def setup(self):
plots = []
for point,dic in self.data.items():
dic['plot'] = self.ax.scatter3D([], [], [], c='red', picker = True)
dic['label'] = self.ax.text3D(dic['x'][0], dic['y'][0], dic['z'][0], point, zorder=1, color='k')
def update(self, i):
plots = []
seq_x = []
seq_y = []
seq_z = []
for point,dic in self.data.items():
if i < dic['length']:
seq_x = dic['x'][i]
seq_y = dic['y'][i]
seq_z = dic['z'][i]
dic['plot']._offsets3d = [seq_x], [seq_y], [seq_z]
#### THIS IS NOT WORKING!!!! ####
dic['label'].set_position((seq_x, seq_y, seq_z))
#### BUT SOMEHOW THIS IS WORKING AND THE TEXT's COLORS GETS UPDATED??? ####
dic['label'].set_color('red')
#### IF SOMEONE IS KIND ENOUGH, I HAVE NO IDEA WHY THIS DOES NOT WORK TOO :( ####
dic['plot'].set_color('blue')
plots.append(dic['plot'])
else:
self.anim.event_source.stop()
print('Simulation ended.')
return plots
Simulator()
从上图可以看到,文本不应该在它们应该位于的位置旁边。我想要的是文字随着内容的增加而紧随其后。
以下部分不是主要问题的一部分,而是我遇到的另一个问题:
有人知道如何更改散点图的颜色吗?我有 尝试过set_color('another color'),但是它不起作用, 积分不会自动更新。
@ImportanceOfBeingErnest
嗯,好像我没有尝试使用那些解决方案一样
我不同意,除一个解决方案答案外,所有答案都显示了针对任何更新的解决方案。这就是为什么。
HYRY接受的答案:
我最初尝试过此答案,但是如果您能向我指出,我只是不知道您将在哪里输入z坐标。这个答案太复杂了。我什至不需要尖锐的箭头,我只需要始终在此处标记该点,并在该点的后面跟随标签。此外,文本仅在鼠标释放时更新,而不动态更新标签。如果您尝试使用我拥有的代码,您将意识到,即使在屏幕上四处拖动,这些点仍会自行移动,标签也应如此。
msch的答案:
我喜欢这个答案,它简单易懂,是问题的核心。这个问题基本上是此答案的基础。我想我的英语水平不如您的英语水平高,所以我再次编辑了该问题,以确保它准确地说明了它的含义。请让我知道是否仍然不清楚。
卢奇科的答案:
这个答案看起来不错,但实际上确实很复杂。我什至不知道从哪里开始。我尝试添加该类,然后使用代码
annotate3D(ax, s=str('hi'), xyz=xyz_, fontsize=10, xytext=(-3,3),textcoords='offset points', ha='right',va='bottom')
我得到了错误:TypeError:annotate3D()为参数's'获得了多个值
DonCristobal,fredcallaway和Rafael J的答案:
使用:fig.canvas.draw(),没有必要考虑我正在使用FuncAnimation。如果我要使用fig.canvas.draw(),那不会破坏使用funcanimation的目的吗?让我知道我是否错
duhaime的答案:
没有文本的更新,它只是与ax.text的一巴掌。
答案 0 :(得分:1)
最简单的方法可能是创建2D文本。
text = ax.text2D(x, y, text)
然后更新其投影坐标。
x2, y2, _ = proj3d.proj_transform(seq_x, seq_y, seq_z, ax.get_proj())
text.set_position((x2,y2))
完整的工作代码:
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
from mpl_toolkits.mplot3d import proj3d
import matplotlib.animation as animation
class Simulator:
def __init__(self):
s_1 = ((0.5, 0.5, 0.0), (0.5,0.5,0.2), (0.5,0.5,1.0), (1.9,0.5,2.0))
s_2 = ((1.9, 0.5, 0.0), (1.9,0.5,0.2), (1.9,0.5,1.0), (1.9,1.9,2.0))
s_3 = ((1.2, 1.2, 0.0), (1.2,1.2,0.2), (1.2,1.2,1.0), (1.2,1.2,2.5))
s_4 = ((0.5, 1.9, 0.0), (0.5,1.9,0.2), (0.5,1.9,1.0), (0.5,0.5,2.0))
s_5 = ((1.9, 1.9, 0.0), (1.9,1.9,0.2), (1.9,1.9,1.0), (0.5,1.9,2.0))
self.data = {
's_1': {'raw': s_1},
's_2': {'raw': s_2},
's_3': {'raw': s_3},
's_4': {'raw': s_4},
's_5': {'raw': s_5}
}
###### Setup ######
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111, projection='3d')
# Setting the axes properties
self.ax.set_xlim3d([0.0, 3.0])
self.ax.set_xlabel('X')
self.ax.set_ylim3d([0.0, 3.0])
self.ax.set_ylabel('Y')
self.ax.set_zlim3d([0.0, 3.0])
self.ax.set_zlabel('Z')
for point,dic in self.data.items():
dic['x'] = []
dic['y'] = []
dic['z'] = []
dic['length'] = len(dic['raw'])
for coords in dic['raw']:
dic['x'].append(coords[0])
dic['y'].append(coords[1])
dic['z'].append(coords[2])
# Interval in milliseconds
self.anim = animation.FuncAnimation(self.fig, self.update, init_func=self.setup, interval=1000)
plt.show()
def setup(self):
plots = []
for point,dic in self.data.items():
dic['plot'] = self.ax.scatter3D([], [], [], c='red', picker = True)
dic['label'] = self.ax.text2D(dic['x'][0], dic['y'][0], point, zorder=1, color='k')
def update(self, i):
plots = []
seq_x = []
seq_y = []
seq_z = []
for point,dic in self.data.items():
if i < dic['length']:
seq_x = dic['x'][i]
seq_y = dic['y'][i]
seq_z = dic['z'][i]
dic['plot']._offsets3d = [seq_x], [seq_y], [seq_z]
#### Set position of text
x2, y2, _ = proj3d.proj_transform(seq_x, seq_y, seq_z, self.ax.get_proj())
dic['label'].set_position((x2,y2))
else:
self.anim.event_source.stop()
print('Simulation ended.')
return plots
Simulator()