8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Pythonでフラクタル - バーンズリーのシダ

Last updated at Posted at 2021-05-02

数学界隈では何を今更という話になりそうだが、知らなかった者にとってはアートだったのです。初学者の手習い。

barnsley.gif

いくつか描いた

バーンズリーのシダ(Wikipedia) より

barnsley1.py
#!python3.8

import turtle
import random

pen = turtle.Turtle()
pen.speed(20)
pen.color('green')
pen.penup()

x = 0
y = 0
for n in range(100000):
    pen.goto(85*x, 57*y-275)  # 57はシダの拡大、-275は下から描き始める意図
    pen.pendown()
    pen.dot()
    pen.penup()
    r = random.random()  # 確率を得る
    r = r * 100
    xn = x
    yn = y
    if r < 1:  # 確率に基づいたelif
        x = 0
        y = 0.16 * yn
    elif r < 86:
        x = 0.85 * xn + 0.04 * yn
        y = -0.04 * xn + 0.85 * yn + 1.6
    elif r < 93:
        x = 0.20 * xn - 0.26 * yn
        y = 0.23 * xn + 0.22 * yn + 1.6
    else:
        x = -0.15 * xn + 0.28 * yn
        y = 0.26 * xn + 0.24 * yn + 0.44

image.png

pythonでバーンズリーのシダを描いてみよう<pythonでフラクタル> より

barnsley2.py
#!python3.8

import matplotlib.pyplot as plt
import random

# 原点を(0, 0)に設定
x, y = 0, 0

# 計算したx座標とy座標を格納するリストを生成
X_list = []
Y_list = []

# X_listとY_listに原点の座標を追加しておく
X_list.append(0)
Y_list.append(0)

# 100000回繰り返す
for i in range(100000):
    #1から100までの乱数を発生させる
    s = random.randint(1, 100)
    if s <=1:      # 1%の確率でこれが起きる
        X = 0.0
        Y = 0.16*y
    
    elif 2 <= s <= 8:      # 7%の確率でこれが起きる
        X = 0.2*x - 0.26*y
        Y = 0.23*x + 0.22*y + 1.6
    
    elif 9 <= s <= 15:      # 7%の確率でこれが起きる
        X = -0.15*x + 0.28*y
        Y = 0.26*x + 0.24*y + 0.44
    
    else:      # 85%の確率でこれが起きる
        X = 0.85*x + 0.04*y
        Y = -0.04*x + 0.85*y + 1.6
    
    X_list.append(X)      # X_listにXの値を追加
    Y_list.append(Y)      # Y_listにYの値を追加
    x = X
    y = Y

plt.scatter(X_list, Y_list, s=0.01, c='green')      # X_listとY_listに入っている値を散布図として描画(サイズは0.01、色は緑)
plt.xlim(-5, 5)      # 散布図のx座標の範囲を設定
plt.ylim(0, 10)      # 散布図のy座標の範囲を設定
plt.show()      # 描画した図を表示

image.png

バーンスレイのシダ(フラクタル)をPythonで描いてみる より

barnsley3.py
#!python3.8

import matplotlib.pyplot as plt
import random

def transformation_1(p): # 85%でこれが選ばれる。茎を右上へ伸ばしていく。時計回りに少し回転させ、少し小さくする。大きく上にシフトする。
    x = p[0]
    y = p[1]
    x_1 =  0.85*x + 0.04*y
    y_1 = -0.04*x + 0.85*y + 1.6
    return x_1,y_1
 
def transformation_2(p): # 茎に対して左側の葉っぱを作るように左大回転、かなり小さくする。大きく上にシフトする。
    x = p[0]
    y = p[1]
    x_1 =  0.20*x - 0.26*y
    y_1 =  0.23*x + 0.22*y + 1.6
    return x_1,y_1
 
def transformation_3(p): # 茎に対して右側の葉っぱを作るように右大回転、かなり小さくする。少し上にシフトする。
    x = p[0]
    y = p[1]
    x_1 = -0.15*x + 0.28*y
    y_1 =  0.26*x + 0.24*y + 0.44
    return x_1,y_1
 
def transformation_4(p): # 中央下部の茎を作る。今までの横推移(x)を中央(0)に戻し、下部の茎まで戻す。
    x = p[0]
    y = p[1]
    x_1 = 0
    y_1 = 0.16*y
    return x_1,y_1
 
def get_index(probability): # 乱数に応じて、変換を割り当てる指数を決める
    r = random.random() # 乱数 0<=r<=1 を生成する
    c_probability = 0
    sum_probability = []
    for p in probability:
        c_probability += p # 確率リストの値をc_probabilityに加えていく
        sum_probability.append(c_probability) # c_probabilityをリストに追加する
    for item, sp in enumerate(sum_probability): # itemをインデックス、spをそのインデックスでのリストの値とする
        if r <= sp:
            return item # 乱数<=リスト(sum_probability)の値になったとき、そのインデックス(0,1,2)を返す。
    return len(probability)-1 # sum_probabilityの値がすべてrより小さいなら、インデックスは3とする
 
def transform(p): # 点pを確率的に変換して返す
    transformations = [transformation_1, transformation_2, transformation_3, transformation_4]
    probability = [0.85,0.07,0.07,0.01] # それぞれの変換が選ばれる確率を指定
    tindex = get_index(probability) # 確率に応じて1~4のインデックスを決める
    x,y = transformations[tindex](p) # 決まったインデックスの変換を施す
    return x,y
 
def draw_fern(n): # 全体を描写する
    x=[0]
    y=[0]
    x_1,y_1 = 0,0 # 初期値は(0,0)
    for i in range(n):
        x_1,y_1 = transform((x_1,y_1)) # 確率的に点を変換する
        x.append(x_1)
        y.append(y_1) # 変換した点をリストに保存し、その点を再び変換していく
    return x,y
 
x,y = draw_fern(100000) # プロット数。多いと時間がかかるので各自調整。

plt.plot(x,y,'.',markersize=1,color='green')
plt.show()

Barnsley Fern Python script より

barnsley4.py
#!python3.8

from PIL import Image
import random
import matplotlib.pyplot as plt
A=[]
mat=[[0.0,0.0,0.0,0.16,0.0,0.0,0.01],
[0.85,0.04,-0.04,0.85,0.0,1.6,0.85],
[0.2,-0.26,0.23,0.22,0.0,1.6,0.07],
[-0.15,0.28,0.26,0.24,0.0,0.44,0.07]]
x=0.0
y=0.0
for k in range(0,100000):
    p=random.random()
    if p <= mat[0][6]:
        i=0
    elif p <= mat[0][6] + mat[1][6]:
        i=1
    elif p <= mat[0][6] + mat[1][6] + mat[2][6]:
        i=2
    else:
        i=3

    x0 = x * mat[i][0] + y * mat[i][1] + mat[i][4]
    y  = x * mat[i][2] + y * mat[i][3] + mat[i][5]
    x = x0

    ptn=[x,y]
    A.append(ptn)

plt.figure(figsize=(10,15))
plt.scatter( *zip(*A),marker='o', color='g',s=0.1)
plt.show()

image.png

その他

Qiita参考

こちらはJavaScript

数学って本来面白いものだったんだよな...。
以上お楽しみいただければさいわいです。

8
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?