延々と少しだけ違う画像を生成して見せるには、次の2つを用意しないといけない。
これを行えば、きっと動画に見えるはずだ。やってみよう。
定数Cは complex(0.322,0.047) に固定されていたが、これを微妙に動かすと、フラクタル図形も微妙に変形するはずで、そのための変位量Δを計算するようにした。
def delta():
global cnt
r = 0.012
th = 0.002 * cnt;
cnt += 1
return r * (math.sin(th)+math. sin(th*math.sqrt(2))*1j)
グローバル変数のcntは最初に0に初期化しておくと、これを呼ぶ度に1ずつ増加する。
三角関数sinを用いるのだが、角度を th = 0.002 * cnt で求めている。
変位デルタが戻り値なのだが、実数部、虚数部ともに三角関数sinに変位thを利用している。ただし、実数部と虚数部の変位角が永遠に重ならないように、虚数部のsinの角度は2の平方根を掛けている。これで、Δは延々と重なることのないリサージュ図形となる。
最後にrを掛けているが、これは僅かな変位にするための適当な値0.012にしている。
次が再描画の関数であるが、変更部分は僅かである。
前と変わったのは、C_valueが初期値にΔを加えることで少しずつ変えた。
最後に、root.after( 5, draw_new_image ) を加えた。
これは、第1引数の値(5)のミリ秒後に、第2引数の関数を実行せよということ。
これにより、この関数は、canvas.update() の後、5ミリ秒待ってから再度呼び出されることで、永久ループとなっている。
実際には、メインループがイベントなどを監視し、そこに登録しているだけである。
def draw_new_image():
global canvas, im, root, C_org
C_value = C_org + delta()
im = calc_julia.calc_julia(1000,C_value) ## Julia集合の計算
im = np.uint8(plt.get_cmap()(im)*255) ## defaultのカラーマップを適用し、uint8 に変換
im = Image.fromarray(im) ## <class 'PIL.Image.Image'>
im = ImageTk.PhotoImage(image=im) ## Tkinterの標準のフォトイメージ
canvas.create_image( 500, 500, image=im ) ## Canvasにイメージを貼り付ける。(500,500)が中心
canvas.update() ## update()されると表示される
root.after( 5, draw_new_image ) ## 10ミリ秒後に再実行
メインであるが、変更は僅かであり、説明は不要であろう。
if __name__ == '__main__':
gui_init() ## GUIの初期化
cnt = 0
C_org = complex(0.322,0.047) ## 初期定数C
draw_new_image() ## 初期表示
root.mainloop() ## メインループ(イベント待ち)
以上で分けてソースを示したが、動画を動かすPythonのメインプログラムが以下である。念のため。
## julia集合の画像をtkinterのcanvasに描く, 動的に変化する。
import calc_julia
import tkinter
from PIL import Image, ImageTk
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
import math
def delta():
global cnt
r = 0.012
th = 0.002 * cnt;
cnt += 1
return r * ( math.sin(th) + math.sin(th*math.sqrt(2))*1j )
def draw_new_image():
global canvas, im, root, C_org
C_value = C_org + delta()
im = calc_julia.calc_julia(1000,C_value) ## Julia集合の計算
im = np.uint8(plt.get_cmap()(im)*255) ## defaultのカラーマップを適用し、uint8 に変換
im = Image.fromarray(im) ## <class 'PIL.Image.Image'>
im = ImageTk.PhotoImage(image=im) ## Tkinterの標準のフォトイメージ
canvas.create_image( 500, 500, image=im ) ## Canvasにイメージを貼り付ける。(500,500)が中心
canvas.update() ## update()されると表示される
root.after( 10, draw_new_image ) ## 10ミリ秒後に再実行
def gui_init():
global canvas, root
root = tkinter.Tk()
root.wm_title("Julia集合をtkinterのcanvasに動的に表示")
canvas_frame = tkinter.Frame(root) ## frameを作る
canvas_frame.pack() ## packする
canvas = tkinter.Canvas(canvas_frame,width=1001,height=1001) ## frameの中にcanvasを作る
canvas.pack(expand = tkinter.YES, fill = tkinter.BOTH) ## packして配置が決定
if __name__ == '__main__':
gui_init() ## GUIの初期化
cnt = 0
C_org = complex(0.322,0.047) ## 初期定数C
draw_new_image() ## 初期表示
root.mainloop() ## メインループ(イベント待ち)
ということで、Pythonが48行、Cythonが44行という100行未満で動くフラクタル動画ができた。
一部のブラウザでは動かないかも。その場合は、ブラウザを変更してみてください。