使用FuncAnimation动态更新3d散点图中的ax.text位置 [英] Dynamically update ax.text position in 3d scatter/point plot's using FuncAnimation

查看:98
本文介绍了使用FuncAnimation动态更新3d散点图中的ax.text位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试注释3d散点图中的各个点,并动态地对其进行更新。



引用此:



在上面的图像中,文本不应该在它们应该位于的点旁边。我想要的是文本随其上升而跟随这些点。



该部分以下不是主要问题的一部分,但我有另一个问题:



任何人都知道如何更改散点图的颜色?我已经尝试过
set_color('another color'),但是它不起作用,
点的颜色不会自动更新。



@ImportanceOfBeingErnest



好吧,好像我没有尝试使用那些解决方案一样



我不同意所有但是一个解决方案的答案显示了针对任何更新的解决方案。这就是为什么。



HYRY接受的答案:



我最初尝试此答案,但我只是不这样做如果您可以向我指出z坐标,则不知道该在哪里输入。这个答案太复杂了。我什至不需要尖锐的箭头,我只需要始终在此处标记该点,并在该点的后面跟随标签。此外,文本仅在鼠标释放时更新,而不动态更新标签。如果您尝试使用我拥有的代码,您将意识到,即使在屏幕上四处拖动,这些点仍会自行移动,标签也应随之移动。



msch的答案:



我喜欢这个答案,它简单易懂,是问题的核心。这个问题基本上是此答案的基础。我想我的英语水平不如您的英语水平高,所以我再次编辑了该问题以确保它准确地说明了它的意思。请让我知道是否仍然不清楚。



Luchko的答案:



这个答案看起来不错,但是实际上真的很复杂。我什至不知道从哪里开始。我尝试添加该类,然后使用代码

  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的一个简单的巴掌。

解决方案

最简单的方法可能是创建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
从mpl_toolkits.mplot3d导入proj3d
导入matplotlib.animation作为动画

类模拟器:

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}
}

######设置### ###
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111,projection ='3d')
#设置轴属性
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')
$对于self.data.items()中的点,dic,b $ b:
dic ['x'] = []
dic ['y'] = []
dic ['z '] = []
dic ['length'] = len(dic ['raw'])
用于dic ['raw']中的坐标:
dic ['x' ] .append(coords [0])
dic ['y']。append(coords [1])$ ​​b $ b dic ['z']。append(coords [2])

#以毫秒为单位的间隔
self.anim = animation.FuncAnimation(self.fig,self.update,init_func = self.setup,interval = 1000)

plt.show()


def设置(自):
个图= []

for self.data.items()中的点,dic:
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):

地块= []

seq_x = []
seq_y = []
seq_z = []

for point,dic在self.data.items()中:
如果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]

####设置文本
的位置x2,y2,_ = proj3d.proj_transform(seq_x,seq_y,seq_z,self.ax.get_proj())
dic ['label']。set_position((x2,y2))

其他:
self.anim.event_source.stop()
print('模拟结束。')
返回图


Simulator()


I've been trying to annotate individual points in a 3d scatter plot and getting them updated dynamically.

Referred to this: Matplotlib: Annotating a 3D scatter plot

But I'm using FuncAnimation to dynamically update my points instead, the above link does not have a solution that does that lets you know how you can constantly change the position of your text at every interval of funcanimation.

The issue here is that although I could get the text to be drawn out at the very start, subsequent intervals does not update the position of my texts.

Below is the code

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

As you can see from the image above, the texts are not right beside the points where they should be. What i would like is for the text to follow the points as it rises.

The portion below is NOT part of the main question, but another question that I have:

Does any one know how to change the color of a scatter plot? I've tried set_color('another color') but it is not working, the color of the points does not update itself.

@ImportanceOfBeingErnest

Well, its not as if i have not tried to use those solutions

I disagree that all but one solution answer showed a solution for any kind of updating. Here is why.

Accepted answer by HYRY:

I tried this answer originally, but I just don't know where you would input the z-coordinates, if you could kindly point it out to me. This answer is just so complicated. I do not even need the pointy arrow thing, I just need the point to be labelled there at all times, with the label following wherever the point goes. Besides, the text only updates on a mouse release, instead of dynamically updating the label. If you were to try the code that I have, you would realise that even if you drag the screen around, the points are still moving on their own, and the labels should as well.

Answer by msch:

I love this answer, its simple and straight to the core of the issue. This question is basically a build up from this answer. I guess my command of English is not as strong as yours, so I've edited the question once again to make sure that it says exactly what it is. Please let me know if it is still unclear.

Answer by Luchko:

This answer looks good, but is actually really complicated. I really can't even understand where to start for this. I've tried adding that class in, and then using the code

annotate3D(ax, s=str('hi'), xyz=xyz_, fontsize=10, xytext=(-3,3),textcoords='offset points', ha='right',va='bottom')

I got the error: TypeError: annotate3D() got multiple values for argument 's'

Answers by DonCristobal, fredcallaway and Rafael J:

Uses: fig.canvas.draw(), which there is no point to considering I'm using FuncAnimation. Wouldn't that defeat the purpose of using funcanimation if I were to use fig.canvas.draw()? Let me know if I'm wrong

The answer by duhaime:

There is no updating of text, it is just a simple slap there with ax.text.

解决方案

The easiest is probably to create 2D text.

text = ax.text2D(x, y, text)

And then to update its projected coordinates.

x2, y2, _ = proj3d.proj_transform(seq_x, seq_y, seq_z, ax.get_proj())
text.set_position((x2,y2))

Full working code:

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

这篇关于使用FuncAnimation动态更新3d散点图中的ax.text位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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