從零開始學習PYTHON3講義(十二)畫一顆心送給你


(內容需要,本講使用了大量在線公式,如果因為轉帖網站不支持公式無法顯示的情況,歡迎訪問原始博客。)

《從零開始PYTHON3》第十二講

上一節課我們主要講解了數值計算和符號計算。數值計算的結果,很常用的目的之一就是用於繪制圖像,從圖像中尋找公式的更多內在規律。

Python科學繪圖

科學繪圖是計算機圖形學的一個重要分支。同其它繪圖方式相比,更簡單易用,能讓使用者把工作的主要精力集注在公式和算法上而不是繪圖本身。此外科學繪圖的工具包普遍精度更高,數據、圖的對應關系准確,從而保證基於圖的研究工作順利進行。最后,科技繪圖一般都使用同數學相同的坐標系,避免了不必要的數據轉換。

常用的一個高質量科學繪圖包是第三方出品的MatplotLib,安裝方式跟其它擴展庫相同(這里只示例基於Windows環境的安裝):

#首先使用管理員模式執行cmd命令行,隨后在命令行執行:
pip install matplotlib  #某些系統需要使用pip3

所有的繪圖,無論是基於顯示器還是打印機(繪圖儀),都可以看做一個寬*高的二維矩陣。這就產生了一個坐標系統,那么矩陣中的任意一個點,就會有坐標(x,y),x代表橫方向坐標,y軸代表縱向坐標。
三維的游戲、VR等應用,在計算的整個過程中使用的是x、y、z三維坐標體系,但最后繪制到屏幕上的時候,還是會根據透視縮放的映射關系,將圖像投影到二維矩陣中。
那么一副圖像,就是有很多個點組成的,每個點都有其x,y的坐標。如果組成一個列表,通常是[[x1,y1],[x2,y2],[x3,y3]]這樣的形式,比如剛才這個例子就代表了3個點的列表。如果是一條線,則可以用[[x1,y1],[x2,y2]]兩個點來描述,這兩個點就是一條線的兩個端點坐標。
在我們今天講的數學繪圖中,通常使用的是另外一種坐標表示方法。科學繪圖會使用x坐標點的列表和y坐標點的列表,兩個列表來描述一組點。比如:[x1,x2,x3],[y1,y2,y3]。
即便只有一個點,也要把x坐標和y坐標分開到兩個列表中去,此時列表就成為只有一個元素的列表,[x],[y]。

使用這種數據結構的原因是這樣的,比如我們試圖繪制函數:

\[y = f(x) \]

的圖像。通常的情況我們首先是有一列的x值,那么通過函數計算之后,組成的就是一個結果y的列表。
因此事實上,為函數繪制圖像,我們不大可能跟傳統圖像一樣,上來就有一個完整的坐標點列表,而只能是x、y兩個列表。列表中相同下標的值,是對應的x、y坐標,而y坐標的值,來自於上面所示函數對於x列表的計算結果。以一個3坐標的列表為例,大致是[x1,x2,x3],[y1,y2,y3]這樣的形式。

言語總是枯燥無味的,讓我們來看一段代碼,用於繪制一副正弦函數圖:

#繪制正弦曲線

#引入數值計算庫,改為短名稱
import numpy as np
#引入繪圖庫,改為短名稱
import matplotlib.pyplot as plt

#生成一個由-4到4、均分為200個元素的列表
x = np.linspace(-4, 4, 200) 
#計算當x取值范圍-4至4時所有的sin函數解
f = np.sin(x)

#繪制
plt.plot(x, f, 'red') 

#將繪制好的圖顯示出來
plt.show()

有幾條命令再更詳細的解釋一下:

  • np.linspace函數我們在講數值計算的時候學過,是生成一個200個元素的列表,這個列表是numpy庫的列表類型,跟python內置的列表是基本兼容的,但並不是同一種類型。這200個元素均分了從-4到+4的值范圍,包含了-4/+4本身。
  • np.sin(x),看起來跟內置的math.sin(x)很像,事實上當x是一個數字變量的時候,兩者完全相同。但在這里,x是一個列表,包含200個元素。那兩者就完全不同了。內置的math.sin一次調用只能處理一個數字。np.sin是一次處理整個數組。因此調用完成后,結果f中是包含了200個值,每個相同下標的值,是對應x列表中對應下標值的正弦函數結果值。所以f在這里實際就是y坐標的值。
  • 終於看到了plt.plot函數,里面有三個參數,x是x坐標列表,本例中包含了200個元素,f實際是y軸坐標列表,也包含了200個元素,最后的'red'表示使用紅色繪制。此函數在繪制這個數組的時候,每兩個點之間,默認會使用直線連接上,從而讓整體上形成一條平滑的曲線。
  • 最后plt.show()是把繪制好的圖形顯示出來,此語句之后的繪圖將被忽略掉,所以請確保這一條語句是所有plt調用的最后一句。

繪制的結果請看下圖。

Figure_1
干凈漂亮的正弦曲線出現了!

