从Julia集的生成看csv二维数据结构

Julia 集简介

朱利亚集是分形几何中的一个重要概念,由法国数学家加斯东·朱利亚研究得出,通过迭代复数平面上的函数 $f_c(z) = z^2 + c$ 来定义,其中 $c$ 为固定的复数参数。对于每一个给定的 $c$ 值,从任意初始点 $z_0$ 开始进行迭代,如果序列 ${zn}$ 保持有界,则初始点属于该朱利亚集;反之,若序列趋向无穷大,则初始点不属于此集。这些集合并呈现出高度复杂和自相似的边界,其形态随不同的 $c$ 值变化,从连通区域到复杂的尘埃状分布不等,展现了丰富的几何结构和美丽的图案,既是数学研究的对象,也是艺术创作的源泉。

通过计算机绘制 Julia 集,需要指定一个 $c$ 值, 然后取一个复平面上的一个区域 $A$, 对于此区域内的每一点按$f(z)$进行迭代, 同时设置一个最大迭代次数 $N$ 和逃逸半径 $R$. 对于复平面内的点如果$|z|>R$, 则取强度为$0$; 如果 $|z|<R$, 则使用 $f(z)$ 迭代, 当迭代 $m$ 次后点 $|z_m|>R$, 则取强度为$m$, 如果迭代$N$次后仍然不满足$|z_N|>R$, 则取强度为$N$. 如此操作后,对于复平面区域$A$内的每一点都赋予一个强度值,然后输出为 csv 的2D数据,按强度上色就构成了一个 Julia 集的图形显示。

代码分析

声明脚本为 python3 , 用 utf-8 编码

1
2
#! /usr/bin/env python3
# vim:fenc=utf-8

调用 numpy 库, 同时设置初值 c, 并定义保存文件的名称 picname

1
2
3
4
5
6
import numpy as np
c = complex(-0.70176, -0.3842)
picname = "Nebula"
file_name = f"{picname}.csv"
width, height = 1000, 1000  # 图像的宽度和高度
max_iter = 100  # 最大迭代次数

绘制程序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def julia_set(c, width, height, max_iter):
    x = np.linspace(-2, 2, width)
    y = np.linspace(-2, 2, height)
    escape_time = np.zeros((height, width))  # 注意这里的维度顺序
    for i in range(width):
        for j in range(height):
            z = complex(x[i], y[j])
            n = 0
            while abs(z) <= 2 and n < max_iter:
                z = z*z + c
                n += 1
            escape_time[j, i] = n  # 根据像素位置更新逃逸时间
            
    return x, y, escape_time

上述程序中:

  • 第1行:定义程序julia_set, 并设置了四个参数c, width, height 和 max_iter.
  • 第2行:定义x数组,将x定义域$-2$到$2$划分成width等份.
  • 第3行:定义y数组,将y定义域$-2$到$2$划分成height等份.
  • 第4行:定义 $height\times width$ 矩阵escape_time,所有矩阵元默认取 $0$.
  • 第5行:遍历x数组, 以取得每一个 $x$数组元 $x[i]$.
  • 第6行:遍历y数组, 以取得每一个 $y$数组元 $y[j]$.
  • 第7行:以$x[i]$ 为实部, $y[j]$为虚部,构建复数$z$.
  • 第8行:对于每一个点$z$, 默认逃逸次数为$n=0$.
  • 第9行:使用while对每一个点$z$判断,条件为小于逃逸半径2和小于最大逃逸次数 max_iter.
  • 第10行:若满足条件,则迭代一次,同时逃逸次数 $n$ 增加$1$, 若仍然满足第9行的条件,则继续循环,同时不断将判断的逃逸次数$n$赋值给矩阵escape_time[j,i].
  • 第11行:返回最后的x,y,escape_time 数组.

使用上述函数处理具体的参数

1
2
# 计算Julia集
x_coords, y_coords, escape_time = julia_set(c, width, height, max_iter)

将结果保存为 csv 数据

1
2
3
4
5
6
with open(file_name, 'w') as file:
    file.write(',' + ','.join(map(str, x_coords)) + '\n')
    for j in range(escape_time.shape[0]):
        # 写入每行的数据,先写Y坐标,然后是该行的逃逸时间值
        file.write(str(y_coords[j]) + ',' + ','.join(map(str, escape_time[j])) + '\n')
print(f"Julia集已成功保存到{file_name}")

上述程序中:

  • 第1行:打开文件file_name, 同时赋予write权限(即选项w), 将其命名为file, 在后续程序中调用.
  • 第2行:写入x坐标行, 数组以逗号,分隔, 行尾添加换行符\n.
  • 第3行:遍历escape_time数组的第一列(也就是所有行数), 写入每一行的数组,仍然以逗号,分隔,行尾添加换行符\n.
  • 第4行:打印处理结果,同时使用f标记来使用变量{file_name}.

{% note primary %} 注意:通过这一段程序,我们可以判断出2d数据的具体形式构成. 第1行是x坐标点,第1列是y坐标点,由x和y决定的点上则(x,y)所对应的强度值,这是一个二维数据表格,和数学上描点绘图的数据一致。 {% endnote %}