Python绘制分形图案探索无限细节和奇妙之美

目录
  • 一、目标
  • 二、表示图像
  • 三、画一条线
  • 四、画三角形
  • 五、生成分形
  • 六、结论

分形是无限复杂的模式,在不同的尺度上具有自相似性。例如,一棵树的树干会分裂成更小的树枝。这些树枝又分裂成更小的树枝,以此类推。

通过编程的方式生成分形,可以将简单的形状变成复杂的重复图案。

本文将探讨如何利用一些简单的几何学基础和编程知识,在Python中建立令人印象深刻的分形图案。

分形在数据科学中发挥着重要作用。例如,在分形分析中,对数据集的分形特征进行评估,以帮助理解基础过程的结构。此外,处于分形生成中心的循环算法可以应用于广泛的数据问题,例如从二进制搜索算法到递归神经网络。

一、目标

写一个可以画等边三角形的程序,并且在三角形的每条边上,它必须能够绘制一个稍微小一点的向外的三角形。能够根据人的意愿多次重复此过程,从而创建一些有趣的模式。

二、表示图像

把图像表示为一个二维的像素阵列。像素阵列中的每个单元格将代表该像素的颜色(RGB)。

为此,可以使用NumPy库生成像素数组,并使用Pillow将其转换为可以保存的图像。

蓝色像素的x值为3,y值为4,可以通过一个二维数组访问,如pixels[4][3]

三、画一条线

现在开始编码,首先,需要一个可以获取两组坐标并在它们之间画一条线的函数。

下面的代码通过在两点之间插值来工作,每一步都向像素阵列添加新的像素。你可以把这个过程看作是在一条线上逐个像素地进行着色。

可以在每个代码片段中使用连续字符“\”来容纳一些较长的代码行。

import numpy as np
from PIL import Image
import math
def plot_line(from_coordinates, to_coordinates, thickness, colour, pixels):
    # 找出像素阵列的边界
    max_x_coordinate = len(pixels[0])
    max_y_coordinate = len(pixels)
    # 两点之间沿着x轴和y轴的距离
    horizontal_distance = to_coordinates[1] - from_coordinates[1]
    vertical_distance = to_coordinates[0] - from_coordinates[0]
    # 两点之间的总距离
    distance =  math.sqrt((to_coordinates[1] - from_coordinates[1])**2 \
                + (to_coordinates[0] - from_coordinates[0])**2)
    # 每次给一个新的像素上色时,将向前走多远
    horizontal_step = horizontal_distance/distance
    vertical_step = vertical_distance/distance
    # 此时,将进入循环以在像素数组中绘制线
    # 循环的每一次迭代都会沿着线添加一个新的点
    for i in range(round(distance)):
        # 这两个坐标是直线中心的坐标
        current_x_coordinate = round(from_coordinates[1] + (horizontal_step*i))
        current_y_coordinate = round(from_coordinates[0] + (vertical_step*i))
        # 一旦得到了点的坐标,
        # 就在坐标周围画出尺寸为thickness的图案
        for x in range (-thickness, thickness):
            for y in range (-thickness, thickness):
                x_value = current_x_coordinate + x
                y_value = current_y_coordinate + y
                if (x_value > 0 and x_value < max_x_coordinate and \
                    y_value > 0 and y_value < max_y_coordinate):
                    pixels[y_value][x_value] = colour
# 定义图像的大小
pixels = np.zeros( (500,500,3), dtype=np.uint8 )
# 画一条线
plot_line([0,0], [499,499], 1, [255,200,0], pixels)
# 把像素阵列变成一张真正的图片
img = Image.fromarray(pixels)
# 显示得到的图片,并保存它
img.show()
img.save('Line.png')

此函数在像素阵列的每个角之间绘制一条黄线时的结果

四、画三角形

现在有了一个可以在两点之间画线的函数,可以画第一个等边三角形了。

给定三角形的中心点和边长,可以使用公式计算出高度:h = ½(√3a)。

