分形勢複雜的幾何圖案或形狀,但卻由簡單的數學公式所生成。與圓形和矩形等幾何圖形相比,分形看上去并不規則,也沒有明顯的模式或描述。但如果仔細觀察,你将發現模式的存在,即整個圖形有無數個自身的副本構成。由于分形設計平面上的點的相同幾何變換的重複引用,因此非常适合使用計算機程序來構建。這一章中,我們将學習如何繪制Barnsley蕨類植物、Sierpinski三角和Manderlbrot集合(後兩個出現在編程挑戰中),這些都是分形研究領域的常見例子。分形在自然界中比比皆是,常見的例子包括海岸線、樹木和雪花。
6.2.1 平面上點的變化創建分形的基本思想是點的變換。給定x-y平面上的一個點P(x,y),變幻的一個例子是P(x,y)->Q(x 1, y 1),這意味着應用變換後,創建好了一個新點Q,它位于P向上和向右各一個單位處。如果以Q點作為起始點,将得到另一個點R,它位于點Q向上和向右各一個單位處。假設起始點P位于(1,1),下圖展示了這些點的位置。
P、Q、R三個點的位置圖
因此,變換是一種描述點在x-y平面上移動的規則,從起始位置開始,每一次叠代使得點移動到新的位置。我們可以把變換想象成點在平面上的軌迹。現在換個思路考慮兩個變換規則,每次叠代将從這兩個規則中随機選擇一個。兩個規則如下:
規則1:P1(x,y) -> P2(x 1, y-1)
規則2:P1(x,y) -> P2(x 1, y 1)
以P(1, 1)作為起始點,如果我們執行4次叠代,将得到以下一系列的點:
P1(1, 1) -> P2(2, 0) (規則1)
P2(2, 0) -> P3(3, 1) (規則2)
P3(3, 1) -> P4(4, 2) (規則2)
P4(4, 2) -> P5(5, 1) (規則2)
...
兩個變換規則是随機選擇的,其中每個規則被選擇的概率相同。無論選擇哪一個規則,點都會右移,因為在兩種規則中都會增加x坐标。當點向右移動時,他們會向上或向下移動,從而形成一條Z字路徑。以下程序繪制了在指定的叠代次數内進行上述轉換規則之一時點的路徑:
'''
Example of selecting a transformation from two equally probable
transformations
'''
import matplotlib.pyplot as plt
import random
def transformation_1(p):
x = p[0]
y = p[1]
return x 1, y - 1
def transformation_2(p):
x = p[0]
y = p[1]
return x 1, y 1
def transform(p):
# List of transformation functions
transformations = [transformation_1, transformation_2]
# pick a random transformation function and call it
t = random.choice(transformations)
x, y = t(p)
return x, y
def build_trajectory(p, n):
x = [p[0]]
y = [p[1]]
for i in range(n):
p = transform(p)
x.append(p[0])
y.append(p[1])
return x, y
if __name__ == '__main__':
# Initial point
p = (1,1)
n = int(input('Enter the number of iterations: '))
x , y = build_trajectory(p, n)
# PLot
plt.plot(x, y)
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
我們定義了兩個函數transformation_1()和transformation_2(),分别對應于之前的兩種變換規則,在transform()函數中,我們創建了一個包含這兩個函數名字的列表,然後使用random.choice()函數從該列表中選擇去哦中一個進行變換。現在假設我們選擇了其中一個變換,蔣點P作為輸入參數調用該變換函數,然後分别使用x,y來存儲變換後的坐标并且返回它們。
從列表中随機選擇一個元素
我們在第一個分形程序中看到的random.choice()函數可以用來從列表中随機選擇一個元素,每一個元素被選中的概率相同,下面是一個例子:
import random
>>> l = [1,2,3]
>>> random.choice(l)
1
>>> random.choice(l)
3
>>> random.choice(l)
3
>>> random.choice(l)
1
>>> random.choice(l)
1
這個函數也适用于元組和字符串。在後一種情形中,函數從字符串中随即返回一個字符。
當運行程序,他首先會詢問叠代次數n,即應用變化的次數。然後調用build_trajectory()函數,該函數的輸入參數為叠代次數n和起始點坐标p,此處設置初始點坐标為(1,1)。build_trajectory()函數重複調用n次transform()函數,并使用兩個列表x和y分别存儲變換後的x和y坐标。最後使用這兩個列表來繪制圖形。
下面兩張圖分别顯示了100次和10000次叠代的點的軌迹圖,這兩幅圖中的Z字形運動都很明顯,這種Z字形路徑通常被稱為一條線上的随機遊走。
叠代100次的Z字路徑
叠代10000次的Z字路徑
這個例子展示了創建分形的基本思想,即從一個點開始并對其重複應用某種變換。接下來,我們将看到一個用相同想法繪制Barnsley蕨類植物的例子。
6.2.2 繪制Barnsley蕨類植物英國數學家Michael Barnsley描述了如何對一個點進行重複的簡單變換,從而創建蕨類植物的結構(如下圖)。
蕨類植物
他提出了以下步驟來創建類似于蕨類植物的結構,以(0,0)為初始點,按事先分配的概率随機選擇下述某種變換。
(1)變換1(概率為0.85):
(2)變換2(概率為0.07):
(3)變換3(概率為0.07):
(4)變換4(概率為0.01):
上述每一個變換對應于蕨類植物的一部分。第一個變換被選中的概率最大,因此被執行的次數最多,從而産生了蕨類植物的莖和底部的葉子。第二個和第三個變換分别對應于左邊和右邊底部的葉子,第四個變換繪制了蕨類植物的莖。
這是一個非均勻概率選擇的例子,我們在第五章中已經學習過,以下程序為指定的點數繪制Barnsley蕨類植物。
'''
Draw a Barnsley Fern
'''
import random
import matplotlib.pyplot as plt
def transformation_1(p):
x = p[0]
y = p[1]
x1 = 0.85*x 0.04*y
y1 = -0.04*y 0.85*y 1.6
return x1, y1
def transformation_2(p):
x = p[0]
y = p[1]
x1 = 0.2*x - 0.26*y
y1 = 0.23*y 0.22*y 1.6
return x1, y1
def transformation_3(p):
x = p[0]
y = p[1]
x1 = -0.15*x 0.28*y
y1 = 0.26*y 0.24*y 0.44
return x1, y1
def transformation_4(p):
x = p[0]
y = p[1]
x1 = 0
y1 = 0.16*y
return x1, y1
def get_index(probability):
r = random.random()
c_probability = 0
sum_probability = []
for p in probability:
c_probability = p
sum_probability.append(c_probability)
for item, sp in enumerate(sum_probability):
if r < sp:
return item
return len(probability) - 1
def transform(p):
# List of transformation functions
transformation = [transformation_1, transformation_2, transformation_3, transformation_4]
probability = [0.85, 0.07, 0.07, 0.01]
# Pick a random transformation function and call it
tindex = get_index(probability)
t = transformation[tindex]
x, y = t(p)
return x, y
def draw_fern(n):
# We start with (0,0)
x = [0]
y = [0]
x1, y1 = 0, 0
for i in range(n):
x1, y1 = transform((x1, y1))
x.append(x1)
y.append(y1)
return x, y
if __name__ == '__main__':
n = int(input('Enter the number of points in the Ferns: '))
x, y = draw_fern(n)
plt.plot(x, y, 'o')
plt.title('Fern with {0} points'.format(n))
plt.show()
運行此程序,他首先詢問蕨類植物圖中指定的點數,然後開始繪制該圖。下面兩張圖分别展示了具有1000個點和10000個點的蕨類植物圖。
制定了1000個點的蕨類植物葉片
指定了10000個點的蕨類植物葉片
這4個變換規則分别在transformation_1(),transformation_2(),transformation_3(),transformation_4()函數中定義。get_index()函數返回按照給定概率下的一種随機變化的索引值,這個概率我們之前已經講過了,不清楚的可以返回去在第五章非均勻概率那裡再次學習。返回索引之後即可選擇某一個具體的變換來應用。
初始點(0,0)變換的次數即為程序輸入中指定的蕨類植物點的個數。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!