アルゴリズム

[Python] フラクタル図形のジュリア集合を描画する方法

ジュリア集合は、複素平面上の各点に対して特定の複素数を使った反復操作を行い、その結果に基づいて点を色分けすることで描画されます。

Pythonでは、matplotlibnumpyを使用してジュリア集合を描画できます。

基本的な手順は、複素数平面上の各点に対して反復計算を行い、発散するかどうかを判定します。

発散の速さに応じて色を決定し、結果を画像として表示します。

ジュリア集合とは何か

ジュリア集合は、複素数を用いたフラクタル図形の一種で、特定の複素定数cに基づいて生成されます。

ジュリア集合は、与えられた複素数の初期値から始まり、反復計算を行うことで得られる点の集合です。

反復計算の結果が無限大に発散するかどうかによって、各点が集合に含まれるかどうかが決まります。

ジュリア集合は、複雑で美しいパターンを持ち、数学やアートの分野で広く利用されています。

特に、色付けの方法によって多様なビジュアルが得られるため、視覚的に魅力的な作品を作成することが可能です。

Pythonでジュリア集合を描画するための準備

必要なライブラリのインストール

ジュリア集合を描画するためには、主にmatplotlibnumpyという2つのライブラリが必要です。

これらは、数値計算やグラフ描画に非常に便利なツールです。

以下のコマンドを使用して、これらのライブラリをインストールします。

pip install matplotlib numpy

matplotlibとnumpyの基本的な使い方

  • numpy: 数値計算を効率的に行うためのライブラリで、配列や行列の操作が得意です。

特に、数値の計算やデータの処理に役立ちます。

  • matplotlib: データの可視化を行うためのライブラリで、グラフや図形を描画するのに使用します。

特に、2Dプロットに強力な機能を持っています。

以下は、numpymatplotlibを使った基本的な例です。

import numpy as np
import matplotlib.pyplot as plt
# 1次元の配列を作成
x = np.linspace(-2, 2, 100)
y = np.sin(x)
# グラフを描画
plt.plot(x, y)
plt.title("Sine Wave")
plt.xlabel("x")
plt.ylabel("sin(x)")
plt.grid()
plt.show()

このコードを実行すると、サイン波のグラフが表示されます。

複素数の扱い方とPythonでの表現

Pythonでは、複素数を簡単に扱うことができます。

複素数は、complex型を使用して表現され、実部と虚部を持ちます。

以下は、複素数の基本的な使い方の例です。

# 複素数の定義
z = complex(1, 2)  # 1 + 2i
# 複素数の実部と虚部を取得
real_part = z.real  # 1.0
imaginary_part = z.imag  # 2.0
# 複素数の演算
z_conjugate = z.conjugate()  # 1 - 2i

このように、Pythonでは複素数を簡単に定義し、演算を行うことができます。

ジュリア集合の描画においても、複素数の操作が重要な役割を果たします。

ジュリア集合の描画アルゴリズム

複素平面の定義と範囲設定

ジュリア集合を描画するためには、まず複素平面を定義し、その範囲を設定する必要があります。

複素平面は、実数軸と虚数軸から成り立っており、各点は複素数として表現されます。

一般的には、以下のように範囲を設定します。

  • 実部の範囲: [2,2]
  • 虚部の範囲: [2,2]

この範囲内の各点を反復計算の初期値として使用します。

以下は、範囲を設定するためのサンプルコードです。

# 複素平面の範囲設定
x_min, x_max = -2, 2
y_min, y_max = -2, 2
width, height = 800, 800  # 画像のサイズ

反復計算の仕組み

ジュリア集合の描画には、反復計算が重要です。

各点zに対して、次の式を用いて反復を行います。

 zn+1=zn2+c

ここで、cは固定された複素数で、初期値z0は複素平面上の点です。

この計算を一定回数(例えば100回)繰り返し、発散するかどうかを判断します。

以下は、反復計算のサンプルコードです。

def iterate(z, c, max_iter):
    for n in range(max_iter):
        if abs(z) > 2:  # 発散条件
            return n
        z = z**2 + c
    return max_iter  # 発散しなかった場合

発散条件の設定

発散条件は、反復計算の結果が無限大に発散するかどうかを判断するための基準です。

一般的には、複素数の絶対値が2を超えた時点で発散と見なします。

この条件を用いて、各点がジュリア集合に含まれるかどうかを決定します。

上記のiterate関数内でこの条件を設定しています。

色付けの方法と発散速度の可視化

ジュリア集合の魅力は、色付けによって得られる美しいビジュアルにあります。

