今回は色々な図形を組み合わせて
デジタルアートを作ってみました
解説動画はこちら
はじめに
今回はPythonで作図できる図形を組み合わせて
デジタルアートを作るものです
今回紹介する図形は以下です。
ライブラリのインストール
今回はGoogle Colabを用いて作図します。
日本語は表示できないので
日本語表示のライブラリをインストールしておいてください。
円が他の円の内側や外側を転がることで描かれる曲線です
ほぼほぼスピログラフですね
曼荼羅
同心円状や同心方形状に
円や方形の図形を配置した図形のことです
こんな感じで、図形を組み合わせることで
様々な紋様を描く事ができます。
複雑な図形を組み合わせれば
それなりにアートっぽく
なって行くんではないでしょうか
気になった方はコピペして
色々パラメータ変えて
試してみてください
それでは。
デジタルアートを作ってみました
解説動画はこちら
はじめに
今回はPythonで作図できる図形を組み合わせて
デジタルアートを作るものです
今回紹介する図形は以下です。
リサージュ図形
ローズ曲線
スピログラフ
ヒルベルト曲線
ドラゴンカーブ
ペンローズタイル(没)
トロコイド曲線
曼荼羅
早速図形を描いてみましょう。
早速図形を描いてみましょう。
ライブラリのインストール
今回はGoogle Colabを用いて作図します。
日本語は表示できないので
日本語表示のライブラリをインストールしておいてください。
pip install japanize_matplotlib
リサージュ図形
二つの正弦波を組み合わせてできる曲線です
周波数や位相の違いで様々なパターンが生成されます
二つの正弦波を組み合わせてできる曲線です
周波数や位相の違いで様々なパターンが生成されます
import numpy as np import matplotlib.pyplot as plt import japanize_matplotlib # パラメータ設定 A = 1 B = 1 a = 5 b = 4 delta = np.pi / 2 # tの範囲 t = np.linspace(0, 2 * np.pi, 1000) # x, y の計算 x = A * np.sin(a * t + delta) y = B * np.sin(b * t) # 描画 plt.figure(figsize=(6, 6)) plt.plot(x, y) plt.axis('off') plt.show()
import numpy as np import matplotlib.pyplot as plt # 図形の数と色の設定 num_shapes = 10 colors = plt.cm.viridis(np.linspace(0, 1, num_shapes)) # 描画設定 plt.figure(figsize=(8, 8)) # 各リサージュ図形の描画 for i in range(num_shapes): A = 1 B = 1 a = np.random.randint(1, 10) b = np.random.randint(1, 10) delta = np.random.uniform(0, 2 * np.pi) t = np.linspace(0, 2 * np.pi, 1000) x = A * np.sin(a * t + delta) y = B * np.sin(b * t) plt.plot(x, y, color=colors[i], alpha=0.7) # グラフの設定 plt.title("複雑なリサージュアート") plt.axis('equal') plt.axis('off') plt.show()
ローズ曲線
極座標を使って描く花のような形の曲線です
極座標を使って描く花のような形の曲線です
import numpy as np import matplotlib.pyplot as plt # パラメータ設定 k = 5 # kは整数または分数 a = 1 # 振幅 # tの範囲 t = np.linspace(0, 2 * np.pi, 1000) # x, y の計算 x = a * np.cos(k * t) * np.cos(t) y = a * np.cos(k * t) * np.sin(t) # 描画 plt.figure(figsize=(6, 6)) plt.plot(x, y, color='magenta') plt.title("ローズ曲線") plt.axis('equal') plt.axis('off') plt.show()
import numpy as np import matplotlib.pyplot as plt # パラメータのリスト k_values = np.arange(1, 6) a_values = np.linspace(0.5, 2.5, 5) # プロット設定 fig, axes = plt.subplots(5, 5, figsize=(6,6)) fig.suptitle("ローズ曲線のグリッド", fontsize=16) # 各プロットの描画 for i, a in enumerate(a_values): for j, k in enumerate(k_values): t = np.linspace(0, 2 * np.pi, 1000) x = a * np.cos(k * t) * np.cos(t) y = a * np.cos(k * t) * np.sin(t) ax = axes[i, j] ax.plot(x, y, color='magenta') ax.set_title(f'k={k}, a={a:.1f}') ax.axis('equal') ax.set_xlim(-2.5, 2.5) ax.set_ylim(-2.5, 2.5) ax.axis('off') # 軸を非表示 plt.tight_layout(rect=[0, 0, 1, 0.96]) plt.show()
スピログラフ
小学生の時とかに作図キットを持っている人もいたかも
あれをPythonで再現します
歯車を使って描くような複雑な曲線です
パラメータを変えることで多様な形ができます
パラメータを変えることで多様な形ができます
小学生の時とかに作図キットを持っている人もいたかも
あれをPythonで再現します
import numpy as np import matplotlib.pyplot as plt # スピログラフのパラメータ R = 100 # 大きい円の半径 r = 30 # 小さい円の半径 d = 160 # 描画する点の距離 # 最大公約数を使って完全なループを描画 gcd = np.gcd(R, r) lcm = (R * r) // gcd t = np.linspace(0, 2 * np.pi * (r // gcd), 1000 * (r // gcd)) # 描画設定 fig, ax = plt.subplots(figsize=(8, 8)) ax.set_xlim(-R - r - d, R + r + d) ax.set_ylim(-R - r - d, R + r + d) ax.set_aspect('equal') ax.axis('off') # スピログラフの描画 x = (R - r) * np.cos(t) + d * np.cos((R - r) / r * t) y = (R - r) * np.sin(t) - d * np.sin((R - r) / r * t) ax.plot(x, y, color='blue') plt.show()
import numpy as np import matplotlib.pyplot as plt # スピログラフのパラメータ r = 30 # 小さい円の半径 # 描画設定 fig, axs = plt.subplots(5, 5, figsize=(8,8)) fig.subplots_adjust(hspace=0.3, wspace=0.3) # Rとdを変化させてプロット R_values = np.linspace(50, 150, 5) d_values = np.linspace(20, 80, 5) for i, R in enumerate(R_values): for j, d in enumerate(d_values): ax = axs[i, j] gcd = np.gcd(int(R), r) t = np.linspace(0, 2 * np.pi * (r // gcd), 1000 * (r // gcd)) x = (R - r) * np.cos(t) + d * np.cos((R - r) / r * t) y = (R - r) * np.sin(t) - d * np.sin((R - r) / r * t) ax.plot(x, y, color='blue') ax.set_xlim(-R - r - d, R + r + d) ax.set_ylim(-R - r - d, R + r + d) ax.set_aspect('equal') ax.axis('off') ax.set_title(f"R={int(R)}, d={int(d)}", fontsize=8) plt.show()
import numpy as np import matplotlib.pyplot as plt # スピログラフのパラメータ R = 150 # 大きい円の半径 r1 = 30 # 中間の円の半径 r2 = 15 # 小さい円の半径 d = 50 # 描画する点の距離 # 描画設定 fig, ax = plt.subplots(figsize=(8, 8)) ax.set_xlim(-R - r1 - r2 - d, R + r1 + r2 + d) ax.set_ylim(-R - r1 - r2 - d, R + r1 + r2 + d) ax.set_aspect('equal') ax.axis('off') # スピログラフの描画 gcd = np.gcd(np.gcd(R, r1), r2) t = np.linspace(0, 2 * np.pi * (r2 // gcd), 1000 * (r2 // gcd)) x = (R - r1) * np.cos(t) + d * np.cos((R - r1) / r1 * t) + r2 * np.cos((R - r1) / r2 * t) y = (R - r1) * np.sin(t) - d * np.sin((R - r1) / r1 * t) - r2 * np.sin((R - r1) / r2 * t) ax.plot(x, y, color='blue') plt.show()
import numpy as np import matplotlib.pyplot as plt # パラメータ設定 R = 100 # 大きい円の半径 r = 30 # 小さい円の半径 d = 60 # 描画する点の距離 a = 5 # リサージュのx軸周波数 b = 4 # リサージュのy軸周波数 delta = np.pi / 2 # 位相差 # 描画設定 fig, ax = plt.subplots(figsize=(8, 8)) ax.set_xlim(-R - r - d, R + r + d) ax.set_ylim(-R - r - d, R + r + d) ax.set_aspect('equal') ax.axis('off') # スピログラフの方程式 gcd = np.gcd(R, r) t = np.linspace(0, 2 * np.pi * (r // gcd), 1000 * (r // gcd)) x_spiro = (R - r) * np.cos(t) + d * np.cos((R - r) / r * t) y_spiro = (R - r) * np.sin(t) - d * np.sin((R - r) / r * t) # リサージュの方程式 x_lissajous = np.sin(a * t + delta) y_lissajous = np.sin(b * t) # 合成 x = x_spiro + x_lissajous * 10 y = y_spiro + y_lissajous * 10 # 図形の描画 ax.plot(x, y, color='blue') plt.show()
ヒルベルト曲線
空間を埋め尽くすフラクタルの一種で
曲線が空間を埋めるように描かれます
空間を埋め尽くすフラクタルの一種で
曲線が空間を埋めるように描かれます
import matplotlib.pyplot as plt def hilbert_curve(x0, y0, xi, xj, yi, yj, n): if n <= 0: x_mid = x0 + (xi + yi) // 2 y_mid = y0 + (xj + yj) // 2 points.append((x_mid, y_mid)) else: hilbert_curve(x0, y0, yi // 2, yj // 2, xi // 2, xj // 2, n - 1) hilbert_curve(x0 + xi // 2, y0 + xj // 2, xi // 2, xj // 2, yi // 2, yj // 2, n - 1) hilbert_curve(x0 + xi // 2 + yi // 2, y0 + xj // 2 + yj // 2, xi // 2, xj // 2, yi // 2, yj // 2, n - 1) hilbert_curve(x0 + xi // 2 + yi, y0 + xj // 2 + yj, -yi // 2, -yj // 2, -xi // 2, -xj // 2, n - 1) # 描画設定 order = 6 # ヒルベルト曲線の階数 points = [] hilbert_curve(0, 0, 2**order, 0, 0, 2**order, order) # プロット x_vals, y_vals = zip(*points) plt.plot(x_vals, y_vals) plt.title(f'Hilbert Curve of Order {order}') plt.axis('equal') plt.axis('off') plt.show()
ドラゴンカーブ
繰り返し折り返すことで生成されるフラクタル曲線です
中華のどんぶりに描かれている模様っぽいものです
繰り返し折り返すことで生成されるフラクタル曲線です
中華のどんぶりに描かれている模様っぽいものです
import matplotlib.pyplot as plt from math import cos, sin, radians def dragon_curve(order, step=1): def recursive_dragon(n, angle, sign): if n == 0: forward(step) else: recursive_dragon(n - 1, angle, 1) turn(sign * angle) recursive_dragon(n - 1, angle, -1) def forward(dist): nonlocal x, y x += dist * directions[0] y += dist * directions[1] points.append((x, y)) def turn(angle): cos_theta = cos(angle) sin_theta = sin(angle) directions[0], directions[1] = ( directions[0] * cos_theta - directions[1] * sin_theta, directions[0] * sin_theta + directions[1] * cos_theta ) # 初期化 x, y = 0, 0 directions = [1, 0] # 初期方向 points = [(x, y)] # ドラゴンカーブの生成 recursive_dragon(order, radians(90), 1) return points # 描画 order = 10 # ドラゴンカーブの階数 points = dragon_curve(order) x_vals, y_vals = zip(*points) plt.plot(x_vals, y_vals) plt.title(f'Dragon Curve of Order {order}') plt.axis('equal') plt.axis('off') plt.show()
ペンローズタイル(没)
本来は非周期的に平面を埋め尽くすタイルのパターンですが
これはちょいとちがっちゃってます
本来は非周期的に平面を埋め尽くすタイルのパターンですが
これはちょいとちがっちゃってます
import matplotlib.pyplot as plt import numpy as np def draw_kite(ax, x, y, angle, size): # カイトの4つの頂点を計算 points = np.array([ [0, 0], [np.cos(angle), np.sin(angle)], [np.cos(angle + np.pi / 5), np.sin(angle + np.pi / 5)], [np.cos(angle - np.pi / 5), np.sin(angle - np.pi / 5)] ]) * size points += [x, y] ax.fill(points[:, 0], points[:, 1], edgecolor='black', fill=False) def draw_dart(ax, x, y, angle, size): # ダートの4つの頂点を計算 points = np.array([ [0, 0], [np.cos(angle), np.sin(angle)], [np.cos(angle + np.pi / 5) / 2, np.sin(angle + np.pi / 5) / 2], [np.cos(angle - np.pi / 5) / 2, np.sin(angle - np.pi / 5) / 2] ]) * size points += [x, y] ax.fill(points[:, 0], points[:, 1], edgecolor='black', fill=False) def draw_penrose_tiling(order, size): fig, ax = plt.subplots() ax.set_aspect('equal') ax.axis('off') for i in range(order): angle = i * 2 * np.pi / order draw_kite(ax, 0, 0, angle, size) draw_dart(ax, 0, 0, angle, size) plt.show() # 描画 order = 30 size = 1000 draw_penrose_tiling(order, size)
import matplotlib.pyplot as plt import numpy as np def draw_penrose(ax, x, y, angle, size, depth): if depth == 0: return golden_ratio = (1 + np.sqrt(5)) / 2 new_size = size / golden_ratio # パチ形の描画 points = np.array([ [0, 0], [np.cos(angle) * size, np.sin(angle) * size], [np.cos(angle + 2 * np.pi / 5) * size, np.sin(angle + 2 * np.pi / 5) * size], [np.cos(angle - 2 * np.pi / 5) * new_size, np.sin(angle - 2 * np.pi / 5) * new_size] ]) points += np.array([x, y]) ax.fill(points[:, 0], points[:, 1], edgecolor='black', fill=False) # 再帰的に描画 for i in range(5): new_angle = angle + i * 2 * np.pi / 5 draw_penrose(ax, points[i % 4, 0], points[i % 4, 1], new_angle, new_size, depth - 1) def plot_penrose_tiling(size, depth): fig, ax = plt.subplots() ax.set_aspect('equal') ax.axis('off') draw_penrose(ax, 0, 0, 0, size, depth) plt.show() # 描画 size = 300 depth = 2 plot_penrose_tiling(size, depth)
トロコイド曲線
円が他の円の内側や外側を転がることで描かれる曲線です
ほぼほぼスピログラフですね
import matplotlib.pyplot as plt import numpy as np # トロコイド曲線のパラメータ R = 5 # 大きな円の半径 r = 3 # 小さな円の半径 d = 5 # 描画する点の距離 # tの範囲 t = np.linspace(0, 10 * np.pi, 1000) # トロコイド曲線の方程式 x = (R - r) * np.cos(t) + d * np.cos((R - r) / r * t) y = (R - r) * np.sin(t) - d * np.sin((R - r) / r * t) # 描画 plt.plot(x, y) plt.title('Trochoid Curve') plt.axis('equal') plt.axis('off') plt.show()
import matplotlib.pyplot as plt import numpy as np # 固定パラメータ R = 6 # 大きな円の半径 # tの範囲 t = np.linspace(0, 10 * np.pi, 1000) # プロットの準備 fig, axes = plt.subplots(5, 5, figsize=(8,8)) fig.suptitle('Trochoid Curves') # rとdを変化させてプロット r_values = np.linspace(1, 5, 5) d_values = np.linspace(1, 5, 5) for i, r in enumerate(r_values): for j, d in enumerate(d_values): x = (R - r) * np.cos(t) + d * np.cos((R - r) / r * t) y = (R - r) * np.sin(t) - d * np.sin((R - r) / r * t) ax = axes[i, j] ax.plot(x, y) ax.set_title(f'r={r:.1f}, d={d:.1f}') ax.set_aspect('equal') ax.axis('off') plt.tight_layout(rect=[0, 0.03, 1, 0.95]) plt.show()
import matplotlib.pyplot as plt import numpy as np # パラメータ設定 R = 5 # スピログラフ用の大きな円の半径 r = 3 # スピログラフ用の小さな円の半径 d = 5 # トロコイド用の点の距離 A = 5 # リサージュ曲線の振幅 B = 4 a = 3 # リサージュ曲線のx軸方向の周波数 b = 2 # リサージュ曲線のy軸方向の周波数 delta = np.pi / 2 # リサージュ曲線の位相差 # tの範囲 t = np.linspace(0, 10 * np.pi, 1000) # スピログラフ(トロコイド)曲線 x_spiro = (R - r) * np.cos(t) + d * np.cos((R - r) / r * t) y_spiro = (R - r) * np.sin(t) - d * np.sin((R - r) / r * t) # リサージュ曲線 x_lissajous = A * np.sin(a * t + delta) y_lissajous = B * np.sin(b * t) # 組み合わせた曲線 x_combined = x_spiro + x_lissajous y_combined = y_spiro + y_lissajous # 描画 plt.figure(figsize=(8, 8)) plt.plot(x_combined, y_combined, label='Combined Curve') plt.title('Combined Curve of Spirograph, Lissajous, and Trochoid') plt.axis('equal') plt.axis('off') plt.show()
import matplotlib.pyplot as plt import numpy as np # パラメータ設定 R = 5 # スピログラフ用の大きな円の半径 r = 3 # スピログラフ用の小さな円の半径 d = 5 # トロコイド用の点の距離 A = 5 # リサージュ曲線の振幅 B = 4 a = 3 # リサージュ曲線のx軸方向の周波数 b = 2 # リサージュ曲線のy軸方向の周波数 delta = np.pi / 2 # リサージュ曲線の位相差 n = 36 # 円周上の個数 # tの範囲 t = np.linspace(0, 10 * np.pi, 1000) # スピログラフ(トロコイド)曲線 x_spiro = (R - r) * np.cos(t) + d * np.cos((R - r) / r * t) y_spiro = (R - r) * np.sin(t) - d * np.sin((R - r) / r * t) # リサージュ曲線 x_lissajous = A * np.sin(a * t + delta) y_lissajous = B * np.sin(b * t) # 組み合わせた曲線 x_combined = x_spiro + x_lissajous y_combined = y_spiro + y_lissajous # 円周上に配置するための角度 angles = np.linspace(0, 2 * np.pi, n, endpoint=False) # 描画 plt.figure(figsize=(8, 8)) for angle in angles: # 回転行列を適用 x_rotated = x_combined * np.cos(angle) - y_combined * np.sin(angle) y_rotated = x_combined * np.sin(angle) + y_combined * np.cos(angle) # 配置する中心を決定 center_x = 15 * np.cos(angle) center_y = 15 * np.sin(angle) plt.plot(x_rotated + center_x, y_rotated + center_y, label=f'Angle {angle:.2f} rad') plt.title(f'{n} Combined Curves on Circle') plt.axis('equal') plt.axis('off') plt.show()
曼荼羅
同心円状や同心方形状に
円や方形の図形を配置した図形のことです
import matplotlib.pyplot as plt import numpy as np # 円の数とそれぞれの半径 num_circles = 12 radii = np.linspace(0.1, 5, num_circles) # 角度の設定 angles = np.linspace(0, 2 * np.pi, 100) # 描画 plt.figure(figsize=(8, 8)) for radius in radii: for angle in np.linspace(0, 2 * np.pi, num_circles, endpoint=False): # 各円の中心 center_x = radius * np.cos(angle) center_y = radius * np.sin(angle) # 円を描画 x = center_x + radius * np.cos(angles) y = center_y + radius * np.sin(angles) plt.plot(x, y, color='purple') plt.title('Mandala Pattern') plt.axis('equal') plt.axis('off') plt.show()
import matplotlib.pyplot as plt import numpy as np # 円の数とそれぞれの半径 num_layers = 36 num_circles_per_layer = 12 radii = np.linspace(0.5, 5, num_layers) # 使用する色 colors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple'] # 描画 plt.figure(figsize=(8, 8)) for i, radius in enumerate(radii): for angle in np.linspace(0, 2 * np.pi, num_circles_per_layer, endpoint=False): # 各円の中心 center_x = radius * np.cos(angle) center_y = radius * np.sin(angle) # 円を描画 angles_circle = np.linspace(0, 2 * np.pi, 100) x = center_x + radius * 0.3 * np.cos(angles_circle) y = center_y + radius * 0.3 * np.sin(angles_circle) plt.plot(x, y, color=colors[i % len(colors)]) plt.title('Complex Mandala Pattern') plt.axis('equal') plt.axis('off') plt.show()
import matplotlib.pyplot as plt import numpy as np # 円の数とそれぞれの半径 num_layers = 24 num_circles_per_layer = 24 radii = np.linspace(0.5, 5, num_layers) # 使用する色 colors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple'] # 描画 plt.figure(figsize=(8, 8)) for i, radius in enumerate(radii): for angle in np.linspace(0, 2 * np.pi, num_circles_per_layer, endpoint=False): # 各円の中心 center_x = radius * np.cos(angle) center_y = radius * np.sin(angle) # 円を描画 angles_circle = np.linspace(0, 2 * np.pi, 100) size_variation = 0.2 + 0.1 * np.sin(angle * num_layers) # サイズに変化をつける x = center_x + radius * size_variation * np.cos(angles_circle) y = center_y + radius * size_variation * np.sin(angles_circle) # ランダムな線幅 # linewidth = np.random.uniform(0.5, 2.5) linewidth = 1 plt.plot(x, y, color=colors[i % len(colors)], linewidth=linewidth) plt.title('Complex Mandala Pattern with Variations') plt.axis('equal') plt.axis('off') plt.show()
こんな感じで、図形を組み合わせることで
様々な紋様を描く事ができます。
複雑な図形を組み合わせれば
それなりにアートっぽく
なって行くんではないでしょうか
気になった方はコピペして
色々パラメータ変えて
試してみてください
それでは。
コメントする