Doing Math with Python讀書筆記-第2章:Visualizing Data with Graphs

本章我們會使用繪圖包matplotlib,因此先安裝:

$ pip3 install --user matplotlib 
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Collecting matplotlib
  Downloading matplotlib-3.1.3-cp38-cp38-manylinux1_x86_64.whl (13.1 MB)
     |████████████████████████████████| 13.1 MB 4.5 kB/s 
Collecting numpy>=1.11
  Downloading numpy-1.18.1-cp38-cp38-manylinux1_x86_64.whl (20.6 MB)
     |████████████████████████████████| 20.6 MB 12 kB/s 
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1
  Using cached pyparsing-2.4.6-py2.py3-none-any.whl (67 kB)
Collecting cycler>=0.10
  Using cached cycler-0.10.0-py2.py3-none-any.whl (6.5 kB)
Collecting kiwisolver>=1.0.1
  Downloading kiwisolver-1.1.0-cp38-cp38-manylinux1_x86_64.whl (91 kB)
     |████████████████████████████████| 91 kB 10 kB/s 
Collecting python-dateutil>=2.1
  Using cached python_dateutil-2.8.1-py2.py3-none-any.whl (227 kB)
Requirement already satisfied: six in /home/xiaoyu/.local/lib/python3.8/site-packages (from cycler>=0.10->matplotlib) (1.14.0)
Requirement already satisfied: setuptools in /usr/local/lib/python3.8/site-packages (from kiwisolver>=1.0.1->matplotlib) (41.2.0)
Installing collected packages: numpy, pyparsing, cycler, kiwisolver, python-dateutil, matplotlib
Successfully installed cycler-0.10.0 kiwisolver-1.1.0 matplotlib-3.1.3 numpy-1.18.1 pyparsing-2.4.6 python-dateutil-2.8.1

瞭解笛卡爾座標平面

橫軸x,縱軸y。座標(x,y),原點爲(0,0)

LIST 和 TUPLE

list和tuple是存儲一組值(不僅僅是數值)的兩種方法。區別是list可以修改,tuple不行。
因此如果你一開始就可以確定這些數值,就用tuple,否則用list。
使用這兩種方法的好處是不必爲每一個數值賦予變量名,只需要用數字索引就可以引用它們。

>>> list1 = [1, 2, 3, 4]
>>> list1[0]
1
>>> tuple1 = (1, 2, 3, 4)
>>> tuple1[0]
1

list後續可以增刪成員:

>>> emptylist = []
>>> emptylist.append(1)
>>> emptylist.append(2)
>>> emptylist
[1, 2]
>>> del(emptylist[0])
>>> emptylist
[2]

索引可以爲負數,表示倒數:

>>> list1[-1]
4
>>> list1[-2]
3

遍歷

>>> for i in list1:
...     print(i)
... 
1
2
3
4

enumerate在遍歷的同時可以返回索引值:

>>> for idx, n in enumerate(list1):
...     print(idx, n)
... 
0 1
1 2
2 3
3 4

用MATPLOTLIB繪圖

matplotlib是一個package,包含很多module。

>>> x = [1, 2, 3]
>>> y = [2, 4, 6]
>>> from pylab import plot, show	# pylab是matplotlib的一部分
>>> plot(x, y)
[<matplotlib.lines.Line2D object at 0x7fb5d6d378b0>]
>>> show()	# 顯示圖形,程序阻塞直到你關閉圖形。

從圖形中可看到,左下角的座標並非(0, 0),而是兩個list中的最小值(1, 2),而右上角則是兩個list中的最大值(3, 6)
<插入圖片>

畫點

>>> plot(x, y, marker='o')	# 標記可以是'o', '*', 'x', 和 '+'。
>>> show()	# 三個點會用'o'標記,並被連接

>>> plot(x, y, 'o')
>>> show()	# 僅顯示三個點,沒有線連接

繪製紐約年度平均溫度
2000-2012年,每年一個值。