発散速度に応じて色を変えることで、視覚的に印象的な図形を描くことができます。

例えば、発散までの反復回数に基づいて色を設定する方法があります。

以下は、色付けのサンプルコードです。

import matplotlib.pyplot as plt
import numpy as np
# 色付けのためのカラーマップ
def color_map(iteration, max_iter):
    return (iteration / max_iter) * 255  # 0-255の範囲にスケーリング
# 描画用の配列を初期化
image = np.zeros((height, width, 3), dtype=np.uint8)
# 各点に対して反復計算を行い、色を設定
for x in range(width):
    for y in range(height):
        zx = x_min + (x / width) * (x_max - x_min)
        zy = y_min + (y / height) * (y_max - y_min)
        z = complex(zx, zy)
        c = complex(-0.7, 0.27015)  # 固定された複素数
        iteration = iterate(z, c, 100)
        color_value = color_map(iteration, 100)
        image[y, x] = [color_value, 0, 255 - color_value]  # RGB色設定
# 画像を表示
plt.imshow(image)
plt.axis('off')
plt.show()

このコードを実行すると、ジュリア集合の美しい図形が描画されます。

色付けの方法を工夫することで、さまざまなパターンを楽しむことができます。

実際にジュリア集合を描画する

基本的なコードの実装

ジュリア集合を描画するための基本的なコードを以下に示します。

このコードでは、複素平面上の各点に対して反復計算を行い、発散速度に基づいて色を設定します。

import numpy as np
import matplotlib.pyplot as plt
# 複素平面の範囲設定
x_min, x_max = -2, 2
y_min, y_max = -2, 2
width, height = 800, 800  # 画像のサイズ
# 反復計算の関数
def iterate(z, c, max_iter):
    for n in range(max_iter):
        if abs(z) > 2:  # 発散条件
            return n
        z = z**2 + c
    return max_iter  # 発散しなかった場合
# 描画用の配列を初期化
image = np.zeros((height, width, 3), dtype=np.uint8)
# 各点に対して反復計算を行い、色を設定
for x in range(width):
    for y in range(height):
        zx = x_min + (x / width) * (x_max - x_min)
        zy = y_min + (y / height) * (y_max - y_min)
        z = complex(zx, zy)
        c = complex(-0.7, 0.27015)  # 固定された複素数
        iteration = iterate(z, c, 100)
        color_value = (iteration / 100) * 255  # 色付け
        image[y, x] = [color_value, 0, 255 - color_value]  # RGB色設定
# 画像を表示
plt.imshow(image)
plt.axis('off')
plt.show()

このコードを実行すると、ジュリア集合の基本的な図形が描画されます。

描画範囲の調整とズーム機能の追加

描画範囲を調整することで、特定の部分を拡大して詳細を観察することができます。

ズーム機能を追加するためには、範囲を動的に変更する引数を用意します。

以下は、ズーム機能を追加したコードの例です。

def draw_julia(c, x_min, x_max, y_min, y_max, width, height):
    image = np.zeros((height, width, 3), dtype=np.uint8)
    for x in range(width):
        for y in range(height):
            zx = x_min + (x / width) * (x_max - x_min)
            zy = y_min + (y / height) * (y_max - y_min)
            z = complex(zx, zy)
            iteration = iterate(z, c, 100)
            color_value = (iteration / 100) * 255
            image[y, x] = [color_value, 0, 255 - color_value]
    plt.imshow(image)
    plt.axis('off')
    plt.show()
# ズームしたい範囲を指定
draw_julia(complex(-0.7, 0.27015), -1, 1, -1, 1, 800, 800)

このコードを実行すると、指定した範囲でジュリア集合が描画されます。

色のグラデーションを使った美しい描画

色のグラデーションを使うことで、ジュリア集合のビジュアルをさらに美しくすることができます。

発散速度に応じて異なる色を設定する方法を以下に示します。

def color_map(iteration, max_iter):
    if iteration == max_iter:
        return [0, 0, 0]  # 発散しなかった場合は黒
    else:
        return [iteration * 10 % 256, 0, 255 - iteration * 5 % 256]  # グラデーション
def draw_julia_with_gradient(c, x_min, x_max, y_min, y_max, width, height):
    image = np.zeros((height, width, 3), dtype=np.uint8)
    for x in range(width):
        for y in range(height):
            zx = x_min + (x / width) * (x_max - x_min)
            zy = y_min + (y / height) * (y_max - y_min)
            z = complex(zx, zy)
            iteration = iterate(z, c, 100)
            image[y, x] = color_map(iteration, 100)
    plt.imshow(image)
    plt.axis('off')
    plt.show()
