作者:Tony Yiu
翻译:Hanz
整理:Lemonbit
译文出品:Python数据之道
— 1 —
前言
-
一开始先设置一个 N×N 的网格(我的动画中用的是 50×50 );
-
接着随机地向格子中填充“小细胞”(一开始随机地从 2500 个格子中选取 1500 个进行填充);
-
如果邻居小细胞少于等于 1 个,那格子中的小细胞会死掉;
-
如果邻居大于等于 4 个的也会死掉;
-
只有 2 个或 3 个邻居时可以生存;
-
空的格子中如果正好有 3 个邻居,则会长出 1 个新的“小细胞”;
— 2 —
建立网格
1 <span class="kwd" style="color: rgb(167, 29, 93);">import</span><span class="pln" style="color: rgb(22, 27, 29);"> time</span>
1 <span class="kwd" style="color: rgb(167, 29, 93);">from</span><span class="pln" style="color: rgb(22, 27, 29);"> </span><span class="typ" style="color: rgb(37, 127, 173);">IPython</span><span class="pln" style="color: rgb(22, 27, 29);"> </span><span class="kwd" style="color: rgb(167, 29, 93);">import</span><span class="pln" style="color: rgb(22, 27, 29);"> display</span>
1 <span class="kwd" style="color: rgb(167, 29, 93);">import</span><span class="pln" style="color: rgb(22, 27, 29);"> matplotlib.pyplot </span><span class="kwd" style="color: rgb(167, 29, 93);">as</span><span class="pln" style="color: rgb(22, 27, 29);"> plt</span>
1 <span class="kwd" style="color: rgb(167, 29, 93);">import</span><span class="pln" style="color: rgb(22, 27, 29);"> matplotlib.animation </span><span class="kwd" style="color: rgb(167, 29, 93);">as</span><span class="pln" style="color: rgb(22, 27, 29);"> animation</span>
1 | <span class="typ" style="color: rgb(167, 29, 93);font-size: 14px;">FuncAnimation()</span> |
函数。
1 | <span class="typ" style="color: rgb(167, 29, 93);font-size: 14px;">FuncAnimation()</span> |
是通过多次调用一个函数并逐次更新图片来实现让图片动起来的。
我们来一步步地实现这个过程。-
我们需要一个 50×50 大小的网格;
-
1<span style="color: rgb(167, 29, 93);font-size: 15px;">pad</span>
变量可以使得计算邻居变得更容易。通过在边界外添加一层空白格子,我们就不需要额外再写一个逻辑来处理网格的边界。因此我们 50×50 的网格其实是被一圈空白格子包围着,这使得实际的 numpy 序列的大小为 52×52;
-
1<span style="color: rgb(167, 29, 93);font-size: 15px;">initial_cels</span>
变量表示在网格启动的时候我们想要多少“小细胞”。他们会被随机地分布在网格上。
1 <span class="com" style="color: rgb(142, 142, 142);"># Input variables for the board</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">boardsize = </span><span class="lit" style="color: rgb(147, 92, 37);">50</span><span class="pln" style="color: rgb(22, 27, 29);"> </span><span class="com" style="color: rgb(142, 142, 142);"># board will be X by X where X = boardsize</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">pad = </span><span class="lit" style="color: rgb(147, 92, 37);">2</span><span class="pln" style="color: rgb(22, 27, 29);"> </span><span class="com" style="color: rgb(142, 142, 142);"># padded border, do not change this!</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">initial_cells = </span><span class="lit" style="color: rgb(147, 92, 37);">1500</span><span class="pln" style="color: rgb(22, 27, 29);"> </span><span class="com" style="color: rgb(142, 142, 142);"># this number of initial cells will be placed</span>
1 <span class="pln" style="color: rgb(22, 27, 29);"> </span><span class="com" style="color: rgb(142, 142, 142);"># in randomly generated positions</span>
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">pos_list</span> |
变量中。
1 <span class="com" style="color: rgb(142, 142, 142);"># Get a list of random coordinates so that we can initialize</span>
1 <span class="com" style="color: rgb(142, 142, 142);"># board with randomly placed organisms</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">pos_list = []</span>
1 <span class="kwd" style="color: rgb(167, 29, 93);">for</span><span class="pln" style="color: rgb(22, 27, 29);"> i </span><span class="kwd" style="color: rgb(167, 29, 93);">in</span><span class="pln" style="color: rgb(22, 27, 29);"> range(initial_cells):</span>
1 <span class="pln" style="color: rgb(22, 27, 29);"> pos_list.append([random.randint(</span><span class="lit" style="color: rgb(147, 92, 37);">1</span><span class="pun" style="color: rgb(22, 27, 29);">, boardsize),</span>
1 <span class="pln" style="color: rgb(22, 27, 29);"> random.randint(</span><span class="lit" style="color: rgb(147, 92, 37);">1</span><span class="pun" style="color: rgb(22, 27, 29);">, boardsize)])</span>
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">my_board</span> |
的 numpy 序列来代表我们的网格——我们先生成一个 52×52 数值为 0 的矩阵序列作为开始(比 50×50 大是由于增加了空白边缘),然后调用
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">init_board()</span> |
函数来根据
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">pos_list</span> |
中的坐标把“小细胞”填充到网格中。辅助函数的具体细节我不再展开讲了,不过我把他们都整理到我的 Github 上了。
1 <span class="com" style="color: rgb(142, 142, 142);"># Initialize the board</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">my_board = np.zeros((boardsize+pad, boardsize+pad))</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">my_board = init_board(pos_list, my_board)</span>
— 3 —
制作网格动画
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">mtplotlib</span> |
图框。
1 <span class="com" style="color: rgb(142, 142, 142);"># Required line for plotting the animation</span>
1 <span class="pun" style="color: rgb(22, 27, 29);">%matplotlib notebook</span>
1 <span class="com" style="color: rgb(142, 142, 142);"># Initialize the plot of the board that will be used for animation</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">fig = plt.gcf()</span>
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">mtplotlib</span> |
中的
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">imshow()</span> |
函数可以接收一组
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">numpy</span> |
矩阵然后返回一张图片。很酷吧!
1 <span class="com" style="color: rgb(142, 142, 142);"># Show first image - which is the initial board</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">im = plt.imshow(my_board)</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">plt.show()</span>
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">imshow()</span> |
的变量是我们的初始的网格
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">my_board</span> |
。生成的图片长这样:
1 | <span class="typ" style="color: rgb(167, 29, 93);font-size: 14px;">FuncAnimation()</span> |
调用的辅助函数。
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">animate()</span> |
函数接受一帧画面作为输入充当计数器。这个画面计数器就是
1 | <span class="typ" style="color: rgb(167, 29, 93);font-size: 14px;">FuncAnimation()</span> |
和
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">animate()</span> |
函数沟通的桥梁——在每一个时间点(也就是每一帧),它都会调用一次
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">animate()</span> |
。然后
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">animate()</span> |
会逐次使用辅助函数
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">update_board()</span> |
来对网格进行迭代。最后,
1 | <span class="pln" style="color: rgb(167, 29, 93);font-size: 14px;">set_data()</span> |
函数将图片更新为迭代后的网格,这就完成了。
1 <span class="com" style="color: rgb(142, 142, 142);"># Helper function that updates the board and returns a new image of</span>
1 <span class="com" style="color: rgb(142, 142, 142);"># the updated board animate is the function that FuncAnimation calls</span>
1 <span class="kwd" style="color: rgb(167, 29, 93);">def</span><span class="pln" style="color: rgb(22, 27, 29);"> animate(frame):</span>
1 <span class="pln" style="color: rgb(22, 27, 29);"> im.set_data(update_board(my_board))</span>
1 <span class="pln" style="color: rgb(22, 27, 29);"> </span><span class="kwd" style="color: rgb(167, 29, 93);">return</span><span class="pln" style="color: rgb(22, 27, 29);"> im,</span>
1 | <span class="typ" style="color: rgb(167, 29, 93);font-size: 14px;">FuncAnimation()</span> |
函数了。注意输入的参数:
-
1<span style="color: rgb(167, 29, 93);font-size: 15px;">fig</span>
是我们在前面创建的用来装载我们的动画的图形变量;
-
1<span style="color: rgb(167, 29, 93);font-size: 15px;">animate</span>
是
1<span style="font-size: 15px;color: rgb(167, 29, 93);">FuncAnimation()</span>用画面计数器进行沟通的函数(自动传入,不需要特别声明)
-
1<span style="color: rgb(167, 29, 93);font-size: 15px;">frames</span>
表示我们希望动画持续多少帧,在这里我们想要动画的长度为 200 帧;
-
1<span style="color: rgb(167, 29, 93);font-size: 15px;">interval</span>
表示每一帧之间间隔的毫秒数。我们想要每帧之间间隔 50 毫秒。
1 <span class="com" style="color: rgb(142, 142, 142);"># This line creates the animation</span>
1 <span class="pln" style="color: rgb(22, 27, 29);">anim = animation.</span><span class="typ" style="color: rgb(37, 127, 173);">FuncAnimation</span><span class="pun" style="color: rgb(22, 27, 29);">(fig, animate, frames=</span><span class="lit" style="color: rgb(147, 92, 37);">200</span><span class="pun" style="color: rgb(22, 27, 29);">,</span>
1 <span class="pln" style="color: rgb(22, 27, 29);"> interval=</span><span class="lit" style="color: rgb(147, 92, 37);">50</span><span class="pun" style="color: rgb(22, 27, 29);">)</span>
— 4 —
总结
-
一个个地画出蒙特卡洛模拟数据,你能观察到最终的分布是如何逐步形成的;
-
按顺序遍历时间序列数据,可以描绘你的模型或数据在新的观察角度下有什么表现;
-
当你改变输入参数时,比如族群数,可以展现你的算法是如何划分族群的;
-
根据时间或不同的数据子集生成关联热力图,用于观察不同的样本是如何影响你的模型的预期参数的。
Github: https://github.com/yiuhyuk/game_of_life 来源:https://towardsdatascience.com/spice-up-your-python-visualizations-with-matplotlib-animations-d437d7e98e67
(完)
看完本文有收获?请转发分享给更多人
关注「Python那些事」,做全栈开发工程师
朋友会在“发现-看一看”看到你“在看”的内容