数学界隈では何を今更という話になりそうだが、知らなかった者にとってはアートだったのです。初学者の手習い。
いくつか描いた
バーンズリーのシダ(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
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() # 描画した図を表示
バーンスレイのシダ(フラクタル)を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()
その他
Qiita参考
こちらはJavaScript
数学って本来面白いものだったんだよな...。
以上お楽しみいただければさいわいです。