现在利用这个高度、中心点和边长,可以计算出三角形的每个角的位置。使用之前制作的plot_line函数,可以在每个角之间画一条线。

def draw_triangle(center, side_length, thickness, colour, pixels):
    # 等边三角形的高度是,h = ½(√3a)
    # 其中a是边长
    triangle_height = round(side_length * math.sqrt(3)/2)
    # 顶角
    top = [center[0] - triangle_height/2, center[1]]
    # 左下角
    bottom_left = [center[0] + triangle_height/2, center[1] - side_length/2]
    # 右下角
    bottom_right = [center[0] + triangle_height/2, center[1] + side_length/2]
    # 在每个角之间画一条线来完成三角形
    plot_line(top, bottom_left, thickness, colour, pixels)
    plot_line(top, bottom_right, thickness, colour, pixels)
    plot_line(bottom_left, bottom_right, thickness, colour, pixels)

在500x500像素PNG的中心绘制三角形时的结果

五、生成分形

一切都已准备就绪,可以用Python创建第一个分形。

但是最后一步是最难完成的,三角形函数为它的每一边调用自己,需要能够计算每个新的较小三角形的中心点,并正确地旋转它们,使它们垂直于它们所附着的一侧。

通过从旋转的坐标中减去中心点的偏移量,然后应用公式来旋转一对坐标,可以用这个函数来旋转三角形的每个角。

def rotate(coordinate, center_point, degrees):
    # 从坐标中减去旋转的点
    x = (coordinate[0] - center_point[0])
    y = (coordinate[1] - center_point[1])
    # Python的cos和sin函数采用弧度而不是度数
    radians = math.radians(degrees)
    # 计算旋转点
    new_x = (x * math.cos(radians)) - (y * math.sin(radians))
    new_y = (y * math.cos(radians)) + (x * math.sin(radians))
    # 将在开始时减去的偏移量加回旋转点上
    return [new_x + center_point[0], new_y + center_point[1]]

将每个坐标旋转35度的三角形

可以旋转一个三角形后,思考如何在第一个三角形的每条边上画一个新的小三角形。

为了实现这一点,扩展draw_triangle函数,为每条边计算一个新三角形的旋转和中心点,其边长被参数shrink_side_by减少。

一旦它计算出新三角形的中心点和旋转,它就会调用draw_triangle(自身)来从当前线的中心画出新的、更小的三角形。然后,这将反过来打击同一个代码块,为一个更小的三角形计算另一组中心点和旋转。

这就是所谓的循环算法,因为draw_triangle函数现在会调用自己,直到达到希望绘制的三角形的最大深度。有这个转义句子是很重要的,因为理论上这个函数会一直循环下去(但实际上调用堆栈会变得太大,导致堆栈溢出错误)。