>>> nyc_temp = [53.9, 56.3, 56.4, 53.4, 54.5, 55.8, 56.8, 55.0, 55.3, 54.0, 56.7, 56.4, 57.3]
>>> plot(nyc_temp, marker='o')	# 由於x軸可以不指定,因此這裏的nyc_temp表示y軸
# 如果希望上面的點表示x軸,可以plot(nyc_temp, [0]*13, marker='o')
>>> show()

在這裏插入圖片描述
上圖有幾點注意,這些都可以調整:

  • 溫差不大,但圖形顯示差距很大,這是由於y軸的最小和最大值和溫度數據關聯
  • x軸整數,y軸是浮點數

將橫座標設置爲年度:

>>> years = range(2000, 2013)
>>> plot(years, nyc_temp, marker='o')
[<matplotlib.lines.Line2D object at 0x7fb5d6468a30>]
>>> show()

比較紐約的月度溫度趨勢
選取了3年,每年12個月。運行以下代碼:

nyc_temp_2000 = [31.3, 37.3, 47.2, 51.0, 63.5, 71.3, 72.3, 72.7, 66.0, 57.0, 45.3, 31.1]
nyc_temp_2006 = [40.9, 35.7, 43.1, 55.7, 63.1, 71.0, 77.9, 75.8, 66.6, 56.2, 51.9, 43.6]
nyc_temp_2012 = [37.3, 40.9, 50.9, 54.8, 65.1, 71.0, 78.8, 76.7, 68.8, 58.0, 43.9, 41.5]
months = range(1, 13)
# 以下的plot等同於plot(months, nyc_temp_2000)加上plot(months, nyc_temp_2006), 加上plot(months, nyc_temp_2012),一次性返回3個matplotlib.lines.Line2D對象
plot(months, nyc_temp_2000, months, nyc_temp_2006, months, nyc_temp_2012)
from pylab import legend	# 用於加圖例,可選。默認位置在右上,可設置。
legend([2000, 2006, 2012])	# 順序和3個plot對象對應

在這裏插入圖片描述
定製圖表
前面談到的加圖例是定製的一種。
加標題和標籤

>>> from pylab import plot, show, title, xlabel, ylabel, legend
>>> title('Average monthly temperature in NYC')
Text(0.5, 1.0, 'Average monthly temperature in NYC')
>>> xlabel('Month')
Text(0.5, 0, 'Month')
>>> ylabel('Temperature')
Text(0, 0.5, 'Temperature')

定製座標軸
回顧之前紐約年度平均氣溫的例子,溫度相差不大,但圖形顯示上差別很大。這可以通過設置橫縱座標的起始值調整:

>>> from pylab import plot, show
>>> nyc_temp = [53.9, 56.3, 56.4, 53.4, 54.5, 55.8, 56.8, 55.0, 55.3, 54.0, 56.7, 56.4, 57.3]
>>> plot(nyc_temp, marker='o')
[<matplotlib.lines.Line2D object at 0x7fe691f5fa60>]
>>> from pylab import axis
>>> axis()	返回的tuple(xmin, xmax, ymin, ymax)
(-0.6000000000000001, 12.6, 53.205, 57.495)
>>> axis(ymin=0)
(-0.6000000000000001, 12.6, 0, 57.495)

使用pyplot繪圖
以上我們都是用pylab繪圖,這在IDLE或交互式shell中是合適的,但對於大型程序,建議用pyplot。
用戶和pylab類似,例如:

import matplotlib.pyplot	# 引入整個pyplot模塊
x_numbers = [1, 2, 3]
y_numbers = [2, 4, 6]
matplotlib.pyplot.plot(x_numbers, y_numbers)
matplotlib.pyplot.show()

簡介的寫法可以爲引入的模塊加別名,例如:

import matplotlib.pyplot as plt
...
plt.plot(x_numbers, y_numbers)
plt.show()

保存繪圖
在顯示的圖表上有保存按鈕。
無論是pylab還是pyplot,都可以用savefig(filename),可以保存爲PDF,PNG和SVG格式。

通過公式繪圖

