原因
自分も原因がわからなかったので少し実験してみました。
(A) im = plt.hist(rand)
質問者さんのコードでは(A)となっていますが、この状態で実行すると「ウィンドウに静止画が表示される」というよりは「matplotlibでエラーが発生している」ことに気づきます。下記はPyCharmで実行してみたときのコンソールの情報です。
python
1C:\Users\ksoh\PycharmProjects\teratail\venv\Scripts\python.exe C:/Users/ksoh/PycharmProjects/teratail/t05_animation.py
2Traceback (most recent call last):
3 File "C:\Users\ksoh\AppData\Roaming\Python\Python37\site-packages\matplotlib\cbook\__init__.py", line 215, in process
4 func(*args, **kwargs)
5 File "C:\Users\ksoh\AppData\Roaming\Python\Python37\site-packages\matplotlib\animation.py", line 999, in _start
6 self._init_draw()
7 File "C:\Users\ksoh\AppData\Roaming\Python\Python37\site-packages\matplotlib\animation.py", line 1520, in _init_draw
8 artist.set_visible(False)
9AttributeError: 'numpy.ndarray' object has no attribute 'set_visible'
一方、リンク先では
(B) im = plt.plot(rand)
のようにplot関数の結果を蓄積してアニメーションしていますがそちらだと上記のようなエラーは出ずにアニメーションが表示されますね。
つまりplt.plotの結果のリストはアニメーションできて、plt.histの結果のリストはアニメーションできないということのように思えました。
もう一度先のエラーメッセージを見ると・・・
matplotlibの中でartistという変数にnumpy.ndarrayが格納されていたため「numpy.ndarrayオブジェクトにはset_visibleなんてメソッドないです」と言われてます。確かにnumpyの配列にそんなメソッドはないです。ArtistAnimationのリファレンスを見ると
https://matplotlib.org/api/_as_gen/matplotlib.animation.ArtistAnimation.html
artists : list
Each list entry a collection of artists that represent what needs to be enabled on each frame. These will be disabled for other frames.
とあり、第二引数に渡すのはmatplotlibのartist(多分グラフを構成するオブジェクト群)のリストらしいことがわかります。そのartistには必ずset_visibleというメソッドがあるはずだということなのでしょう。
さてplotのリファレンスを見ると
https://matplotlib.org/api/_as_gen/matplotlib.pyplot.plot.html
Returns:
lines
A list of Line2D objects representing the plotted data.
さらにhistのリファレンスを見ると
https://matplotlib.org/api/_as_gen/matplotlib.pyplot.hist.html
Returns:
n : array or list of arrays
The values of the histogram bins. ...
bins : array
The edges of the bins. ...
patches : list or list of lists
Silent list of individual patches used to create the histogram or list of such list if multiple input datasets.
とあり、plotの方はグラフを構成するLine2Dのリストを返すのに対してhistはn, bins, patchesの3つの要素を持つtupleが返されグラフを構成するオブジェクトは3つ目のpatchesに当たるように見えました。
対処(推測)
以上のことから「多分histが返す3つ目の要素をリストにすればアニメーションできるんじゃないか」と推測しました。そのとおりやってみると実行時例外はおきなくなりアニメーションが表示されました。
python
1import numpy as np
2import matplotlib.pyplot as plt
3import matplotlib.animation as animation
4from scipy import stats
5
6fig = plt.figure()
7artists = []
8a = np.linspace(start=15, stop=0, num=16)
9for i in a:
10 np.random.seed(1)
11 rand = stats.norm.rvs(i,2,7321)
12 n, bins, artist = plt.hist(rand)
13 artists.append(artist)
14
15# 16枚のプロットを 1000ms ごとに表示
16ani = animation.ArtistAnimation(fig, artists, interval=1000)
17plt.show()
余談:
例えばPyCharmのようなコードの誤りを事前に警告してくれるような親切なIDEを用いて、次の図のように警告を発してくれればまだ気づきやすかったと思います。
しかし残念ながらPythonの超有名ライブラリーであるnumpyもmatplotlibもPython3.5でサポートされた型ヒントをサポートしていません。(Python3.5より前のバージョンを利用しているユーザーがまだまだ多いということを考えればサポートできないのも当然といえましょう。なお、上の図はわざわざ自分で型ヒント付きの定義をしてPyCharmに誤りを警告させてみたものです)
それゆえ引数の型があっているかについてIDEのサポートは期待できず、当然自分が使う関数の仕様をドキュメントにより調べようとするわけですが、Pythonではコード上に型の宣言がないことが多いですし、そもそも動的型付け言語であることを最大限生かした関数、すなわち「スカラーの数値でも、strでも、tuple/list/ndarrayでもいいよー」的な、良く言えば柔軟、悪く言えばチャランポラン(?)な関数も多く、ドキュメントを見てさえすぐに間違いに気づけるとは限りません。
逆に言えばリファレンスをよく見ずになんとかなるものではないといえましょう。単にサンプルを見てそれを応用しようとしても本件のような落とし穴に落ちやすいと思います。
質問者さんがリファレンスをどのくらい見ておられるか、どのくらいプログラムの実行結果に関する情報に注意を向けているか不明ですが
- ライブラリーが発する例外/警告メッセージを注意深く見て、その意味を想像する
- リファレンスを見て仕様を把握しようとする
- ときに実験によって原因究明に努める
そういう努力をしないと解決に近づくことはおぼつかないと思います。今回の回答があってるかどうか完全な自身はないですが、少なくとも前述のことをせずには原因に近づける気がしません。「どういうコードを書けばよいか」が知りたい情報だとは思いますが、「それをどのようにして得るか」の方が本質的にはもっと重要と考えます。質問する際にも「どういうところまで調べたか」を言っていただけると閲覧者のみなさんに有用な質問になると思います。