Create animation of plt.contourf for visualize air flow past three cylinders using Python Matplotlib.pyplot and Matplotlib.animation.ArtistAnimation


The result is:

This page shows my exercise to visualize air flow past three cylinders.
The flow is calculated by commercial finite elemental method software i.e. COMSOL Multiphysics.
In this code, matplotlib.animation.ArtistAnimation function is used.
See also:

In [1]:
import matplotlib.pyplot as plt
import scipy as sp
import numpy as np
import pandas as pd
from matplotlib import cm
from matplotlib.animation import ArtistAnimation
from scipy.integrate import ode as ode

plt.rcParams['animation.html'] = 'html5'
Firstly, load the data calculated by COMSOL Multiphysics.
In [2]:
df0 = pd.read_csv('./air_flow_multi_cylinder.txt',skiprows=9,delim_whitespace=True,header=None)
dfs = []
ntime = 0
while True:
    try:
        df1 = df0.loc[:,:1]
        df2 = df0.loc[:,2+3*ntime:2+3*ntime+2]
        df = pd.concat([df1,df2],axis=1)
        df.columns = ['x','y','p','u','v']
        dfs.append(df)
        ntime += 1
    except:
        break
Secondary, process the data to visualize.
In [3]:
dfs[-1]
Out[3]:
x y p u v
0 0.005556 0.005556 3.476638 2.033778 0.022833
1 0.016667 0.005556 3.273756 2.096380 0.036774
2 0.027778 0.005556 3.053863 2.147082 -0.008535
3 0.038889 0.005556 2.961340 2.183505 -0.032816
4 0.050000 0.005556 2.760196 2.257305 -0.041367
5 0.061111 0.005556 2.490186 2.354591 -0.049823
6 0.072222 0.005556 2.155103 2.472089 -0.057407
7 0.083333 0.005556 1.752164 2.608163 -0.064182
8 0.094444 0.005556 1.277889 2.761207 -0.070082
9 0.105556 0.005556 0.731568 2.928643 -0.074522
10 0.116667 0.005556 0.114605 3.106345 -0.076824
11 0.127778 0.005556 -0.569058 3.291365 -0.077397
12 0.138889 0.005556 -1.296239 3.478679 -0.075672
13 0.150000 0.005556 -2.045081 3.661731 -0.071824
14 0.161111 0.005556 -2.793318 3.836468 -0.066440
15 0.172222 0.005556 -3.520424 3.999549 -0.059769
16 0.183333 0.005556 -4.208106 4.147565 -0.051647
17 0.194444 0.005556 -4.835612 4.277577 -0.042532
18 0.205556 0.005556 -5.372674 4.384672 -0.031954
19 0.216667 0.005556 -5.823756 4.472920 -0.022299
20 0.227778 0.005556 -6.191429 4.542180 -0.012975
21 0.238889 0.005556 -6.482800 4.592324 -0.004368
22 0.250000 0.005556 -6.704726 4.623952 0.002989
23 0.261111 0.005556 -6.862639 4.638570 0.009301
24 0.272222 0.005556 -6.964660 4.637545 0.016315
25 0.283333 0.005556 -7.012266 4.621263 0.022949
26 0.294444 0.005556 -7.009219 4.590024 0.030320
27 0.305556 0.005556 -6.960588 4.543430 0.038237
28 0.316667 0.005556 -6.866331 4.479101 0.047339
29 0.327778 0.005556 -6.724597 4.394377 0.058132
... ... ... ... ... ...
8070 0.672222 0.994444 -0.851534 1.153717 0.029639
8071 0.683333 0.994444 -0.615391 1.157955 0.017868
8072 0.694444 0.994444 -0.448159 1.128254 0.003178
8073 0.705556 0.994444 -0.309423 1.070925 0.001550
8074 0.716667 0.994444 -0.177514 0.998890 0.014465
8075 0.727778 0.994444 -0.122093 0.905566 -0.023575
8076 0.738889 0.994444 -0.183005 0.781106 -0.036201
8077 0.750000 0.994444 -0.341312 0.615622 -0.046848
8078 0.761111 0.994444 -0.512191 0.514118 -0.033104
8079 0.772222 0.994444 -0.600258 0.471323 -0.003324
8080 0.783333 0.994444 -0.578806 0.467240 0.019231
8081 0.794444 0.994444 -0.495871 0.480875 0.017767
8082 0.805556 0.994444 -0.432617 0.476951 0.005760
8083 0.816667 0.994444 -0.363794 0.520549 0.017140
8084 0.827778 0.994444 -0.259861 0.562288 0.024488
8085 0.838889 0.994444 -0.150498 0.589191 0.020880
8086 0.850000 0.994444 -0.045798 0.608310 0.018449
8087 0.861111 0.994444 0.047842 0.620577 0.018299
8088 0.872222 0.994444 0.120442 0.617089 0.010458
8089 0.883333 0.994444 0.155461 0.589333 -0.007691
8090 0.894444 0.994444 0.165376 0.541088 -0.001524
8091 0.905556 0.994444 0.152983 0.487346 -0.002567
8092 0.916667 0.994444 0.140183 0.443023 -0.000484
8093 0.927778 0.994444 0.126171 0.401138 -0.001678
8094 0.938889 0.994444 0.096152 0.351792 -0.012470
8095 0.950000 0.994444 0.034019 0.290089 -0.031129
8096 0.961111 0.994444 -0.059803 0.224311 -0.046518
8097 0.972222 0.994444 -0.149929 0.170325 -0.052306
8098 0.983333 0.994444 -0.170083 0.206427 -0.011552
8099 0.994444 0.994444 -0.079147 0.326862 0.057447
8100 rows × 5 columns
Check the data.
In [4]:
ntime,len(dfs)
Out[4]:
(26, 26)
In [5]:
x = dfs[0].loc[:,'x']
y = dfs[0].loc[:,'y']
nx = int(len(x)**0.5)
ny = int(len(y)**0.5)
x = x[:nx]
y = y[::ny]
In [6]:
x
Out[6]:
0     0.005556
1     0.016667
2     0.027778
3     0.038889
4     0.050000
5     0.061111
6     0.072222
7     0.083333
8     0.094444
9     0.105556
10    0.116667
11    0.127778
12    0.138889
13    0.150000
14    0.161111
15    0.172222
16    0.183333
17    0.194444
18    0.205556
19    0.216667
20    0.227778
21    0.238889
22    0.250000
23    0.261111
24    0.272222
25    0.283333
26    0.294444
27    0.305556
28    0.316667
29    0.327778
        ...   
