Pythonでtkinterを使ってマンデルブロ集合を描く(ちょっと遅いけど)
しつこくマンデルブロ集合ネタで、pythonで描いてみたときの記録を残しておこう。tkinterについてはpygletをいじっていたときにサンプルプログラムを入手していたりしたが、どこから手に入れたかは忘れてしまった。当然、描画のロジックはC#と基本的には同じであるが、C#ではforループでbreakしたのかどうかをカウンター変数の値で判断していたが、pythonではループの最後でbreakした場合とbreakしなかった場合とはカウンター変数では判断できないので、わざわざフラグを用意して判断していた。しかしその後、else節を使うとbreakが発生したのかどうかを識別できることを知ったので、フラグは使わないように修正した。
C#のときと変わっているのは色の数と配色だけのはず。処理の仕方がまずいのか分からないが計算処理が終わってから表示されるまでに20秒くらい待たされる。「スクリプトなので、まあ、そんなものなのだろう」と、あまり疑問は抱かないことにしておいた。
import os import sys import tkinter as tk import tkinter.ttk as ttk class Window(ttk.Frame): def __init__(self, master, cvs): super().__init__(master, padding="0.75m") self.create_ui() self.canvas = cvs def create_ui(self): self.create_menubar() def create_menubar(self): self.menubar = tk.Menu(self.master) self.master.config(menu=self.menubar) self.create_file_menu() def create_file_menu(self): fileMenu = tk.Menu(self.menubar, name="apple") fileMenu.add_command(label="Draw", underline=0, command=self.draw, compound=tk.LEFT, accelerator="") fileMenu.add_separator() fileMenu.add_command(label="Quit", underline=0, command=self.close, compound=tk.LEFT, accelerator="") self.menubar.add_cascade(label="File", underline=0, menu=fileMenu) def draw(self): width = 800 height = 500 pixelunit = 0.005 iteration = 200 position_x = -2.35 position_y = 1.25 palette = [ "black", "deep sky blue", "yellow", "hot pink", "red", "orange", "cyan", "dark green", "sea green", "spring green", "gold", "white"] maxcycle = len(palette) - 1 print("maxcycle = ",maxcycle) for i in range(width): for j in range(height): zlist = [] z0 = complex( position_x + pixelunit*i, position_y - pixelunit*j) zlist.append(z0) for k in range(iteration): z = zlist[k]*zlist[k] + z0 zlist.append(z) abs = z.real**2 + z.imag**2 if abs > 4: self.canvas.create_line(i, j, i + 1, j,fill = palette[0]) break else: for n in range(1,maxcycle): dz = zlist[-1]-zlist[-1-n] s = dz.real**2 + dz.imag**2 if s < pixelunit : self.canvas.create_line(i, j, i + 1, j,fill = palette[n]) break else: self.canvas.create_line(i, j, i + 1, j,fill = palette[maxcycle]) print("calculation finished.") def close(self, event=None): self.quit() def main(): application = tk.Tk() application.withdraw() application.title("tkinter canvas sample") application.option_add("*tearOff", False) canvas = tk.Canvas(application, width = 800, height = 500, bg="black") window = Window(application,canvas) application.protocol("WM_DELETE_WINDOW", window.close) application.deiconify() application.geometry("803x503") canvas.place(x=0, y=0) application.mainloop() if __name__ == "__main__": main()