情報理学入門講義案その2
友人に、前回の講義案が褒められたので、調子に乗って第2回
今日のテーマ
前回はグラフを表示しましたが、今回はグラフをアニメーションさせましょう。
何はともあれ、動かしてみる
zipファイルをダウンロードしてください。
解凍すると"anim"フォルダが出来ます。gnuplotで"anim"に移動し、"anim.gp"を「load」します。
gnuplot> cd "D:/python/2/anim" gnuplot> load "anim.gp"
ここで、
- 引用符「""」をつける
- windowsではバックスラッシュ「\」ではなく、スラッシュ「/」を使う
- 全角・半角を間違えない
に注意。
どうです?動きましたか?
アニメーションする仕組み
anim.gpをテキストエディタで開いてください。
plot "steps/anim_0.txt" pause 0.05 plot "steps/anim_1.txt" pause 0.05 plot "steps/anim_2.txt" pause 0.05 (中略) plot "steps/anim_49.txt" pause 0.05
plot "ファイル名"とpause 0.05が並んでいますね。
実は、"steps/anim_**.txt"には、少しずつ変化させたsinのグラフが書き込まれています。
load "anim.gp"で、gnuplotは"anim.gp"のコマンドを次々に実行します。
すると少しずつ変化するグラフが次々に表示されるので、
人間の目には動いているように見えるのです。
pauseは表示速度の調整用です。pause 0.05で0.05秒だけ一時停止します。
pauseが無いと一瞬で終わってしまうので。
ファイルに書き込む
では、アニメーショングラフを作ってみましょう。
グラフのデータをファイルに出力する事は前回学びました。
> generate_graph.py > graph.txt
しかし、今回は50コマ文の、グラフデータが必要です。
一々、リダイレクトで書き込むわけには行きません。
Pythonには(リダイレクトを使わずに)直接ファイルに書き込む機能があります。
ファイルに書き込む
import math N = 100 with open("sin_graph.txt", "w") as f: for i in xrange(N): x = 2 * math.pi * i / N y = math.sin(x) print(x, y, file=f)
"sin_graph.txt"にsinのグラフデータが書き込まれます。
with open(ファイル名, "w") as 変数
で、ファイルを開きます。- 例によってインデントに注意
- 開いたファイルは、指定した変数(上の例ではf)を通して操作します。
- ファイルに書き込むために、printに
file=ファイルの変数
を付けます。
"w"は"write"の意味です。"read"用の"r"もありますが、それは後で
文字列
しかし、上の例では50個のファイルは作れません。
50個のファイル名を、openに与える方法をまだ知らないからです。
そのためには、"文字列"と、その操作を知らなければなりません。
文字列とは
今あなたが見ているものです。テキスト、文、文字の並び、と言い換えてもいいかも知れません。
アルファベット、ひらがな、カタカナ、漢字、数字、その他記号を扱うものです。
Pythonでは、ダブルコーテーション「""」やシングルコーテーション「''」ではさんだものは、
すべて文字列として扱われます。
文字列の操作
Pythonにおいて、文字列は数と同格です。
つまり、数と同じように、printで表示したり、変数に代入したり、関数に渡したり出来ます。
# 超オーソドックスな入門プログラム。 # これを一番最初に書かせない当講義は異端である print("Hello World!")
# 足し算は、文字列をつなげる name = "Tanaka" + " " + "Taro" print(name) # => Tanaka Taro # 数を掛けると、繰り返し print("SPAM" * 10) # => SPAMSPAMSPAMSPAMSPAMSPAMSPAMSPAMSPAMSPAM # \n で改行、\\でバックスラッシュ print("I Love \n\\10,000,000") #=> I Love # \10,000,000 # 整数に変換するにはint関数 print(1 + int("2")) # => 3 # 小数に変換するにはfloat関数 print(1 + int("2.5")) # => 3.5 # 文字列に変換するにはstr関数 print("Happy " + str(2011)) # => "Happy 2011"
シングルコーテーションとダブルコーテーションの2種類あるのは、
互いにもう一方の中に書くためで、それ以外の違いはありません。
print("'") # => ' print('"') # => " print(""") # これはエラーになる
バックスラッシュをつければ、ダブル〜の中にダブル〜を書くことも出来ます。
print("\"") # => " print('\'') # => '
なお、数<=>文字列は自動で変換されません。つまり、
x = 1 + "hello" #エラーになる x = 1 + "2" #数を表現する文字列でもエラー
アニメーションを出力する
今までの事を総合すれば・・・
("steps"ディレクトリは、予め手動で作っておいてください。)
import math N = 50 #コマ数 # まず、少しずつ違うコマのグラフを出力 for n in range(N): filename = "steps/anim_" + str(n) + ".txt" with open(filename, "w") as f: for i in range(100): x = 2*math.pi * i / 100 y = math.sin(x + 2*math.pi * n / N) print(x, y, file=f) # loadするための、コマンドを羅列したファイルを出力 with open("anim.gp", "w") as f: for n in range(N): filename = "steps/anim_" + str(n) + ".txt" # コマンド内のファイル名はダブルコーテーションで囲む p = 'plot "' + filename + '"' print(p, file=f) print("pause 0.05", file=f)
どうでしょう?うまくアニメされましたか?
文字列フォーマット
これでアニメーションは自在なわけですが、ちょっとだけ便利な機能を。
先のサンプルはファイル名を作る操作が、やや見にくい。
filename = "steps/anim_" + str(n) + ".txt"
こう書くことが出来ます。
filename = "steps/anim_{0}.txt".format(n)
文字列の後に、.format
をつけると、関数のように呼び出せます。
そして、{0}
に、str(n)
が挿入された文字列を返します。
さっきの例を書き直す
多少見やすくなったのではないでしょうか?
import math N = 50 #コマ数 # まず、少しずつ違うコマのグラフを出力 for n in range(N): filename = "steps/anim_{0}.txt".format(n) with open(filename, "w") as f: for i in range(100): x = 2*math.pi * i / 100 y = math.sin(x + 2*math.pi * n / N) print(x, y, file=f) # loadするための、コマンドを羅列したファイルを出力 with open("anim.gp", "w") as f: for n in range(N): filename = "steps/anim_{0}.txt".format(n) p = 'plot "{0}"'.format(filename) print(p, file=f) print("pause 0.05", file=f)
ちょっとだけ詳しく
文字列.format
は、print
と同じように、
文字列も(どころか何でも)、また複数個渡せます。
print("{0}/{1}/{2} ({3})".format(2011, 1, 16, "Sunday")) # => 2011/1/16 (Sunday)
{*}
は何回でも使えますし、使わない事も出来ます。
print("{0} {2} {0}".format("alpha", "beta", "gamma")) # => alpha gamma alpha
この他にも文字列フォーマットには、表示桁数を指定する記法がありますが、
詳しくはドキュメントを参照。
ファイルオブジェクト
文字列と同じように、ファイルも変数に代入したりできる対象、「ファイルオブジェクト」です。
「ファイル名の文字列」ではなく「ファイル」です。
f = open("graph.txt", "w") for i in xrange(100): print(i / 100, x ** 2, file=f) f.close()
.close()
.close()
は、ファイルを閉じる操作です。
close後はそのファイルオブジェクトは操作不能になります。
openすると、closeするまでの間、他のプログラムがそのファイルを操作できないからです。
プログラムが終了すると、自動でcloseが呼ばれることになっていますが、
ファイルへの書き込みが終わったら、すぐcloseを呼ぶようにしましょう。
with文とopen
with open(ファイル名, "w") as 変数名:
は、
実は、ファイルオブジェクトを変数に代入する操作です。
普通に変数に代入するのとの違いは、
.close()
が自動で呼ばれる- インデントで、ファイルを操作しているのが明確になる。
したがって、特に理由が無い限り、withを使ってください。
演習
何か面白いアニメーションを表示してください
つづく