Kei Minagawa's Blog

皆川圭(@keimina)のブログ、Pythonで試したことを書いていきます

Pythonでドーナッツの形を描画する

いきなりですがPythonでドーナッツの形を描画します。まず、頭の中でその形をイメージします。次にそれを数式で表し、Python 3 で実装します。最後に描画されたものをみてみます。

1. 頭の中でドーナツの形をイメージする

ドーナッツの形をイメージします。以下のように円盤をz軸を中心にぐるぐる回転させると、その軌跡は、ドーナッツ形となるはずです。

f:id:keimina:20181218211055g:plain
回転する円盤

2. ドーナッツの形を数式で表す

ドーナッツの形を数式で表します。

以下のように、xz平面に円を定義します。媒介変数として、 u を用いると以下のように書けると思います。

f:id:keimina:20181218212123p:plain
xz平面の円の数式

※ u は角度、x1 と z1 は座標で定数だと思ってください。円盤の半径は1とします。

この円盤を z軸 を中心に回転させます。アファイン変換*1を使うと円盤を回転させることができます。具体的には、以下の回転行列*2を上記 x, y, z の数式に作用させることになります。今回はこれを使ってやってみましょう。

回転する角度を v とすると、回転行列は以下になります。

f:id:keimina:20181218211850p:plain
回転行列

この回転行列を 先ほど定義した xz平面の円上の点 x, y, z に作用させます。回転後の円上の点を x’, y’, z’ とすると、それらの数式は以下のようになります。

f:id:keimina:20181218212618j:plain
回転後の数式

無事に、回転後の数式を変数 u, v で表すことができました。
これは u, v の2次元ですので、平面(ドーナッツの表面)を表す関数だということがわかります。
ドーナッツの形をみるのには、表面の情報があれば十分なため、この数式で十分です。

回転後の数式が求まりましたので、次は実装を行います。

3. Pythonとmatplotlibで実装する。

2.で求めたドーナッツの形を表す数式をPythonで実装しmatplotlibで描画します。
ドーナッツの形は前述の通り、 u と v で表すことができるので、この u と v を少しづつ変化させて描画すればドーナッツの形になると思われます。
注意すべき点は、描画をおこなうグラフの軸のアスペクト比率を同じにすることです。
そうしないと、目盛は正しいのだけど見た目上わかりづらいグラフになってしまいます.

コード:

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

N_us = 20
N_vs = 40

us = np.linspace(0, 2*np.pi, N_us)
vs = np.linspace(0, 2*np.pi, N_vs)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

x1 = 2
z1 = 0

for v in vs:
    x = np.cos(v)*(x1 + np.cos(us))
    y = np.sin(v)*(x1 + np.cos(us))
    z = z1 + np.sin(us)
    ax.scatter(x, y, z)

ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)
ax.set_zlim(-2, 2)
ax.set_aspect('equal')
plt.axis('off')

plt.show()

4. 描画されたものをみてみる

最後に描画されたものを見てみます。

f:id:keimina:20181218213219g:plain
ドーナッツ形の出力結果

カラフルなドーナッツが表示されました。
以上です。

*1:ここでは、点を別の点に移動させるくらいの意味で使ってます。

*2: https://ja.m.wikipedia.org/wiki/回転行列