Python的學習一定要多動手練習,所以請自己也來來試試繪制過程。比如改變參數范圍從-10到+10,比如把200個列表元素改成只有10個,看看是什么效果?

我們繼續為這個畫面做一些輔助性的補充。請把下面的代碼加到plt.show()語句之前:

#為某條曲線增加注釋文字
plt.text(1.3, 0.9, 'sin(x)',color='b')

#為整個圖增加標題
plt.title('y=f(x)', fontsize=16)

只加了兩行代碼。第一行代碼是在畫面中增加注釋性的文字,其實只有一條曲線意義並不大。但多條曲線,如果沒有注釋的文字,看起來就很困難了。第一行代碼里面,頭兩個參數是坐標,表示注釋文字出現的起始位置,這個坐標的單位就是正弦曲線的數學值,這一點,在其它繪圖系統中都是要做很復雜的變換才能搞的定,在這里直接用就好了;第三個參數是顯示的文字;第四個參數“b”代表blue,意思是用藍色顯示注釋文字,這是想告訴你,其實前面的“red”,一樣可以簡寫成“r”。
第二行代碼視為整個畫面增加一個標題,標題會顯示在圖片的上方中間的位置,第二個參數給了個字體尺寸,其實第二個參數可以沒有,那樣的話會自動給出一個適合標題的尺寸,一般都適於大多數情況使用。
有一點需要注意,畫面中的注釋文字,和標題,都不能直接支持中文。通常國外的軟件,或多或少支持其它語言文字都有小問題。解決也並不難,就是需要指定使用中文的字體,這個超出了本課程的范圍,有興趣了解的可以參考教學資源包中的demo.py程序,注意字體的設置,是跟操作系統相關的,不具備可移植性。
Figure_2
上圖是增加了注釋文字和標題之后的效果。你可能注意到了,圖片窗口中有菜單是可以直接保存圖片的。這樣的圖片直接引用到論文中效果一流。

科學繪圖庫我們使用了已經內置的正弦函數作為示例開始,這樣為了降低使用的難度,專注解釋繪圖操作的機理。

在實際應用中,要繪制的通常都是很復雜的數學公式,這時候前面講過的數學內容就用得上了。建議你自己定義一個函數,把復雜的公式,使用Python描述出來。注意因為要繪圖,所以通常都是需要使用數值計算庫而不是符號計算庫。
下面我們舉一個例子,簡單起見,我們只使用最簡單的直線公式(僅為示例,單純畫直線有很多更好的辦法):

\[y=ax+b \]

#繪制直線

#引入數值計算庫
import numpy as np
#引入繪圖庫
import matplotlib.pyplot as plt

#定義一個直線函數
def line(x,a,b):
    return a*x+b

#我們用於示例,定義的函數沒有計算數組的功能
x1=-4
y1=line(x1,0.2,0)
x2=4
y2=line(x2,0.2,0)

#繪制直線,只需要兩個端點
plt.plot([x1,x2],[y1,y2],'r')

#增加注釋文字
plt.text(-3.9, -0.8, '0.2*x',color='r')
#為整個圖增加標題
plt.title('y=ax+b', fontsize=16)

#將繪制好的圖顯示出來
plt.show()

整體的程序結構跟上面畫正弦函數的幾乎相同。區別有兩點,1是使用自定義的函數替代np.sin函數;2是計算的時候,因為我們自己定義的函數不支持數組運算,所以自己要逐次計算每個點。好在是直線,只要計算兩個點就成了。
此外有一點要說明的,我們前面其實提到過,plt.plot函數,會自動連接每個點,使得整體成為連貫的線條,所以這個繪圖示例的結果,我們給出兩個點,最終得到了一條線。下面是運行結果:
Figure_3
一個小思考題,排除這個直線函數。如果我們自己定義的函數式曲線,那肯定還是需要自己定義的Python函數,除了實現函數的計算,還要能實現數組的計算比較合理,這應當如何做呢?最好能用自己定義的函數來說明一下,或者用偽代碼來描述一下也可以接受。
科技繪圖部分的最后,推薦去官方網站看一看經典的“繪圖畫廊”,都是使用MatplotLab繪制的,都附有源代碼,而且程序還都不算長,相信會讓你很有收獲。多說一句,Python的內置函數和第三方函數總量浩如煙海,你看別人程序的時候肯定會碰到很多不理解的函數或者關鍵字,基本的語法我們都已經學過了,這些不明白的內容求助搜索引擎,一定能讓你快速的找到答案。


海龜繪圖

今天一開始講的科學繪圖工具包非常強大。Python也內置了一套簡單易用的繪圖包,名字是海龜繪圖,庫名為:turtle,內置庫無需安裝,直接在程序一開始引用就可以了。

海龜繪圖是在上世紀90年代非常流行的一套兒童繪圖工具包,曾經風靡一時,但可惜在當今各種高級工具層出不窮的情況下,已經比較沒落了。
但我的感覺是對於初學者,還是有很多參考意義,所以下面的內容,着重了解和動手嘗試,對於具體的內容,有興趣當然可以學習,興趣不足的,練練手就好了,不要求你重點記憶。

