首頁 > 軟體

Matplotlib 3D 繪製小紅花原理

2022-02-16 13:00:56

 前言:

上篇博文中使用了matplotlib繪製了3D小紅花,本篇部落格主要介紹一下3D小紅花的繪製原理。

1. 極座標系

對於極座標系中的一點 P ,我們可以用極徑 r  和極角 θ 來表示,記為點 P ( r , θ ) ,

使用matplotlib繪製極座標系:

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    # 極徑
    r = np.arange(10)
    # 角度
    theta = 0.5 * np.pi * r

    fig = plt.figure()
    plt.polar(theta, r, c='r', marker='o', ms=3, ls='-', lw=1)
    # plt.savefig('img/polar1.png')
    plt.show()

使用matplotlib繪製極座標散點圖:

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    r = np.linspace(0, 10, num=10)
    theta = 2 * np.pi * r
    area = 3 * r ** 2

    ax = plt.subplot(111, projection='polar')
    ax.scatter(theta, r, c=theta, s=area, cmap='hsv', alpha=0.75)
    # plt.savefig('img/polar2.png')
    plt.show()

有關matplotlib極座標的引數更多介紹,可參閱官網手冊

2. 極座標系花瓣

繪製r = s i n ( θ ) r=sin(theta)r=sin(θ) 在極座標系下的影象:

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    fig = plt.figure()
    ax = plt.subplot(111, projection='polar')
    ax.set_rgrids(radii=np.linspace(-1, 1, num=5), labels='')

    theta = np.linspace(0, 2 * np.pi, num=200)
    r = np.sin(theta)
    ax.plot(theta, r)
    # plt.savefig('img/polar3.png')
    plt.show()

以 2 π 為一個週期,增加影象的旋轉週期:

r = np.sin(2 * theta)

繼續增加影象的旋轉週期:

r = np.sin(3 * theta)
r = np.sin(4 * theta)

然後我們可以通過調整極徑係數和角度係數來調整影象:

import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
    fig = plt.figure()
    ax = plt.subplot(111, projection='polar')
    ax.set_rgrids(radii=np.linspace(-1, 1, num=5), labels='')

    theta = np.linspace(0, 2 * np.pi, num=200)
    r1 = np.sin(4 * (theta + np.pi / 8))
    r2 = 0.5 * np.sin(5 * theta)
    r3 = 2 * np.sin(6 * (theta + np.pi / 12))

    ax.plot(theta, r1)
    ax.plot(theta, r2)
    ax.plot(theta, r3)
    # plt.savefig('img/polar4.png')
    plt.show()

3. 三維花瓣

現在可以將花瓣放置在三維空間上了,根據花瓣的生成規律,其花瓣外邊緣線在一條旋轉內縮的曲線上,這條曲線的極徑 r 隨著角度的增大逐漸變小,其高度 h  逐漸變大。

其函數影象如下:

這樣定義就滿足前面對花瓣外邊緣曲線的假設了,即 r 遞減, h 遞增。

現在將其放在三維空間中:

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


if __name__ == '__main__':
    fig = plt.figure()
    ax = Axes3D(fig)
    # plt.axis('off')

    x = np.linspace(0, 1, num=30)
    theta = np.linspace(0, 2 * np.pi, num=1200)
    theta = 30 * theta
    x, theta = np.meshgrid(x, theta)

    # f is a decreasing function of theta
    f = 0.5 * np.pi * np.exp(-theta / 50)

    r = x * np.sin(f)
    h = x * np.cos(f)

    # 極座標轉笛卡爾座標
    X = r * np.cos(theta)
    Y = r * np.sin(theta)
    ax = ax.plot_surface(X, Y, h,
                         rstride=1, cstride=1, cmap=plt.cm.cool)

    # plt.savefig('img/polar5.png')
    plt.show()

笛卡爾座標系(Cartesian coordinate system),即直角座標系。

然而,上述的表達仍然沒有得到花瓣的細節,因此我們需要在此基礎之上進行處理,以得到花瓣形狀。因此設計了一個花瓣函數:

其是一個以 2 π 為週期的周期函數,其值域為[ 0.5 , 1.0 ],影象如下圖所示:

再次繪製:

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


if __name__ == '__main__':
    fig = plt.figure()
    ax = Axes3D(fig)
    # plt.axis('off')

    x = np.linspace(0, 1, num=30)
    theta = np.linspace(0, 2 * np.pi, num=1200)
    theta = 30 * theta
    x, theta = np.meshgrid(x, theta)

    # f is a decreasing function of theta
    f = 0.5 * np.pi * np.exp(-theta / 50)

    # 通過改變函數週期來改變花瓣的形狀
    # 改變值域也可以改變花瓣形狀
    # u is a periodic function
    u = 1 - (1 - np.absolute(np.sin(3.3 * theta / 2))) / 2
    r = x * u * np.sin(f)
    h = x * u * np.cos(f)
    
    # 極座標轉笛卡爾座標
    X = r * np.cos(theta)
    Y = r * np.sin(theta)
    ax = ax.plot_surface(X, Y, h,
                         rstride=1, cstride=1, cmap=plt.cm.RdPu_r)

    # plt.savefig('img/polar6.png')
    plt.show()

4. 花瓣微調

  為了使花瓣更加真實,使花瓣的形態向下凹,因此需要對花瓣的形狀進行微調,這裡新增一個修正項和一個噪聲擾動,修正函數影象為:

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


if __name__ == '__main__':
    fig = plt.figure()
    ax = Axes3D(fig)
    # plt.axis('off')

    x = np.linspace(0, 1, num=30)
    theta = np.linspace(0, 2 * np.pi, num=1200)
    theta = 30 * theta
    x, theta = np.meshgrid(x, theta)

    # f is a decreasing function of theta
    f = 0.5 * np.pi * np.exp(-theta / 50)

    noise = np.sin(theta) / 30
    # u is a periodic function
    u = 1 - (1 - np.absolute(np.sin(3.3 * theta / 2))) / 2 + noise

    # y is a correction function
    y = 2 * (x ** 2 - x) ** 2 * np.sin(f)
    r = u * (x * np.sin(f) + y * np.cos(f))
    h = u * (x * np.cos(f) - y * np.sin(f))

    X = r * np.cos(theta)
    Y = r * np.sin(theta)
    ax = ax.plot_surface(X, Y, h,
                         rstride=1, cstride=1, cmap=plt.cm.RdPu_r)

    # plt.savefig('img/polar7.png')
    plt.show()

修正前後影象區別對比如下:

5. 結束語

3D花的繪製主要原理是極座標,通過正弦/餘弦函數進行旋轉變形構造,引數略微變化就會出現不同的花朵,有趣!

到此這篇關於Matplotlib 3D 繪製小紅花原理的文章就介紹到這了,更多相關Matplotlib 繪製小紅花內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com