1

On top of this animation plot, related to a previous project, to make it more presentable, I want the value to be displayed on top of the point, but ONLY for the last data, as the animation goes along.

Below the code is showing all of the annotations, as the animation adding the data in, thus it's mess in the end...Can anyone help me on resolving this issue?

I tried to add the plt.pause() and remove() underneath the execution of annotation, but then it turns out the annotation always precede the data point....I have no idea why....

import numpy as np
from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt


def collatz(k):
    seq = [k]
    while seq[-1] > 1:
       if k % 2 == 0:
         seq.append(k/2)
       else:
         seq.append(3*k+1)
       k = seq[-1]
    return seq

y= collatz(22)
x = list(range(len(y)))
  
fig = plt.figure()
plt.xlim(1,len(y))
plt.ylim(1,max(y))

draw, = plt.plot([],[], marker='o', markersize='4', color='magenta') 

def update(idx):
    draw.set_data(x[:idx], y[:idx])
    plt.gca()
    ann = plt.annotate(f'{y[idx]:.1f}', (x[idx],y[idx]), textcoords="offset points", xytext=(0,0.5), ha="center")
    #plt.pause(0.5)
    #ann.remove()
    return draw,

a = FuncAnimation(fig, update, frames=len(x), interval=30, repeat=False)

plt.show()
Zephyr
  • 11,891
  • 53
  • 45
  • 80
Maggie
  • 149
  • 2
  • 9
  • Do you mean to remove all points except the last point with each loop, or am I misunderstanding? – phuycke Aug 12 '21 at 12:09
  • @flyinthelotion Hi, thanks for the quick response. Since it's animation that dynamically display data on graph, so what I want is, showing the last value each time the graph updates. So it will be exactly like Veritasium's video [link](https://www.youtube.com/watch?v=094y1Z2wpJg), where he not only plot the graph dynamically, also showing the last values simultaneously – Maggie Aug 12 '21 at 12:13
  • I added my updated answer, I misunderstood the first time – phuycke Aug 12 '21 at 12:24

1 Answers1

1

You should place text as matplotlib.text, not annotation and return it as well as draw:

from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt


def collatz(k):
    seq = [k]
    while seq[-1] > 1:
        if k%2 == 0:
            seq.append(k/2)
        else:
            seq.append(3*k + 1)
        k = seq[-1]
    return seq


y = collatz(22)
x = list(range(len(y)))

fig = plt.figure()
plt.xlim(1, len(y))
plt.ylim(1, max(y))

draw, = plt.plot([], [], marker = 'o', markersize = '4', color = 'magenta')
ax = plt.gca()
text = ax.text(0.5, 0.5, '')

def update(idx):
    draw.set_data(x[:idx + 1], y[:idx + 1])
    text.set_text(f'{y[idx]:.1f}')
    text.set_position((x[idx], y[idx]))
    return draw, text,

a = FuncAnimation(fig, update, frames = len(x), interval = 30, repeat = False)

plt.show()

enter image description here

Zephyr
  • 11,891
  • 53
  • 45
  • 80
  • Sweet! Thanks a lot! I still little confused, why `draw.set_data(x[:idx + 1], y[:idx + 1])` This mean to update the next point immediately? – Maggie Aug 12 '21 at 12:46
  • 1
    No, in python `[a, b]` slicing is starting-inclusive and ending-exclusive. This means a is inclulded, b not. So, if the current point is `idx`, you place the text on `idx`-th position and you plot your curve from the first to `idx + 1`-th point (so that the `idx`-th is included, `idx + 1`-th not). – Zephyr Aug 12 '21 at 13:43