def draw_triangle(center, side_length, degrees_rotate, thickness, colour, \
                  pixels, shrink_side_by, iteration, max_depth):
    # 等边三角形的高度是,h = ½(√3a)
    # 其中'a'是边长
    triangle_height = side_length * math.sqrt(3)/2
    # 顶角
    top = [center[0] - triangle_height/2, center[1]]
    # 左下角
    bottom_left = [center[0] + triangle_height/2, center[1] - side_length/2]
    # 右下角
    bottom_right = [center[0] + triangle_height/2, center[1] + side_length/2]
    if (degrees_rotate != 0):
        top = rotate(top, center, degrees_rotate)
        bottom_left = rotate(bottom_left, center, degrees_rotate)
        bottom_right = rotate(bottom_right, center, degrees_rotate)
    # 三角形各边之间的坐标
    lines = [[top, bottom_left],[top, bottom_right],[bottom_left, bottom_right]]
    line_number = 0
    # 在每个角之间画一条线来完成三角形
    for line in lines:
        line_number += 1
        plot_line(line[0], line[1], thickness, colour, pixels)
        # 如果还没有达到max_depth,就画一些新的三角形
        if (iteration < max_depth and (iteration < 1 or line_number < 3)):
            gradient = (line[1][0] - line[0][0]) / (line[1][1] - line[0][1])
            new_side_length = side_length*shrink_side_by
            # 正在绘制的三角形线的中心
            center_of_line = [(line[0][0] + line[1][0]) / 2, \
                              (line[0][1] + line[1][1]) / 2]
            new_center = []
            new_rotation = degrees_rotate
            # 需要旋转traingle的数量
            if (line_number == 1):
                new_rotation += 60
            elif (line_number == 2):
                new_rotation -= 60
            else:
                new_rotation += 180
            # 在一个理想的世界里,这将是gradient=0,
            # 但由于浮点除法的原因,无法
            # 确保永远是这种情况
            if (gradient < 0.0001 and gradient > -0.0001):
                if (center_of_line[0] - center[0] > 0):
                    new_center = [center_of_line[0] + triangle_height * \
                                 (shrink_side_by/2), center_of_line[1]]
                else:
                    new_center = [center_of_line[0] - triangle_height * \
                                  (shrink_side_by/2), center_of_line[1]]
            else:
                # 计算直线梯度的法线
                difference_from_center = -1/gradient
                # 计算这条线距中心的距离
                # 到新三角形的中心
                distance_from_center = triangle_height * (shrink_side_by/2)
                # 计算 x 方向的长度,
                # 从线的中心到新三角形的中心
                x_length = math.sqrt((distance_from_center**2)/ \
                                     (1 + difference_from_center**2))
                # 计算出x方向需要走哪条路
                if (center_of_line[1] < center[1] and x_length > 0):
                    x_length *= -1
                # 现在计算Y方向的长度
                y_length = x_length * difference_from_center
                # 用新的x和y值来偏移线的中心
                new_center = [center_of_line[0] + y_length, \
                              center_of_line[1] + x_length]
            draw_triangle(new_center, new_side_length, new_rotation, \
                          thickness, colour, pixels, shrink_side_by, \
                          iteration+1, max_depth)

三角形分形,收缩边=1/2,最大深度=2

六、结论

下面是通过修改输入到draw_triangle函数的shrink_side_bymax_depth值生成的不同图像的一些示例。

有趣的是,这些多次重复的图案往往能创造出更复杂的形状,比如六边形,但却具有令人着迷的对称性。

越来越复杂的形状开始在重复三角形的对称性中出现

另一个分形,每次迭代使用较小的尺寸减小

分形是非常有趣的玩法,可以创造出美丽的图案。使用一些简单的概念和丰富的创造力,可以产生非常令人印象深刻的结构。

在理解分形的核心属性和应用循环算法的过程中打下的坚实基础,可以帮助理解数据科学中更复杂的分形问题。

