1

I'm trying to compare several numerical schemes with exact solution of a PDE. To do that, I'm trying to make an animation, in which there are multiple subplots and each subplot has two functions evolving. (numerical and exact)

I found out how to make multiple lines animating here, Matplotlib multiple animate multiple lines

And I also found out how to make multiple subplots. animated subplots using matplotlib

But I'm not sure how to do both. They looks so confusing when looked together (I'm not that familiar with matplotlib, especially FuncAnimation) And also I want to make a subplot number as variable, so user can input any number of functions.

my code is this. Currently this code generates plot for each numerical scheme, but I want it to make only one plot. So the 'plot' function would be called only once,

plot(*arguments, FTCS, upwind, anotherfunc, anotherfunc2, ...)

this way.

Sorry for the messy code. I attached all of them just to make a minimum working example. Only 'plot' function is relevant to my question.

*edited code.

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



#dt=1/5
dx=1/400
tm=9
xm=1
C=0.8
u=.1
dt=dx*C/u
arguments=dt,dx,tm,xm,C

def plot(dt,dx,tm,xm,C,*funcs):
    plt.figure()
    fig,axes=plt.subplots(len(funcs))
    i=1
    for ax,func in zip(axes, funcs):
    #    plt.subplot(len(funcs),1,i)
        x1,T1=func(dt,dx,tm,xm,C)
        plotlays, plotcols = [2], ["black","red"]
        lines = []
        ax=plt.axes(xlim=(0,1),ylim=(-1.1,1.1))
        line,=ax.plot([],[],lw=2)
        for index in range(2):
            lobj = ax.plot([],[],lw=2,color=plotcols[index])[0]
            lines.append(lobj)

        def init():
            for line in lines:
                line.set_data([],[])
            return lines

        def animate(i):
            x=x1
            y=T1[i]
            y2=T2[i]
            xlist=[x,x]
            ylist=[y,y2]

            for lnum,line in enumerate(lines):
                line.set_data(xlist[lnum],ylist[lnum])
            return lines

        anim=animation.FuncAnimation(fig,animate,init_func=init,frames=np.shape(T1)[0],interval=20,blit=False)

        plt.title('%s' % func.__name__)
        plt.xlabel('x')
        plt.ylabel('T')
        i+=1

    plt.show()



    return



def finit(x):
    if 0<=x<=.1:
        return np.sin(10*np.pi*x)
    else:
        return 0

def FTCS(dt,dx,tm,xm,C):
    x=np.arange(0,xm+dx,dx)
    t=np.arange(0,tm+dt,dt)
    lx=len(x)
    lt=len(t)
    T=np.zeros([lt,lx])
    for i in range(0,lx):
        T[0,i]=finit(x[i])
    for n in range(0,lt-1):
        for j in range(1,lx-1):
            T[n+1,j]=T[n,j]-.5*C*(T[n,j+1]-T[n,j-1])
    return x,T

def upwind(dt,dx,tm,xm,C):
    x=np.arange(0,xm+dx,dx)
    t=np.arange(0,tm+dt,dt)
    lx=len(x)
    lt=len(t)
    T=np.zeros([lt,lx])
    for i in range(0,lx):
        T[0,i]=finit(x[i])
    for n in range(0,lt-1):
        for j in range(1,lx-1):
            T[n+1,j]=(1-C)*T[n,j]+C*T[n,j-1]
    return x,T

def exact(dt,dx,tm,xm,C):
    x=np.arange(0,xm+dx,dx)
    t=np.arange(0,tm+dt,dt)
    u=C*dx/dt
    T=np.zeros([len(t),len(x)])
    for n in range(0,len(t)):
        for j in range(0,len(x)):
            if u*t[n]<x[j]<=u*t[n]+.1:
                T[n,j]=np.sin(10*np.pi*(x[j]-u*t[n]))
            else: T[n,j]=0
    return T

plot(*arguments,FTCS,upwind)
Septacle
  • 278
  • 5
  • 15
  • Let your plot function take a list of functions `plot(..., funcs=[func1, func2,..])`. Create as many axes as you have functions, `fig, axes = plt.subplots(len(funcs))`. Then iterate over the functions and axes, `for ax, func in zip(axes, funcs):` Do so for creating the lines as well as when animating them. – ImportanceOfBeingErnest Feb 24 '19 at 05:18
  • @ImportanceOfBeingErnest I'm sorry but it doesn't work. It only shows the animation of the last function. I posted edited code. Did I do it right? I'm not sure which portion of code I should put in loop and which I shouldn't. – Septacle Feb 24 '19 at 23:07
  • I think anim=animation.FuncAnimation(fig,animate,init_func=init,frames=np.shape(T1)[0],interval=20,blit=False) This part is problem, because fig refers to the whole figure. But I cannot put it out of loop because I made animate for each axes. – Septacle Feb 24 '19 at 23:11
  • Neither the animation, nor the functions should be inside the loop. Rather you'd have a loop inside the animating function. – ImportanceOfBeingErnest Feb 25 '19 at 03:52

0 Answers0