python交互绘制Julia集
发布日期:2021-10-06 15:05:23 浏览次数:18 分类:技术文章

本文共 5898 字,大约阅读时间需要 19 分钟。

文章目录

matplotlib的Show面板中提供了放大、移动等交互式操作,但也未能涵盖所有的交互需求,比如希望通过mandelbrot集上的一点来生成对应的Julia集。所谓Julia集就是类似下面的美妙的图案
在这里插入图片描述

Julia集

此Julia非彼Julia,乃是传说中的分形鼻祖,指的是对于给定的一个复数 c c c,使得迭代式 f ( z ) = z 2 + c f(z)=z^2+c f(z)=z2+c收敛的复数 z z z的集合。例如,当 c = 0 c=0 c=0时,那么其收敛区间为 z 2 < 1 z^2<1 z2<1的单位圆,对应的 c c c的Julia集便是 cos ⁡ θ + i sin ⁡ θ \cos\theta+i\sin\theta cosθ+isinθ

特别地,当 c = z c=z c=z的初始值时,符合收敛条件的 z z z的便构成大名鼎鼎的Mandelbrot集
Mandelbrot集在上图中,颜色表示该点的发散速度,可以理解为开始发散时迭代的次数。其生成代码也非常简单:

#mbrot.pyimport numpy as npimport timeimport pyplotlib.pyplot as plt#生成z坐标,axis为起始位置,nx,ny为x向和y向的格点个数def genZ(axis,nx,ny):    x0,x1,y0,y1 = axis    x = np.linspace(x0,x1,nx)    y = np.linspace(y0,y1,ny)    real, img = np.meshgrid(x,y)    z = real + img*1j    return z#获取Julia集,n为迭代次数,m为判定发散点,大于1即可def getJulia(z,c,n,m=2):    t = time.time()    c = np.zeros_like(z)+c    out = abs(z)    for i in range(n):        absz = abs(z)        z[absz>m]=0		#对开始发散的点置零        c[absz>m]=0		        out[absz>m]=i	#记录发散点的发散速度        z = z*z + c    print("time:",time.time()-t)    return outif __name__ == "__main__":    axis = np.array([-2,1,-1.5,1.5])    z0 = genZ(axis,500,500)    mBrot = getJulia(z0,z0,50)    plt.imshow(mBrot, cmap=cm.jet, extent=axis)    plt.gca().set_axis_off()    plt.show()

matplotlib绑定事件

下面希望实现点击Mandelbrot集中的一点,生成相应的Julia集。

在mpl中,事件绑定函数mpl_connect被封装在中,调用格式为canvas.mpl_connect('str', func),其中func事件函数,字符串为被传入事件函数的事件标识,如下所列,望文生义即可

'button_press_event''button_release_event''draw_event''key_press_event''key_release_event''motion_notify_event''pick_event''resize_event''scroll_event''figure_enter_event''figure_leave_event''axes_enter_event''axes_leave_event''close_event'

简单起见,可以先检测一下鼠标点击事件'button_press_event',对此我们需要定义一个事件函数,并将上面的入口函数稍加修改:

def test(evt):    print(evt.xdata)	#xdata即x方向的坐标if __name__ == "__main__":    axis = np.array([-2,1,-1.5,1.5])    z0 = genZ(axis,500,500)    mBrot = getJulia(z0,z0,50)    fig, ax = plt.subplots()    fig.canvas.mpl_connect('button_press_event', test)#调用事件函数    plt.imshow(mBrot, cmap=cm.jet, extent=axis)    plt.gca().set_axis_off()    plt.show()

于是点击imshow()出来的图片,即可返回相应的x坐标。

python mbrot.pytime: 0.47572827339172363-0.8652597402597402-0.7840909090909087-0.183441558441558070.230519480519481230.8149350649350655

缩放

那么生成Julia集只需要重新调用一次getJulia这个函数即可。

Mandelbrot集的分形特征意味着我们所生成的图片可以无限放大,但是mpl自带的放大工具并不会重新生成数据,所以是虚假的放大。因此需要重新绑定放大操作,其思路是,当右键点击(‘button_press_event’)时,记录此时的坐标,当右键释(‘button_release_event’)放时重新绘制图片,为了防止与左键冲突,所以在点击所对应的事件函数中加入左右键判断。其结果如图
在这里插入图片描述
此外,还可以绑定鼠标滚轮,实现Mandelbrot集在该点的真实缩放,代码如下