到此这篇关于Python绘制分形图案探索无限细节和奇妙之美的文章就介绍到这了,更多相关Python绘制分形图案内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python实现绘制3D地球旋转效果

    目录 画一个地球 让地球转起来 画一个地球 想画一个转动的地球,那么首先要有一个球,或者说要有一个球面,用参数方程可以表示为 x​=rcosϕcosθ y=rcosϕsinθ z=rsinϕ​ 然后要有一个地球,或者说要有一个地图,用来作为贴图,映射到球面上. import numpy as np import matplotlib.pyplot as plt path = "earth1.jpg" img = plt.imread(path) h, w, c = img.shape

  • Python基于欧拉角绘制一个立方体

    目录 先画个立方体 欧拉角和旋转矩阵 初步演示 不同转动顺序的影响 旋转演示 先画个立方体 工欲善其事.必先利其器,在开始学习欧拉角模拟之前,可先绘制一个立方体. 在matplotlib中,这个任务可通过plt.voxels实现,下面先绘制一个最质朴的立方体 代码为 import matplotlib.pyplot as plt import numpy as np x, y, z = np.indices((2, 2, 2)) filled = np.ones((1,1,1)) ax = pl

  • Python实现绘制多种激活函数曲线详解

    利用numpy.matplotlib.sympy绘制sigmoid.tanh.ReLU.leaky ReLU.softMax函数 起因:深度学习途中,老师留一作业,绘制激活函数及其导数,耗时挺久,记录学习过程 准备工作:下载numpy.matplotlib.sympy pip install numpy matplotlib sympy 查找对应库的文档: numpy文档 matplotlib文档 sympy文档 写代码的时候发现vscode不会格式化我的python?查了一下原来还要安装fla

  • 一文教你如何使用Python绘制瀑布图

    目录 前期准备 方法一:waterfall_ax 方法二:waterfall_chart 方法三:plotly 什么是瀑布图?瀑布图用表达两个数值之间的变化过程,过程值为正的时候,向上加,过程值为负的时候向下减[1]. 今天分享在Python中绘制瀑布图的3种简单方法(使用不同的库)! 前期准备 首先先安装所需的库: pip install waterfallcharts (注意该库名) pip install waterfall_ax (注意该库名) pip install plotly 接着

  • 基于Python实现绘制一个足球

    目录 前情提要 先画六边形 再画五边形 前情提要 如果想优雅地绘制一个足球,那首先需要绘制正二十面体:用Python绘制正二十面体 其核心代码为 import numpy as np from itertools import product G = (np.sqrt(5)-1)/2 def getVertex(): pt2 = [(a,b) for a,b in product([1,-1], [G, -G])] pts = [(a,b,0) for a,b in pt2] pts += [(

  • 用Python绘制一个仿黑洞图像

    目录 简介 单位制 观测绘图 简介 黑洞图像大家都知道,毕竟前几年刚发布的时候曾火遍全网,甚至都做成表情包了. 问题在于,凭什么认为这就是黑洞的照片,而不是一个甜甜圈啥的给整模糊了得到的呢?有什么理论依据吗? 单位制 利用einsteinpy模块中的Shadow类,可以实现黑洞吸积盘的发射强度,换言之,用理论模拟一下黑洞的照片应该是什么样子的. 22年5月份发布的是人马座A*的照片,这个"黑洞"的质量为8.26×1036kg,距离地球26673光年. 根据源码推测,einstenipy

  • Python绘制分形图案探索无限细节和奇妙之美

    目录 一.目标 二.表示图像 三.画一条线 四.画三角形 五.生成分形 六.结论 分形是无限复杂的模式,在不同的尺度上具有自相似性.例如,一棵树的树干会分裂成更小的树枝.这些树枝又分裂成更小的树枝,以此类推. 通过编程的方式生成分形,可以将简单的形状变成复杂的重复图案. 本文将探讨如何利用一些简单的几何学基础和编程知识,在Python中建立令人印象深刻的分形图案. 分形在数据科学中发挥着重要作用.例如,在分形分析中,对数据集的分形特征进行评估,以帮助理解基础过程的结构.此外,处于分形生成中心的循

  • 基于Python绘制三种不同的中国结

    目录 前言 示例一 效果图 代码展示 示例二 效果图 代码展示 示例三 效果图 代码展示 前言 今天就来分享几个用python绘制的图案吧 马上就要迎来新年了 就绘制了几个中国结,嘿嘿 话不多说,直接展示一下代码和效果图吧 示例一 效果图 代码展示 import turtle turtle.screensize(600,800) turtle.pensize(10) turtle.pencolor("red") turtle.seth(-45) turtle.fd(102) turtl

  • 使用Python NumPy库绘制渐变图案

    目录 1. 导入模块 2. 基本绘画流程 3. 生成随机彩色图像 4. 生成渐变色图像 5. 在渐变色背景上画曲线 6. 使用颜色映射(ColorMap) 7. 展示NumPy的魅力 NumPy也可以画图吗?当然!NumPy不仅可以画,还可以画得更好.画得更快!比如下面这幅画,只需要10行代码就可以画出来.若能整明白这10行代码,就意味着叩开了NumPy的大门.请打开你的Python IDLE,跟随我的脚步,一起来体验一下交互式编程的乐趣吧,看看如何用NumPy画图,以及用NumPy可以画出什么

  • python使用turtle绘制分形树

    由于分形树具有对称性,自相似性,所以我们可以用递归来完成绘制.只要确定开始树枝长.每层树枝的减短长度和树枝分叉的角度,我们就可以把分形树画出来啦!! 代码如下: # -*- coding: utf-8 -*- ''' 绘制分形树 ''' import turtle as tl def draw_smalltree(tree_length,tree_angle): ''' 绘制分形树函数 ''' if tree_length >= 3: tl.forward(tree_length) #往前画 t

  • python绘制超炫酷动态Julia集示例

    目录 前言 Mandelbrot集 无限缩放 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θ.

  • 详解如何利用Python绘制科赫曲线

    目录 1. 递归 1.1 定义 1.2 数学归纳法 2. 递归的使用方法 2.1 阶乘 2.2 字符串反转 3. 科赫曲线的绘制 3.1 概要 3.2 绘制科赫曲线 3.3 科赫曲线的雪花效果 3.4 分形几何 1. 递归 1.1 定义 函数作为一种代码封装, 可以被其他程序调用,当然,也可以被函数内部代码调用.这种函数定义中调用函数自身的方式称为递归.就像一个人站在装满镜子的房间中,看到的影像就是递归的结果.递归在数学和计算机应用上非常强大,能够非常简洁地解决重要问题. 数学上有个经典的递归例

  • Python绘制牛奶冻曲线(高木曲线)案例

    前言: 牛奶冻曲线(blancmange curve),因在1901年由高木贞治所研究,又称高木曲线. 在单位区间内,牛奶冻函数定义为: 分形曲线的轮廓会随着阶数的增多而填充细节,即对于下面的来说, N的变化会增添曲线的自相似特性 import numpy as np import matplotlib.pyplot as plt s = lambda x : np.min([x-np.floor(x), np.ceil(x)-x],0) x = np.arange(1000).reshape(

  • Python绘制并保存指定大小图像的方法

    绘制直线,三角形,正方形 import matplotlib.pyplot as plt def plotLine(): x = [1,2,3,4,5] y = [3,3,3,3,3] plt.figure(figsize=(100,100),dpi=1) plt.plot(x,y,linewidth=150) plt.axis('off') plt.savefig('C:\\Users\\Administrator\\Desktop\\分形图\\a.jpg',dpi=1) plt.show()

  • Python绘制二维曲线的日常应用详解

    使用Python绘制出类似Excel或者MATLAB的曲线还是比较容易就能够实现的,需要用到的额外库有两个,numpy和matplotlib.使用这两个模块实现的曲线绘制其实在一定程度上更像是MATLAB的plot功能,不过今天看了一下matplotlib网站上的信息,现在的功能更为强劲了,而且已经支持三维图像的绘制. 模块库的安装非常简单,我使用的Mac,在Mac上用pip进行了两个模块库的安装都十分顺畅.相信其他平台基本上也都这样,如果能够联网,这种安装方式是十分推荐的,确实是简单. 我用P

  • python 绘制国旗的示例

    国旗是一个国家的象征,它可以反映一个国家的特色和传统,国旗起源于近代的欧洲,是一个国家主权意识不断增强后的必然产物,本文我们使用 Python 来画几面国旗,使用的 Python 库是大家比较熟悉的 turtle. 五星红旗 五星红旗是中华人民共和国的国旗,它是由四颗小的黄五角星环绕一颗大的黄五角星组成的,底色为红色,实现代码如下: turtle.setup(600,400,0,0) turtle.bgcolor("red") turtle.fillcolor("yellow

随机推荐