Search code examples
pythonmatplotlibjupyter-notebookmatplotlib-animation

How to real-time update a Histogram in a Jupyter notebook?


So i have my initial array 'P' with the same number (500) 100 times

I made a while loop to randomly update two numbers in the P array (number 1 will lose/win 75 points so number 2 will do the opposite):

maxInteractions=500
interactions=0
def s(): #variable random s, defines who loses and who wins
    return random.choice([-1, 1])
while interactions <= maxInteractions:
    k= random.randint(0,99) #random number in P
    newList = [p for p in range(0,100,1) if p != k] #new list without K for second number in P
    l=random.choice(newList) #second number of P
    deltaM=75 #Points
    S=s() #will be either 1 o -1
    if P[k]+(deltaM*S)<0 or P[l]-(deltaM*S)<0: #if transaction ends up in debt, no transaction proceeds.
        continue
    else: #transacion
        P[k]=P[k]+(deltaM*S)
        P[l]=P[l]-(deltaM*S)
        interactions+=1

I want to animate this process, I tried using matplotlib animation:

    def animate(i):
    k = random.randint(0,99)
    newList = [p for p in range(0,100,1) if p != k] 
    l=random.choice(newList) 
    deltaM=75
    S=s() 
    if P[k]+(deltaM*S)<0 or P[l]-(deltaM*S)<0:
        True 
    else: 
        P[k]=P[k]+(deltaM*S)
        P[l]=P[l]-(deltaM*S)
    N1, bins, patches= ax.hist(P, [z for z in range(0,M+2500,2500)])
    time_text.set_text('trans={:.2f}'.format(i))
anim=animation.FuncAnimation(fig,animate,frames=100)
anim.save('ani.gif',writer='pillow',fps=30,dpi=100)

, however, the resultant gif doesn't update the histogram. ¿what's wrong?


Solution

  • Solution

    When you call ax.hist(...) there is no need to set it equal to N1, bins, patches. Instead, you can simply call the function. Also, only your data P is required as an argument for ax.hist().

    NOTE: It is important to call ax.cla() at the beginning of each iteration of your animation function. This clears all of the data from the subplot and makes it so that fresh data can be plotted without interference from the previous iterations.

    Complete Code

    %matplotlib notebook
    import matplotlib.pyplot as plt
    import random
    from matplotlib import animation
    from matplotlib.animation import FuncAnimation
    import time
    
    start = time.perf_counter()
    
    numBins = 100
    P = [500] *numBins
    
    fig = plt.figure()
    ax = fig.add_subplot()
        
    def animate(i):
        ax.cla()
        time_text = ax.text(1,1,"",transform = ax.transAxes, ha="right")
        k = random.randint(0,numBins-1)
        newList = [p for p in range(0,numBins,1) if p != k] 
        l=random.choice(newList) 
        deltaM=75
        S=random.choice([-1, 1])
        if P[k]+(deltaM*S)<0 or P[l]-(deltaM*S)<0:
            True 
        else: 
            P[k]=P[k]+(deltaM*S)
            P[l]=P[l]-(deltaM*S)
        ax.hist(P)
        time_text.set_text('trans={:.2f}'.format(i))
    
    anim=animation.FuncAnimation(fig,animate,repeat = False,frames=100, interval = 20)
    anim.save('ani.gif',writer='pillow',fps=30,dpi=100)
    
    end = time.perf_counter()
    print("Total runtime:", (end-start))