60    0.672222
61    0.683333
62    0.694444
63    0.705556
64    0.716667
65    0.727778
66    0.738889
67    0.750000
68    0.761111
69    0.772222
70    0.783333
71    0.794444
72    0.805556
73    0.816667
74    0.827778
75    0.838889
76    0.850000
77    0.861111
78    0.872222
79    0.883333
80    0.894444
81    0.905556
82    0.916667
83    0.927778
84    0.938889
85    0.950000
86    0.961111
87    0.972222
88    0.983333
89    0.994444
Name: x, dtype: float64
In [7]:
y
Out[7]:
0       0.005556
90      0.016667
180     0.027778
270     0.038889
360     0.050000
450     0.061111
540     0.072222
630     0.083333
720     0.094444
810     0.105556
900     0.116667
990     0.127778
1080    0.138889
1170    0.150000
1260    0.161111
1350    0.172222
1440    0.183333
1530    0.194444
1620    0.205556
1710    0.216667
1800    0.227778
1890    0.238889
1980    0.250000
2070    0.261111
2160    0.272222
2250    0.283333
2340    0.294444
2430    0.305556
2520    0.316667
2610    0.327778
          ...   
5400    0.672222
5490    0.683333
5580    0.694444
5670    0.705556
5760    0.716667
5850    0.727778
5940    0.738889
6030    0.750000
6120    0.761111
6210    0.772222
6300    0.783333
6390    0.794444
6480    0.805556
6570    0.816667
6660    0.827778
6750    0.838889
6840    0.850000
6930    0.861111
7020    0.872222
7110    0.883333
7200    0.894444
7290    0.905556
7380    0.916667
7470    0.927778
7560    0.938889
7650    0.950000
7740    0.961111
7830    0.972222
7920    0.983333
8010    0.994444
Name: y, dtype: float64
In [8]:
nx,ny
Out[8]:
(90, 90)
In [9]:
# p: pressure
plt.contourf(x,y,dfs[-1]['p'].values.reshape(nx,ny))
plt.axes().set_aspect('equal')
plt.show()

# u: velocity in x direction
plt.contourf(x,y,dfs[-1]['u'].values.reshape(nx,ny))
plt.axes().set_aspect('equal')
plt.show()

# v: velocity in y direction
plt.contourf(x,y,dfs[-1]['v'].values.reshape(nx,ny))
plt.axes().set_aspect('equal')
plt.show()

# (u**2+u**2)**0.5: velocity magnitude
z = ((dfs[-1]['u']**2+dfs[-1]['v']**2)**0.5).values.reshape(nx,ny)
plt.contourf(x,y,z)
plt.axes().set_aspect('equal')
plt.show()
Thirdly, plot the data for each grame and store them to the array.
In [10]:
fig = plt.figure(figsize=(6.1,5),facecolor='w')
ims = []
levs = np.linspace(0,6,100)
for i in range(ntime):
    z = ((dfs[i]['u']**2+dfs[i]['v']**2)**0.5).values.reshape(nx,ny)
    im = plt.contourf(x,y,z,levs,cmap=cm.jet,vmax=6,vmin=0)
    ims.append(im.collections)
cbar = plt.colorbar(im)
cbar.set_clim(0,6)
cbar.set_ticks(np.linspace(0,6,7))
cbar.set_label('Velocity magnitude [m/s]')
plt.xlim(0,1)
plt.ylim(0,1)
plt.xlabel('x [m]')
plt.ylabel('y [m]')
plt.axes().set_aspect('equal')
Finaly, create animation using ArtistAnimation function
In [11]:
ani = ArtistAnimation(fig,ims,interval=200,repeat=True)
In [12]:
ani
Out[12]:
In [13]:
ani.save('air_flow_multi_cylinder.mp4',writer='ffmpeg')
ani.save('air_flow_multi_cylinder.gif',writer='imagemagick')