海龜繪圖的基本理念是這樣:想象沙灘上有只小海龜。它只會向前走、轉向等簡單的動作,它在沙灘上爬行所留下的軌跡就是繪制出的圖形(其實繪圖命令中還有抬起畫筆、放下畫筆等操作,有興趣的使用help(turtle)可以查看完整幫助)。
這種模式很適合使用循環語句繪制螺旋線等規律幾何結構,如果設計得當,可以得到很多炫目的幾何圖形。我們來看幾個例子:

#海龜繪圖演示

#引入海龜繪圖庫
import turtle

#建立一支筆(一只海龜)
t = turtle.Pen()
for x in range(100):
    #向前走x步
    t.forward(x)
    #左轉90度
    t.left(90)
turtle.done()

上面就是在第一講中我們介紹過的圖形,繪制結果為:
turtle1

換一個算法再看看:

#海龜繪圖演示

#引入海龜繪圖庫
import turtle

#建立一支筆(一只海龜)
t = turtle.Pen()
t.pencolor('red')
for x in range(100):
    #向前走x步
    t.forward(x)
    #左轉90度
    t.left(95)
turtle.done()

注意這個程序中有了設置畫筆顏色的語句。下面是繪制結果:
turtle2
除了設置畫筆的顏色,還可以設置畫筆所封閉的區域中的填充顏色,請看這個例子和執行的結果:

#引入繪圖庫
from turtle import *

#設置筆的顏色和填充顏色
color('red', 'yellow')
#開始填充
begin_fill()
while True:
    forward(200)
    left(170)
    #pos是當前海龜坐標
    #abs(pos())表示判斷如果
    # 海龜回到原點附近則停止
    if abs(pos()) < 1:
        break
#結束填充
end_fill()
done()

turtle3

這些例子中,基本都使用了循環結構,希望你還記得循環的語法、邊界條件、循環體這些概念,並以此讀懂這些例子的原理。

在上面最后的例子中,有一些需要補充的。pos()返回當前小海龜的位置(x,y),是以數學復數的方式返回的。復數不在我們學習計划內,所以這部分內容了解即可,大致原理:abs(pos())實際是計算sqrt(x * 2+y * 2),也既當前坐標到原點的直線距離。所以上面例子中,使用這個方法來判斷小海龜畫筆,回到了原點附近,表示整個曲線繪制完整、並且頭尾連貫、閉合了。因為只有閉合的區域,才可能填充顏色。

本節課總體上都是很輕松愉悅的。相信你經過前面艱苦的學習,已經嘗到了收獲的滋味,我們也到了收獲的季節。娛樂起見,我們再提供一個網上轉帖的海龜繪圖程序,用於繪制小豬佩奇(程序比較長,請直接參考paige.py,此處感謝原作者):
turtle4

小豬佩奇的程序中,使用了很多海龜繪圖的縮寫功能,比如forward向前走命令可以縮寫為fd,向左轉命令left可以縮寫為lt。這些在help(turtle)文檔中都能查到。縮寫只是為了編寫程序時候的方便,功能是完全一樣的。

除了前面講過的規則幾何圖案,想繪制這種定制的圖形,通常都需要使用“坐標紙”,現在除了上淘寶,估計平常的商店都買不到了。然后把想繪制的圖形描繪在坐標紙上,從而獲得每個點的准確坐標。接下來就可以利用這些坐標,利用抬筆、移動坐標、落筆的功能,繪制定制的圖形了。
不過可惜啊,現在有了Photoshop之類的軟件,像坐標紙描格子的過程,都足以在屏幕上繪制完成了,完全不需要編程的知識。這也是海龜繪圖逐漸沒落的原因。


練習時間

1.請繪制下面函數的圖像:

\[y=\sqrt{1-(|x|-1)^2},\arccos(1-|x|)-\pi \]

這里解釋一下:

  • y是兩個公式,用逗號隔開,表示取值是兩個,程序中應當分別計算,得到兩組值
  • x取值空間建議:-2至2
  • 根號函數:numpy.sqrt(),絕對值:numpy.fabs()
  • 平方:numpy.square(),同**2的區別,后者只計算一個值,前者計算整個列表
  • 其它函數:numpy.arccos,常量π:numpy.pi

2.海龜繪圖的練習,其實在第一講的時候我們練習過一些了,現在學習了這么多,再來試試吧
A.修改前面例程的簡單參數,構建有趣的規則幾何圖形
B.開動腦筋,重新編程,繪制一副更有創意的圖形


本講小結

  • 圖形、圖像是計算機科學中重要的組成部分
  • 科技繪圖用途廣泛,也是理工學習中必須用到的內容
  • 海龜繪圖簡單有趣,能顯示繪圖過程,適合簡單創意性的場合

練習答案

1.課程中的思考題,在自定義函數中,應當使用循環,遍歷參數的所有元素,逐個代入數學公式中計算,得到的結果逐個加入已經預先定義好的空列表中,最終返回這個完整的列表。程序代碼略。

2.請參考ex1.py程序

3.海龜繪圖練習略


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM