Search code examples
pythontypeerrorsubplot

How to animate several graphs in python


------------------- Summation ------------

I want to animate 3+ graphs using FuncAnimation by using the same animation object to speed up the code.

What is the best way of achieve this? What am I doing wrong as my use of return a + b + c do not work as this is an unreported operand type for +?

------------------- Summation ------------

I am working on a project were I need to print data in real time, as the data is spred over different measurements do I need to separate them into different graphs both for ease of use and as they have widely shifting amplitudes.

There are a lot of examples out there how one animates one graph however not on how to animate several. The ones that I have found how to use FuncAnimation to update and animate multiple figures with matplotlib? https://www.reddit.com/r/learnpython/comments/4a0e8v/live_graphing_multiple_subplots_with_matplotlib/

And the one that I have had the most successes with is to create several subplots in one figure and animate that figure. I have sett up the following testprogram based on the first example I mentioned above.

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

x1 = np.arange(130, 190, 1)
x2 = np.arange(130, 190, 1)
x3 = np.arange(130, 190, 1)
test1 = 1 * np.sin(2 * np.pi * x1 / 10)
test2 = 2 * np.sin(2 * np.pi * x2 / 10)
test3 = 3 * np.sin(2 * np.pi * x3 / 10)

xa, xb, xc, y1, y2, y3 = [], [], [], [], [], []

fig = plt.figure(1)
ax1 = fig.add_subplot(131)
line1, = ax1.plot([], [])
ax1.set_xlabel('Samples')
ax1.set_ylabel('Amplitude')
ax1.set_title('Line 1')

ax2 = fig.add_subplot(132)
line2, = ax2.plot([], [])
ax2.grid(True)
ax2.set_xlabel('Samples')
ax2.set_ylabel('Amplitude')
ax2.set_title('Line 2')

ax3 = fig.add_subplot(133)
line3, = ax3.plot([], [])
ax3.grid(True)
ax3.set_xlabel('Samples')
ax3.set_ylabel('Amplitude')
ax3.set_title('Line 3')


def update_line_1(i):
    xa.append(x1[i])
    y1.append(test1[i])
    line1.set_data(xa, y1)
    return line1


def update_line_2(i):
    xb.append(x2[i])
    y2.append(test2[i])
    line2.set_data(x2, y2)
    return line2


def update_line_3(i):
    xc.append(x3[i])
    y3.append(test3[i])
    line3.set_data(x3, y3)
    return line3


def update_all(i):
    a = update_line_1(i)
    b = update_line_2(i)
    c = update_line_3(i)
    return a + b + c


animALL = FuncAnimation(fig, update_all, interval=50, blit=True)
plt.show()

However the use of return a + b + c do not work as this is an unreported operand type for +

TypeError: unsupported operand type(s) for +: 'Line2D' and 'Line2D'

As I am relative new to animate do I wounder if this is the right approach and if the knowledgeable community do know of a beter way or if one of you might help me understand what I am doing wrong with adding the uppdatering information for multiple subplots.


Solution

  • Was able to sole it my self, my problem were that I attempt to return a line object for FuncAnimation to use instead of plotting the graphs inside of the updating function.

    I will leave my code if somebody in the future got the same problem.

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    
    def my_function(i):
    
        sin = np.sin(2 * np.pi * (i + 1) / 10)
    
        # Changing the data for line 1
        line1.pop(0)    # Removing the first element
        line1.append(1 * sin)      # Adding the last element
    
        # Changing the data for line 2
        line2.pop(0)  # Removing the first element
        line2.append(2 * sin)  # Adding the last element
    
        # Changing the data for line 3
        line3.pop(0)  # Removing the first element
        line3.append(3 * sin)  # Adding the last element
    
        # Changing the data for line 4
        line4.pop(0)  # Removing the first element
        line4.append(4 * sin)  # Adding the last element
    
        # Changing the data for line 5
        line5.pop(0)  # Removing the first element
        line5.append(5 * sin)  # Adding the last element
    
        # Changing the data for line 6
        line6.pop(0)  # Removing the first element
        line6.append(6 * sin)  # Adding the last element
    
        # Changing the data for sample
        sample.pop(0)  # Removing the first element
        sample.append((i + 1) / 10)  # Adding the last element
    
        # clear axis
        ax1.clear()
        ax2.clear()
    
        # plot the graphs for the first subgraph
        ax1.plot(sample, line1, label='Joint 1')
        ax1.plot(sample, line2, label='Joint 2')
        ax1.plot(sample, line3, label='Joint 3')
    
        # plot the graphs for the second subgraph
        ax2.plot(sample, line4, label='Joint 4')
        ax2.plot(sample, line5, label='Joint 5')
        ax2.plot(sample, line6, label='Joint 6')
    
        # Add legend, labels and titles to subgraph 1
        ax1.legend(['Joint 1', 'Joint 2', 'Joint 3'])
        ax1.set_xlabel('Samples')
        ax1.set_ylabel('Torque (Nm)')
        ax1.set_title('Subgraph 1')
    
        # Add legend, labels and titles to subgraph 2
        ax2.legend(['Joint 4', 'Joint 5', 'Joint 6'])
        ax2.set_xlabel('Samples')
        ax2.set_ylabel('Torque (Nm)')
        ax2.set_title('Subgraph 2')
    
    
    # start collections with zeros
    line1 = [0] * 10
    line2 = [0] * 10
    line3 = [0] * 10
    line4 = [0] * 10
    line5 = [0] * 10
    line6 = [0] * 10
    sample = [0] * 10
    
    # define and adjust figure
    fig = plt.figure(figsize=(12, 6))
    ax1 = plt.subplot(121)
    ax2 = plt.subplot(122)
    
    # animate
    ani = animation.FuncAnimation(fig, my_function, interval=100)
    plt.show()