# グラデーションを使った描画
draw_julia_with_gradient(complex(-0.7, 0.27015), -2, 2, -2, 2, 800, 800)

このコードを実行すると、色のグラデーションが施された美しいジュリア集合が描画されます。

複素定数cの変更によるパターンの変化

ジュリア集合の形状は、複素定数cの値によって大きく変化します。

異なるcの値を試すことで、さまざまなパターンを観察できます。

以下は、複素定数を変更して描画する例です。

# 複素定数を変更して描画
c_values = [complex(-0.7, 0.27015), complex(0.355, 0.355), complex(-0.4, 0.6)]
for c in c_values:
    draw_julia_with_gradient(c, -2, 2, -2, 2, 800, 800)

このコードを実行すると、異なる複素定数に基づくジュリア集合が次々と描画され、各パターンの違いを楽しむことができます。

完全なサンプルコード

以下に、ジュリア集合を描画するための完全なサンプルコードを示します。

このコードは、必要なライブラリのインポートから始まり、複素平面の範囲設定、反復計算、色付け、そして最終的な描画までを含んでいます。

import numpy as np
import matplotlib.pyplot as plt
# 複素平面の範囲設定
x_min, x_max = -2, 2
y_min, y_max = -2, 2
width, height = 800, 800  # 画像のサイズ
# 反復計算の関数
def iterate(z, c, max_iter):
    for n in range(max_iter):
        if abs(z) > 2:  # 発散条件
            return n
        z = z**2 + c
    return max_iter  # 発散しなかった場合
# 色付けのためのカラーマップ
def color_map(iteration, max_iter):
    if iteration == max_iter:
        return [0, 0, 0]  # 発散しなかった場合は黒
    else:
        return [iteration * 10 % 256, 0, 255 - iteration * 5 % 256]  # グラデーション
# ジュリア集合を描画する関数
def draw_julia(c, x_min, x_max, y_min, y_max, width, height):
    image = np.zeros((height, width, 3), dtype=np.uint8)
    for x in range(width):
        for y in range(height):
            zx = x_min + (x / width) * (x_max - x_min)
            zy = y_min + (y / height) * (y_max - y_min)
            z = complex(zx, zy)
            iteration = iterate(z, c, 100)
            image[y, x] = color_map(iteration, 100)
    plt.imshow(image)
    plt.axis('off')
    plt.title(f"ジュリア集合 (c = {c})")
    plt.show()
# 複素定数を指定して描画
c_value = complex(-0.7, 0.27015)  # 変更可能な複素定数
draw_julia(c_value, x_min, x_max, y_min, y_max, width, height)

このコードを実行すると、指定した複素定数cに基づくジュリア集合が描画されます。

c_valueを変更することで、異なるパターンを楽しむことができます。

ジュリア集合の応用例

アニメーションによる動的なジュリア集合の描画

ジュリア集合をアニメーション化することで、時間の経過とともに変化する美しいフラクタルを楽しむことができます。

以下は、複素定数cを徐々に変化させながらジュリア集合を描画するアニメーションのサンプルコードです。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# 反復計算の関数
def iterate(z, c, max_iter):
    for n in range(max_iter):
        if abs(z) > 2:
            return n
        z = z**2 + c
    return max_iter
# 色付けのためのカラーマップ
def color_map(iteration, max_iter):
    if iteration == max_iter:
        return [0, 0, 0]
    else:
        return [iteration * 10 % 256, 0, 255 - iteration * 5 % 256]
# アニメーションの描画関数
def update(frame):
    plt.clf()  # 前のフレームをクリア
    c = complex(np.cos(frame / 10), np.sin(frame / 10))  # cを動的に変更
    image = np.zeros((height, width, 3), dtype=np.uint8)
    for x in range(width):
        for y in range(height):
            zx = x_min + (x / width) * (x_max - x_min)
            zy = y_min + (y / height) * (y_max - y_min)
            z = complex(zx, zy)
            iteration = iterate(z, c, 100)
            image[y, x] = color_map(iteration, 100)
    plt.imshow(image)
    plt.axis('off')
    plt.title(f"ジュリア集合 (c = {c})")
# アニメーションの設定
x_min, x_max = -2, 2
y_min, y_max = -2, 2
width, height = 800, 800
fig = plt.figure()
ani = animation.FuncAnimation(fig, update, frames=100, interval=100)
plt.show()

