對比python學julia(第二章)--(第三節)玫瑰曲線—數學之美
3.1.問題描述
在數學世界中有一些美麗的曲線圖形,有螺旋線、擺線、雙紐線、蔓葉線且、心臟線、漸開線、玫瑰曲線、蝴蝶曲線…… 這些形狀各異、簡有繁別的數學曲線圖形為看似枯燥的數學公式披上精彩紛呈的美麗衣裳。
在數學曲線的百花園中,玫瑰曲線算得上箇中翹楚,它的數學方程簡單,曲線變化眾多,根據引數的變化能展現出姿態萬千的優美形狀。玫瑰曲線可用極座標方程表示為
ρ=a∗sinθ 也可以用引數方方程表示為 其中,引數a控制葉子的長度;引數n控制葉子的數量,並影響曲線閉合週期。 當n為奇數時,玫瑰曲線的葉子數為n,閉合週期為 π,即引數 的取值範圍為0~π ,才能使玫瑰曲線閉合為完整形圖。當n為偶數時,玫瑰曲線的葉子數為2n,,閉合週期為 2π ,即引數 的取值範圍為0~2π,如圖所示,這是方程 ρ=a∗sinθ對應的三葉玫瑰曲線圖形。圖一、三葉玫瑰曲線
3.2.問題描述
在數學世界中,像玫瑰曲線這樣美麗的曲線圖形實際上是由簡單的函式關係生成的。通過利用曲線函式的引數方程,可以在平面直角座標系中方便地繪製出它們的圖形。
假如要利用玫瑰曲線的引數方程繪製三葉玫瑰曲線,則引數n的值可以設定為3,引數a的值可以設定葉子的長度(如 100)。因為引數 n=3 是奇數,所以三葉玫瑰曲線的閉合週期為π。 只要將引數 θ從0變化到 π,就能利用玫瑰曲線的引數方程求出平面內的一系列連續的點的座標(x,y),由此可構成三葉玫瑰曲線的圖形。
繪製玫瑰曲線的程式設計思路: 在一個迴圈結構中讓引數 θ從 0 變化到π,再利用玫瑰曲線的引數方程求出點座標x和y的值,並通過海龜繪相簿繪製一系列連續的點,最終繪製出一個完整的玫瑰曲線圖。
3.3.程式設計解題
根據上述演算法分析中給出的程式設計思路,程式設計繪製玫瑰曲線的圖形。這個案例需要用到海龜繪圖的知識.,請回顧上一節介紹的海龜繪圖方法。
首先我們來看Python的程式碼:
1 ''' 2 程式:繪製玫瑰曲線 3 作者:蘇秦@小海豚科學館公眾號 4 來源:圖書《Python趣味程式設計:從入門到人工智慧》 5 ''' 6 from turtle import * 7 from math import * 8 9 def draw(a, n, end): 10 '''繪製玫瑰曲線''' 11 t = 0 12 while t <= end: 13x = a * sin(n * t) * cos(t) 14 y = a * sin(n * t) * sin(t) 15 goto(x, y) 16 t = t + 0.01 17 18 if __name__ == '__main__': 19 '''三葉玫瑰''' 20 draw(100, 3, 3.14) 21 '''六葉玫瑰''' 22 #draw(100, 1.5, 12.56)
在上面的程式碼中可以看出,Python除了要匯入海龜繪相簿外,還要匯入數學庫,因為玫瑰曲線函式中涉及三角函式,需要用到 Python 內建的數學庫。
用於繪製玫瑰曲線的 draw()函式有3個引數,其中引數變數 a 表示葉子的長度,引數變數 n 表示葉子的數量,引數變數 end 表示曲線閉合週期。
在函式體中,通過 while 迴圈結構畫出一系列連續的點,迴圈變數為t,迴圈控制條件為 t <= end,即在從 0 到 end 的範圍內繪製一個閉合的玫瑰曲線。
在迴圈體中,使用玫瑰曲線的引數方程求出點座標 x 和 y 的值,再利用海龜繪相簿提供的 goto(x,y)函式定位畫筆就能繪製出相應的圖形。 為了繪製出平滑的曲線,迴圈變數t每次以0.01 的幅度增加。
上面程式碼中的main函式中“三頁玫瑰”的程式碼呼叫 draw()繪製出一個葉子長度為 100 的三葉玫瑰曲線。由於葉子數3是奇數,所以閉合週期為π ,這裡選取 3.14 即可。它繪出的圖形如下:
然而“六葉玫瑰”的引數n=1.5,end=12.56,這又是怎麼得來的呢?下面我們來討論玫瑰線引數的特性。
當在整數範圍內討論引數n時,玫瑰曲線的引數特性:若n為奇數,則玫瑰曲線n個葉子數,閉合週期為π,即θ取值為0~ π;若n為偶數,玫瑰曲線2n個葉子數,閉合週期為2π ,即θ取值為 0~2π。
當在有理數範圍內討論引數n時,可利用公式 確定玫瑰曲線的葉子數和閉合週期。n為非整數的有理數,L/W為簡約分數,引數L控制葉子數,引數W控制閉合週期。玫瑰曲線的引數特性:當引數L和W僅有一個是偶數時,則閉合週期為2Wπ,葉子數為2L;當引數L和W都是奇數時,則閉合週期為Wπ ,葉子數為L。
在下圖中展示的是玫瑰曲線 7 代圖譜,位於頂端的數字表示引數 L 的值,位於左端的數字表示引數W 的值,通過選擇 L 和W 的值,就能確定玫瑰曲線的圖形。
所以,當 L=3、W=2 時,則n=1.5,閉合週期為 2Wπ =12.56。 根據這兩個引數就可以繪製出六葉玫瑰曲線圖形。如下圖:
好了,我們已經知道了繪製玫瑰曲線的原理,轉換為Julia語言來實現相比也不困難。
當然還是要請出Julia的海龜繪相簿Luxor,在上一節中已有介紹。不過,筆者在Luxor中沒有找到類似Python海龜繪相簿turtle中的goto()函式,所以只能自主實現了自定義函式Goto()。
完整程式碼如下:
1 """ 2 程式:Julia繪製玫瑰曲線 3 Python原作者:蘇秦@小海豚科學館公眾號 4 來源:圖書《Python趣味程式設計:從入門到人工智慧》 5 """ 6 7 using Luxor 8 9 #實現海龜畫線,從原座標點到目標座標點 10 function Goto(t::Turtle,p::Point) 11 oldx, oldy = t.xpos, t.ypos 12 t.xpos=p.x 13 t.ypos=p.y 14 if t.pendown 15 gsave() 16 sethue(t.pencolor...) 17 line(Point(oldx, oldy), Point(t.xpos, t.ypos), :stroke) 18 grestore() 19 end 20 end 21 22 #繪製玫瑰曲線''' 23 function draw(t::Turtle,a, n, stop) 24 s = 0 25 while s <= stop 26 x = a * sin(n * s) * cos(s) 27 y = a * sin(n * s) * sin(s) 28 Goto(t,Point(x,y)) 29 s = s + 0.01 30 end 31 end 32 function main() 33 Drawing(300, 300, "mgqx.svg") 34 origin() 35 turtle=Turtle() 36 #三葉玫瑰曲線 37 draw(turtle,100, 3, 3.14) 38 finish() 39 end 40 main()
繪製的三葉玫瑰圖如下:
可以發現,上圖與Python繪製的三葉玫瑰曲線上下顛倒了,當然這關係不大,只能說明Luxor的海龜與Python的turtle移動方向是相反的。
- 擴充套件閱讀
在用海龜繪相簿實現繪製玫瑰曲線之後,我們並不打算就此停步。因為原書作者是用引數方方程作為程式設計的數學模型:
而我們打算迴歸玫瑰曲線的極座標方程:
ρ=a∗sinθ
而且,無論是Python還是Julia都有豐富的科學計算和資料視覺化繪相簿,相比於海龜繪相簿更加高效。因此我們用極座標方程作為數學模型,並採用其它視覺化庫來看看如何繪製玫瑰曲線。
經過這麼些年的發展,Julia的繪相簿也日漸豐富,比較常用的有Gadfly, Plots, PyPlot庫等,大家可以在下面的網址檢視這些庫的說明:https://juliapackages.com/c/graphics。
本文選用PyPlot.jl庫來實現繪製玫瑰曲線。PyPlot庫實際上是一個經典的Python繪相簿Matplotlib的一個模組,PyPlot.jl提供了一個介面用於呼叫Matplotlib.PyPlot模組,所以在使用它之前需要先安裝matplotlib:
方法一,使用pip安裝matplotlib
pip install matplotlib
方法二,使用pip安裝光速安裝matplotlib如果安裝太慢,可替換國內的下載源
pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple
然後我們用之前介紹的Julia的庫安裝方法來安裝PyPlot.jl庫,或者直接在Julia終端環境輸入using PyPlot,然後根據提示操作即可。
所謂玫瑰曲線就是在平面內,圍繞某一中心點平均分佈整數個正弦花瓣的曲線,在極座標下可表示為ρ=a*sin(nθ),a為定長,n為整數,來看完整程式碼:
1 using PyPlot 2 function draw() 3 theta=0:0.01:2*pi 4 #上面返回一個array物件,其元素從0-2*pi,步長0.01 5 subplot(111,polar=true) #設定為極座標模式 6 #6瓣花瓣 7 plot(theta,sin.(6*theta),linewidth=2.0, linestyle="-") 8 #5瓣花瓣 9 plot(theta,sin.(5*theta),linewidth=2.0, linestyle="--") 10 #4瓣花瓣 11 plot(theta,2*sin.(4*theta),linewidth=2) 12 rgrids((0.5:0.5:2),angle=45) #網格線 13 thetagrids([0,45,90])#角度值 14 show() 15 end 16 draw()
執行後,會開啟一個圖形視窗,顯示所畫的圖形:
怎麼樣,是不是很漂亮!