pythonmatplotlibframenetgraph

Netgraph Animation — how to display frame numbers


I'm trying to add a frame number to a simulation visualization modified from here. Is there any simple way to add a frame number to this animation so that it displays as a part of the plot title?

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.animation import FuncAnimation
from netgraph import Graph

# Simulate a dynamic network with
total_frames = 10
total_nodes = 5
NODE_LABELS = {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E'}
NODE_POS = {0: (0.0, 0.5), 1: (0.65, 0.25), 2: (0.7, 0.5), 3: (0.5, 0.75), 4: (0.25, 0.25)}
adjacency_matrix = np.random.rand(total_nodes, total_nodes) < 0.25
weight_matrix = np.random.randn(total_frames, total_nodes, total_nodes)

# Normalise the weights, such that they are on the interval [0, 1].
# They can then be passed directly to matplotlib colormaps (which expect floats on that interval).
vmin, vmax = -2, 2
weight_matrix[weight_matrix<vmin] = vmin
weight_matrix[weight_matrix>vmax] = vmax
weight_matrix -= vmin
weight_matrix /= vmax - vmin

cmap = plt.cm.RdGy

fig, ax = plt.subplots()
fig.suptitle('Simulation viz @ t=', x= 0.15, y=0.95)
g = Graph(adjacency_matrix, node_labels=NODE_LABELS,
            node_layout = NODE_POS, edge_cmap=cmap, arrows=True, ax=ax)

def update(ii):
    artists = []
    for jj, kk in zip(*np.where(adjacency_matrix)):
        w = weight_matrix[ii, jj, kk]
        artist = g.edge_artists[(jj, kk)]
        artist.set_facecolor(cmap(w))
        artist.update_width(0.03 * np.abs(w-0.5))
        artists.append(artist)
    return artists

animation = FuncAnimation(fig, update, frames=total_frames, interval=200, blit=True, repeat=False)
plt.show()

Thank you. I would appreciate any help/suggestions.


Solution

  • When animating while using blit (blit=True), figure level titles cannot be changed, as blit caches everything outside of the axis being animated.

    The simplest change is to set blit to false, and then update the figure title within the animation update function.

    import numpy as np
    import matplotlib.pyplot as plt
    
    from matplotlib.animation import FuncAnimation
    from netgraph import Graph
    
    # Simulate a dynamic network with
    total_frames = 10
    total_nodes = 5
    NODE_LABELS = {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E'}
    NODE_POS = {0: (0.0, 0.5), 1: (0.65, 0.25), 2: (0.7, 0.5), 3: (0.5, 0.75), 4: (0.25, 0.25)}
    adjacency_matrix = np.random.rand(total_nodes, total_nodes) < 0.25
    weight_matrix = np.random.randn(total_frames, total_nodes, total_nodes)
    
    # Normalise the weights, such that they are on the interval [0, 1].
    # They can then be passed directly to matplotlib colormaps (which expect floats on that interval).
    vmin, vmax = -2, 2
    weight_matrix[weight_matrix<vmin] = vmin
    weight_matrix[weight_matrix>vmax] = vmax
    weight_matrix -= vmin
    weight_matrix /= vmax - vmin
    
    cmap = plt.cm.RdGy
    
    fig, ax = plt.subplots()
    title = fig.suptitle('Simulation viz @ t=', x= 0.15, y=0.95) # <----
    g = Graph(adjacency_matrix, node_labels=NODE_LABELS,
                node_layout = NODE_POS, edge_cmap=cmap, arrows=True, ax=ax)
    
    def update(ii):
        artists = []
        for jj, kk in zip(*np.where(adjacency_matrix)):
            w = weight_matrix[ii, jj, kk]
            artist = g.edge_artists[(jj, kk)]
            artist.set_facecolor(cmap(w))
            artist.update_width(0.03 * np.abs(w-0.5))
            artists.append(artist)
    
        title.set_text(f"Simulation viz @ t={ii}") # <----
    
        return artists
    
    animation = FuncAnimation(fig, update, frames=total_frames, interval=200, blit=False, repeat=False)
    plt.show()