このコードを実行すると、ジュリア集合が動的に変化するアニメーションが表示されます。

インタラクティブなジュリア集合の描画ツールの作成

インタラクティブなツールを作成することで、ユーザーが複素定数cを自由に変更し、リアルタイムでジュリア集合を描画できるようになります。

以下は、matplotlibのスライダーを使用したインタラクティブな描画ツールの例です。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
# 反復計算の関数
def iterate(z, c, max_iter):
    for n in range(max_iter):
        if abs(z) > 2:
            return n
        z = z**2 + c
    return max_iter
# 色付けのためのカラーマップ
def color_map(iteration, max_iter):
    if iteration == max_iter:
        return [0, 0, 0]
    else:
        return [iteration * 10 % 256, 0, 255 - iteration * 5 % 256]
# ジュリア集合を描画する関数
def draw_julia(c):
    image = np.zeros((height, width, 3), dtype=np.uint8)
    for x in range(width):
        for y in range(height):
            zx = x_min + (x / width) * (x_max - x_min)
            zy = y_min + (y / height) * (y_max - y_min)
            z = complex(zx, zy)
            iteration = iterate(z, c, 100)
            image[y, x] = color_map(iteration, 100)
    plt.imshow(image)
    plt.axis('off')
    plt.title(f"ジュリア集合 (c = {c})")
# インタラクティブなスライダーの設定
x_min, x_max = -2, 2
y_min, y_max = -2, 2
width, height = 800, 800
c_real = -0.7
c_imag = 0.27015
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)
draw_julia(complex(c_real, c_imag))
# スライダーの作成
axcolor = 'lightgoldenrodyellow'
ax_real = plt.axes([0.1, 0.1, 0.65, 0.03], facecolor=axcolor)
ax_imag = plt.axes([0.1, 0.15, 0.65, 0.03], facecolor=axcolor)
s_real = Slider(ax_real, 'Real Part', -1.5, 1.5, valinit=c_real)
s_imag = Slider(ax_imag, 'Imaginary Part', -1.5, 1.5, valinit=c_imag)
# スライダーの更新関数
def update(val):
    c = complex(s_real.val, s_imag.val)
    draw_julia(c)
s_real.on_changed(update)
s_imag.on_changed(update)
plt.show()

このコードを実行すると、スライダーを使って複素定数cの実部と虚部を調整し、リアルタイムでジュリア集合を描画することができます。

高解像度のジュリア集合画像を生成する方法

高解像度のジュリア集合画像を生成するためには、描画サイズを大きく設定し、適切な画像フォーマットで保存することが重要です。

以下は、高解像度の画像を生成するためのサンプルコードです。

import numpy as np
import matplotlib.pyplot as plt
# 複素平面の範囲設定
x_min, x_max = -2, 2
y_min, y_max = -2, 2
width, height = 4000, 4000  # 高解像度のサイズ
# 反復計算の関数
def iterate(z, c, max_iter):
    for n in range(max_iter):
        if abs(z) > 2:
            return n
        z = z**2 + c
    return max_iter
# 色付けのためのカラーマップ
def color_map(iteration, max_iter):
    if iteration == max_iter:
        return [0, 0, 0]
    else:
        return [iteration * 10 % 256, 0, 255 - iteration * 5 % 256]
# 高解像度のジュリア集合を描画する関数
def draw_high_res_julia(c):
    image = np.zeros((height, width, 3), dtype=np.uint8)
    for x in range(width):
        for y in range(height):
            zx = x_min + (x / width) * (x_max - x_min)
            zy = y_min + (y / height) * (y_max - y_min)
            z = complex(zx, zy)
            iteration = iterate(z, c, 100)
            image[y, x] = color_map(iteration, 100)
    plt.imsave('high_res_julia.png', image)  # 画像を保存
# 複素定数を指定して高解像度画像を生成
c_value = complex(-0.7, 0.27015)
draw_high_res_julia(c_value)

このコードを実行すると、高解像度のジュリア集合画像がhigh_res_julia.pngとして保存されます。

クリック・タップで拡大

画像サイズを大きくすることで、詳細なフラクタルパターンを楽しむことができます。

まとめ

この記事では、ジュリア集合の基本的な概念から、Pythonを用いた描画方法、さらには応用例まで幅広く取り上げました。

ジュリア集合は、複素数を用いたフラクタル図形であり、特定の複素定数に基づいて生成される美しいパターンを持っています。

これを機に、さまざまな複素定数を試しながら、自分だけのジュリア集合を描いてみることをお勧めします。

関連記事

Back to top button
目次へ