import matplotlib.pyplot as pltimport numpy as npfrom matplotlib import cmimport matplotlib.backend_bases as mbbimport timeclass MandelBrot():    def __init__(self,x0,x1,y0,y1,n):        self.oriAxis = np.array([x0,x1,y0,y1])        	#初始坐标        self.axis = self.oriAxis        self.nx,self.ny,self.nMax = n,n,n               #x,y方向的网格划分个数        self.nIter = 100                                #迭代次数        self.n0 = 0                                     #预迭代次数        self.z = genZ(self.oriAxis,self.nx,self.ny)        self.DrawMandelbrot()    def DrawMandelbrot(self):        mBrot = getJulia(self.z,self.z,self.nIter)                self.fig, ax = plt.subplots()        plt.imshow(mBrot, cmap=cm.jet, extent=self.axis)        plt.gca().set_axis_off()                self.fig.canvas.mpl_disconnect(self.fig.canvas.manager.key_press_handler_id)        self.fig.canvas.mpl_connect('button_press_event', self.OnMouse)        self.fig.canvas.mpl_connect('button_release_event', self.OnRelease)        self.fig.canvas.mpl_connect('scroll_event', self.OnScroll)                plt.show()    def DrawJulia(self,c0):        z = genZ([-2,2,-2,2],800,800)        julia = getJulia(z,c0,self.nIter)                jFig,jAx = plt.subplots()        plt.cla()        plt.imshow(julia, cmap=cm.jet, extent=self.axis)        plt.gca().set_axis_off()        plt.show()        jFig.canvas.draw_idle()		#滚轮缩放    def OnScroll(self,evt):        x0,y0 = evt.xdata,evt.ydata        if evt.button == "up":            self.axis = (self.axis+[x0,x0,y0,y0])/2        elif evt.button == 'down':            self.axis = 2*self.axis-[x0,x0,y0,y0]        z = genZ(self.axis,self.nx,self.ny)        mBrot = getJulia(z,z,self.nIter)        plt.cla()        plt.imshow(mBrot, cmap=cm.jet, extent=self.axis)        plt.gca().set_axis_off()                mBrot[mBrot<1]==self.n0+self.nIter        self.n0 = int(np.min(mBrot))        self.fig.canvas.draw_idle()        pass    def OnMouse(self, evt):        self.xStart = evt.xdata        self.yStart = evt.ydata        self.fig.canvas.draw_idle()        def OnRelease(self,evt):        x0,y0,x1,y1 = self.xStart,self.yStart,evt.xdata,evt.ydata        if evt.button == mbb.MouseButton.LEFT:            self.DrawJulia(x1+y1*1j)		#如果释放的是左键,那么就绘制Julia集并返回            return        #右键拖动,可以对Mandelbrot集进行真实的放大        self.axis = np.array([min(x0,x1),max(x0,x1),                             min(y0,y1),max(y0,y1)])                nxny = self.axis[[1,3]]-self.axis[[0,2]]        self.nx,self.ny = (nxny/max(nxny)*self.nMax).astype(int)        z = genZ(self.axis,self.nx,self.ny)        n = 100     #n为迭代次数        mBrot = getJulia(z,z,n)        plt.cla()        plt.imshow(mBrot, cmap=cm.jet, extent=self.axis)        plt.gca().set_axis_off()                mBrot[mBrot<1]==self.n0+n        self.n0 = int(np.min(mBrot))        self.fig.canvas.draw_idle()def genZ(axis,nx,ny):    x0,x1,y0,y1 = axis    x = np.linspace(x0,x1,nx)    y = np.linspace(y0,y1,ny)    real, img = np.meshgrid(x,y)    z = real + img*1j    return zdef getJulia(z,c,n,n0=0,m=2):    t = time.time()    c = np.zeros_like(z)+c    out = abs(z)    for _ in range(n0):        z = z*z + c    for i in range(n0,n0+n):        absz = abs(z)        z[absz>m]=0        c[absz>m]=0        out[absz>m]=i        z = z*z + c    print("time:",time.time()-t)    return outif __name__ == "__main__":    x,y = 0,0    brot = MandelBrot(-2,1,-1.5,1.5,1000)

转载地址:https://blog.csdn.net/m0_37816922/article/details/102530064 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Matlab中视频的读取与写入
下一篇:Prolog入门教程

发表评论

最新留言

很好
[***.229.124.182]2024年04月03日 18时57分29秒