牛頓萬有引力定律(Newton’s Law of Universal Gravitation)
如下,m1m_{1}m1m_{1}表示兩個物體的質量,r表示兩個物體的距離,G是重力常數:
F=Gm1m2r2F=\frac{Gm_{1}m_{2}}{r^2}
這裏假定m1m_{1}m1m_{1}分佈爲0.5和1.5公斤,需繪製F和r的關係。
代碼如下:

import matplotlib.pyplot as plt
m1 = 0.5; m2 = 1.5; G = 6.674*(10**-11)
r = range(100, 1001, 50)
F = []
for dist in r:
	force = G*(m1*m2)/(dist**2)
	F.append(force)

plt.plot(r, F, marker='o')
plt.xlabel('Distance in meters')
plt.ylabel('Gravitational force in newtons')
plt.title('Gravitational force and distance')
plt.show()

輸出如下:
在這裏插入圖片描述
拋體運動(Projectile Motion)
若初始速度爲μ\mu,投射角度爲θ\theta,則:
μx=μcosθ\mu_{x}=\mu * cos\theta
μy=μsinθ\mu_{y}=\mu *sin\theta
公式的推演暫不贅述。Latex數學公式的語法見這裏

這一段程序需要了解的幾點。

  1. 模擬range()編寫了frange()函數提供浮點數的列表
  2. 利用了math庫中radians()和sin()和cos()函數

以下複習下數學。
radians是將角度轉換爲弧度,記住2π=36002\pi=360^0就好。

>>> import math
>>> math.radians(45)
0.7853981633974483
>>> math.radians(180)
3.141592653589793

cos和sin的原理:
在這裏插入圖片描述
三角函數表見這裏

>>> math.cos(math.radians(90))
6.123233995736766e-17
>>> math.sin(math.radians(90))
1.0
>>> math.sin(math.radians(45))
0.7071067811865475
>>> 2**(1/2)/2
0.7071067811865476
>>> math.cos(0)
1.0

編程挑戰

條形圖
這一部分講述瞭如何使用pyplot.barh()做條形圖(Bar Chart):

>>> import matplotlib.pyplot as plt
>>> labels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
>>> steps = [6534, 7000, 8900, 10786, 3467, 11045, 5095]
>>> positions = range(1, len(steps)+1)
>>> plt.barh(positions, steps, align='center')
<BarContainer object of 7 artists>
>>> plt.yticks(positions, labels)
([<matplotlib.axis.YTick object at 0x7f43a1c14c70>, <matplotlib.axis.YTick object at 0x7f43a1c14850>, <matplotlib.axis.YTick object at 0x7f43a48c4f70>, <matplotlib.axis.YTick object at 0x7f43a1bf10a0>, <matplotlib.axis.YTick object at 0x7f43a1bf1640>, <matplotlib.axis.YTick object at 0x7f43a1bf1be0>, <matplotlib.axis.YTick object at 0x7f43a1bf61c0>], <a list of 7 Text yticklabel objects>)
>>> plt.xlabel('Steps')
Text(0.5, 0, 'Steps')
>>> plt.ylabel('Day')
Text(0, 0.5, 'Day')
>>> plt.title('Number of steps walked')
Text(0.5, 1.0, 'Number of steps walked')
>>> plt.grid()
>>> plt.show()

輸出爲:
在這裏插入圖片描述
Fibonacci序列黃金比例
我實現的代碼如下:

def fibo(n):
    f = [1, 2]
    if n <= 2:
        return f[:n]

    for i in range(2, n):
        f.append(f[i-2] + f[i-1])

    return f

def gold_ratio(f):
    r = []
    size = len(f)
    if size >= 2:
        for i in range(2, size + 1):
            r.append(f[i-1]/f[i-2])

    return r


import matplotlib.pyplot as plt
items=50
plt.title('Golden Ratio for Fibonacci Sequence')
plt.xlabel('n')
plt.ylabel('ratio')
plt.plot(gold_ratio(fibo(items)))
plt.show()

輸出如下,當n增加時,比例趨近黃金比例1.618:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章