前回までのおさらいと今回の目標
以前、Pythonを使ってマンデルブロ集合の実装について考えてきました。
これによって、指定した箇所のマンデルブロ集合を、指定した解像度で表示することができるようになりました。
def set_mandelbrot(left, right, bottom, top, resolution, max):
if (right - left) > (top - bottom):
width = resolution
height = round(resolution / (right - left) * (top - bottom))
elif (right - left) < (top - bottom):
width = round(resolution / (top - bottom) * (right - left))
height = resolution
else:
width = resolution
height = resolution
#返却用の配列
mandelbrot_array = np.zeros((height, width))
#縦横を解像度に分解
re_array = np.linspace(left, right, width)
im_array = np.linspace(top, bottom, height)
#縦横のポイントごとにfunc_mandelbrotを適用
for w_num, re_num in enumerate(re_array):
for h_num, im_num in enumerate(im_array):
mandelbrot_array[h_num][w_num] = func_mandelbrot(max, re_num, im_num)
return mandelbrot_array
今回はこれを応用して、GUIを使ってマンデルブロ集合を動かせるようにします。
上下左右に移動
ボタンの配置
動かすといっても、Tkinterを使って、Pyplotで描き出すマンデルブロ集合の描写場所をずらすというだけです。
ボタンを押すごとに、「top = 1.2、bottom = -1.2、left = -2.4、right = 0.8」の範囲で表示していたマンデルブロ集合を、例えば10%ずつずらすようなイメージです。
まずはTkinterを使って、前回作成したマンデルブロ集合を表示し、その下に上下左右に動かす用のボタンを配置します。
class Application(tk.Frame):
def __init__(self, left, right, bottom, top, resolution, max, master=None):
#set definition
self.left, self.right, self.bottom, self.top, self.resolution = left, right, bottom, top, resolution
self.ver_mid, self.hor_mid = round((self.top + self.bottom) / 2, 8), round((self.left + self.right) / 2, self.round_digit)
self.ver_lng, self.hor_lng = round((self.top - self.bottom), 8), round((self.right - self.left), self.round_digit)
if (right - left) > (top - bottom):
self.res_width = resolution
self.res_height = round(resolution / (right - left) * (top - bottom))
elif (right - left) < (top - bottom):
self.res_width = round(resolution / (top - bottom) * (right - left))
self.res_height = resolution
else:
self.res_width = resolution
self.res_height = resolution
self.magnific = 1.0
self.max = max
#set figure
self.fig = plt.figure()
self.fig.set_size_inches(16, 12)
super().__init__(master)
self.master = master
self.master.title('Matplotlib in tkinter')
self.pack()
#set Mandelbrot
self.Mandelbrot = set_mandelbrot(self.left, self.right, self.bottom, self.top, self.resolution, self.max)
plt.imshow(self.Mandelbrot, cmap="jet")
#func canvas, button
self.create_widgets()
def create_widgets(self):
self.canvas_frame = tk.Frame(self.master)
self.canvas_frame.pack(side=tk.TOP)
self.canvas = FigureCanvasTkAgg(self.fig, self.canvas_frame)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=tk.TOP)
self.control_frame = tk.Frame(self.master)
self.control_frame.pack(side=tk.BOTTOM)
self.button = tk.Button(self.control_frame, text = "Move Left", command = self.move_left, width = 16)
self.button.pack(side = tk.LEFT)
self.button = tk.Button(self.control_frame, text = "Move Right", command = self.move_right, width = 16)
self.button.pack(side = tk.RIGHT)
self.button = tk.Button(self.control_frame, text = "Move Up", command = self.move_up, width = 16)
self.button.pack(side = tk.TOP)
self.button = tk.Button(self.control_frame, text = "Move Down", command = self.move_down, width = 16)
self.button.pack(side = tk.TOP)
Tkinterクラスをセットし、「#set definition」以下では実際に動かすときに計算しやすいように、中心線の場所を把握し、また、縦横の解像度を把握しています。
「#set figure」の中の「#set Mandelbrot」でマンデルブロ集合をTkinterの中に描画し、「#func canvas, button」でset_widgets関数に処理を私、その中でボタンをセットしていきます。
ボタンが押されると、例えばMove Upのボタンなら「self.move_up」のコマンドが処理されます。
試しにそれぞれのコマンドに「print(“flag”)」と入れて処理すると、次のように、ボタンとともに描画されます。
ボタンの処理
あとは、ボタンを押されるごとにどのような処理をするかを実装すれば、実際にマンデルブロ集合を動かすことができます。
def move_up(self):
self.ver_mid = round(self.ver_mid + (self.ver_lng) / 10, self.round_digit)
self.top_res = self.top
self.top, self.bottom = round(self.ver_mid + (self.ver_lng) / 2, self.round_digit), round(self.ver_mid - (self.ver_lng) / 2, self.round_digit)
self.buf_Mandelbrot = set_mandelbrot(self.left, self.right, self.top_res, self.top, self.res_width, self.max)
self.Mandelbrot = self.Mandelbrot[:round(-1 * self.res_height / 10), :]
self.Mandelbrot = np.concatenate([self.buf_Mandelbrot, self.Mandelbrot], 0)
plt.imshow(self.Mandelbrot, cmap="jet")
self.canvas.draw()
上へ動かすときの実装は上の通りです。
初期化のときに設定した中心線を使って、実際にtopとbottomの位置を設定します。
この時、改めてマンデルブロ集合全体を描きなおしてもいいのですが、それだと処理が重くなりすぎるので、上部分10%だけを描きなおして、それを上にくっつけるという処理をおこなっています。
こうすることで、描きなおすより10倍の速度で動かすことができます。
実際にボタンを押してみると、次の通り上に少し動きました。
さいごに
これを左右と下に対しても実装すれば、自由にマンデルブロ集合を動かせます。
ただ、これだと拡大縮小ができないため、まだあまり面白くありません。
次回以降で、拡大と縮小についても、実装していきたいと思います。
コメント