本人pygal庫的安裝使用了 pip3 install pygal 安裝成功,使用 conda install pygal 提示沒有這個庫,我在學習過程中安裝別的庫的時候也有出現這種情況,所以使用Anaconda 的用戶如果安裝不上某個庫時,建議使用 pip 安裝,而且這兩種安裝是並不沖突的。
原文的摘錄如下:
本章我們將使用 Python 可視化包 Pygal 來生成可縮放的矢量圖形文件。對於需要在尺寸不同的屏幕上顯示的圖表,這很有用,因為它們將自動縮放,以適合觀看者的屏幕。
如果你打算以在線方式使用圖表,請考慮使用 Pygal 來生成它們,這樣它們在任何設備上顯示時都會很美觀。
代碼摘錄如下,略有改動便於學習記錄,日后查看:

1 from random import randint 2 3 # 創建Die類 4 class Die(): 5 # 表示一個骰子的類 6 def __init__(self, num_sides = 6): 7 # 骰子默認為6面 8 self.num_sides = num_sides 9 10 def roll(self): 11 # 返回一個位於1和骰子面數之間的隨機值 12 return randint(1, self.num_sides)

1 # 擲骰子 2 from die import Die 3 4 # 創建一個D6 5 die = Die() 6 7 # 擲幾次骰子,並將結果存儲在一個列表中 8 results = [] 9 10 # 擲骰子100次 11 for roll_num in range(100): 12 result = die.roll() 13 results.append(result) 14 15 print(results)

1 # 擲骰子 2 from die import Die 3 4 # 創建一個D6 5 die = Die() 6 7 # 擲幾次骰子,並將結果存儲在一個列表中 8 results = [] 9 10 # 擲骰子1000次 11 for roll_num in range(1000): 12 result = die.roll() 13 results.append(result) 14 # 分析結果 15 frequencies = [] 16 for value in range(1, die.num_sides+1): 17 frequency = results.count(value) 18 frequencies.append(frequency) 19 20 print(frequencies)

1 import pygal 2 from die import Die 3 4 # 創建一個D6 5 die = Die() 6 7 # 擲幾次骰子,並將結果存儲在一個列表中 8 results = [] 9 10 # 擲骰子1000次 11 for roll_num in range(1000): 12 result = die.roll() 13 results.append(result) 14 15 # 分析結果 16 frequencies = [] 17 for value in range(1, die.num_sides+1): 18 frequency = results.count(value) 19 frequencies.append(frequency) 20 21 # 對結果進行可視化 22 # pygal.Bar() 實例 用於創建條形圖,存儲到hist中 23 hist = pygal.Bar() 24 25 hist.title = 'Results of rolling one D6 1000 times.' 26 hist.x_labels = ['1', '2', '3', '4', '5', '6'] 27 hist.x_title = 'Result' 28 hist.y_title = 'Frequency of Result' 29 30 # add傳遞到圖標,這種文件的擴展名必須為.svg 31 hist.add('D6', frequencies) 32 hist.render_to_file('die_visual.svg') 33 34 # 使用瀏覽器打開這個圖表
個人提示:不要用系統自帶的圖像查看器查看,你很有可能看到的是一堆黑的,SVG文件用瀏覽器打開能夠看到如圖的效果,並且將鼠標放置在直方圖上時會顯示出,該點數一共擲到了幾次,實現與用戶之間的一個簡單交互,我想你可能會與我一樣對此感興趣,接下來和隨機漫步一樣,會進行多次操作,對這個有趣的小東西進行升級。
投擲兩個骰子的代碼如下:

1 import pygal 2 3 from die import Die 4 5 # 創建兩個D6骰子 6 die_1 = Die() 7 die_2 = Die() 8 9 # 擲1000次骰子,並將結果存儲在一個列表中 10 results = [] 11 for roll_num in range(1000): 12 result = die_1.roll() + die_2.roll() 13 results.append(result) 14 15 # 分析結果 16 frequencies = [] 17 max_result = die_1.num_sides + die_2.num_sides 18 for value in range(2, max_result+1): 19 frequency = results.count(value) 20 frequencies.append(frequency) 21 22 # 對結果進行可視化 23 hist = pygal.Bar() 24 25 hist.title = 'Results of rolling two D6 1000 times.' 26 hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', 27 '9', '10', '11', '12'] 28 hist.x_title = 'Result' 29 hist.y_title = 'Frequency of Result' 30 31 # add傳遞到圖標,這種文件的擴展名必須為.svg 32 hist.add('D6 + D6', frequencies) 33 hist.render_to_file('dice_visual.svg')
這些圖片不是我給它更改了大小,而是pygal可以根據窗口自動調節尺寸的,這也是它神奇的一個地方,我使用的瀏覽器是 Ubuntu 中的 Chromium 瀏覽器,無論我怎么縮放,瀏覽器中的圖片都保持尺寸不變。
而且我們還發現了什么?正如我們想的一樣,同時擲兩顆骰子,擲出2點和12點的概率是最小的,因為只有兩個都是1或者6時才能夠出現。關於這些概率問題,通過修改書本中所提供的代碼,我們是不是可以把現實中的例子放入進來,做一個概率分析呢?
下面是書籍中所提到的練習,如果我已經寫出了這個代碼,則會在下面貼出來,如果還沒能寫出來的,作業就暫時留着,等我學得更好了再回頭來做這些我現在所不能完成的練習,也歡迎看到本文章的各位給我提供源碼+適當的注釋。
動手試一試:
1.同時擲 6 面骰子和 10 面骰子 50 000 次的結果:
首先需要把原來建立的類(die.py)依舊保存到你新建項目的文件夾中,然后根據 die.py 的建立方法,把骰子從 6 面改成 10 面,文件命名為 die1.py 。本人感覺用這樣的方法雖然會多一個文件,但是在分析的時候會看得更加清楚,邏輯比較清晰,相關注釋已經在代碼中給出。具體的代碼如下(根據原先代碼修改得到結果):

1 # Author:Canvas 2 # -*- coding:utf-8 -*- 3 from random import randint 4 5 # 創建Die1類 6 class Die1(): 7 # 表示一個骰子的類 8 def __init__(self, num_sides = 10): 9 # 此處將骰子默認為10面 10 self.num_sides = num_sides 11 12 def roll(self): 13 # 返回一個位於1和骰子面數之間的隨機值 14 return randint(1, self.num_sides)

1 # Author:Canvas 2 # -*- coding:utf-8 -*- 3 4 # 同時擲 6 面骰子和 10 面骰子 50 000 次的結果 5 6 import pygal 7 8 from die import Die 9 from die1 import Die1 10 11 # 創建兩個D6骰子 12 die_1 = Die() 13 die_2 = Die1() 14 15 # 擲5000次骰子,並將結果存儲在一個列表中 16 results = [] 17 for roll_num in range(5000): 18 result = die_1.roll() + die_2.roll() 19 results.append(result) 20 21 # 分析結果 22 frequencies = [] 23 max_result = die_1.num_sides + die_2.num_sides 24 for value in range(2, max_result+1): 25 frequency = results.count(value) 26 frequencies.append(frequency) 27 28 # 對結果進行可視化 29 hist = pygal.Bar() 30 31 hist.title = 'Results of rolling D6 and D10 5000 times.' 32 hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', 33 '9', '10', '11', '12', '13', '14', 34 '15', '16'] 35 hist.x_title = 'Result' 36 hist.y_title = 'Frequency of Result' 37 38 # add傳遞到圖標,這種文件的擴展名必須為.svg 39 hist.add('D6 + D10', frequencies) 40 hist.render_to_file('D6D10.svg')
2.自動生成標簽 :請修改 die.py 和 dice_visual.py ,將用來設置 hist.x_labels 值的列表替換為一個自動生成這種列表的循環。如果你熟悉列表解析,可嘗試將die_visual.py 和 dice_visual.py 中的其他 for 循環也替換為列表解析。
3.兩個 D8 骰子: 請模擬同時擲兩個 8 面骰子 1000 次的結果。逐漸增加擲骰子的次數,直到系統不堪重負為止。

1 # -*- coding:utf-8 -*- 2 3 from random import randint 4 5 # 創建Die類 6 class Die(): 7 # 表示一個骰子的類 8 def __init__(self, num_sides = 8): 9 self.num_sides = num_sides 10 11 def roll(self): 12 # 返回一個位於1和骰子面數之間的隨機值 13 return randint(1, self.num_sides)

1 # -*- coding:utf-8 -*- 2 3 import pygal 4 5 from die import Die 6 7 # 創建兩個D8骰子 8 die_1 = Die() 9 die_2 = Die() 10 11 # 擲1000次骰子,並將結果存儲在一個列表中 12 results = [] 13 for roll_num in range(1000): 14 result = die_1.roll() + die_2.roll() 15 results.append(result) 16 17 # 分析結果 18 frequencies = [] 19 max_result = die_1.num_sides + die_2.num_sides 20 for value in range(2, max_result+1): 21 frequency = results.count(value) 22 frequencies.append(frequency) 23 24 # 對結果進行可視化 25 hist = pygal.Bar() 26 27 hist.title = 'Results of rolling two D8 1000 times.' 28 hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', '9', 29 '10', '11', '12', '13', '14', '15', '16'] 30 hist.x_title = 'Result' 31 hist.y_title = 'Frequency of Result' 32 33 hist.add('D8 + D8', frequencies) 34 hist.render_to_file('D8_D8.svg')
注:上面我把鼠標放在 9 那邊就進行了一個小互動
4.同時擲三個骰子 :如果你同時擲三個 D6 骰子,可能得到的最小點數為 3 ,而最大點數為 18 。請通過可視化展示同時擲三個 D6 骰子的結果。
在這個練習中,我們依然引入本章中第一次引入的代碼 Class_Die ,因為這里的骰子仍然是 6 面的,所以導入原來的類,然后修改代碼即可,具體代碼如下:

1 # -*- coding:utf-8 -*- 2 3 # 同時擲三個 6 面骰子的結果 4 5 import pygal 6 7 from die import Die 8 9 # 創建三個D6骰子 10 die_1 = Die() 11 die_2 = Die() 12 die_3 = Die() 13 14 # 將結果存儲在一個列表中 15 results = [] 16 for roll_num in range(3): 17 result = die_1.roll() + die_2.roll() +die_3.roll() 18 results.append(result) 19 20 # 分析結果 21 frequencies = [] 22 max_result = die_1.num_sides + die_2.num_sides + die_3.num_sides 23 for value in range(3, max_result+1): 24 frequency = results.count(value) 25 frequencies.append(frequency) 26 27 # 對結果進行可視化 28 hist = pygal.Bar() 29 30 hist.title = 'Results of rolling three D6 one time.' 31 hist.x_labels = ['3', '4', '5', '6', '7', '8', 32 '9', '10', '11', '12', '13', '14', 33 '15', '16', '17', '18'] 34 hist.x_title = 'Result' 35 hist.y_title = 'Frequency of Result' 36 37 # add傳遞到圖標,這種文件的擴展名必須為.svg 38 hist.add('D6 + D6 +D6', frequencies) 39 hist.render_to_file('D6_D6_D6.svg')
注:結果是隨機的,因為pygal的自動適應屏幕原因,這邊的Y軸其實最小值就是1,如果選擇擲骰子多次則不會出現這樣的刻度划分。
5.將點數相乘 :同時擲兩個骰子時,通常將它們的點數相加。請通過可視化展示將兩個骰子的點數相乘的結果。
關於點數相乘,我遇見了一些小小的問題,在經過幾次代碼的修改以后,我突然發現,乘法和加法在擲骰子的行為中,有着一些本質的區別,兩個骰子相加時,最小點數為 2 ,最大點數是 12 , 這之間的數字是連續不斷開的,理論上來講,只要擲骰子的次數夠多,每個點都會擲到。但是乘法不同,乘法的最小值是 1 , 最大值是 36 , 注意了! 乘法從 1 到 36 的得數不是連續的,比如說 兩個骰子無論怎么分配,都是不可能擲到 11 點 、17 點 等等的,所以在這里我們需要考慮一個問題,是把 1 - 36 的每個數都寫出來作為 X 軸呢,還是把不需要的數值去掉。這個問題是仁者見仁智者見智的,需要注意的一點是,pygal 的 互動 在你取消掉中間不可能的得數時,它是不會根據你橫坐標數值的不同而自動對應的,比如說當橫坐標為 1, 2, 3 時,如果你去掉了 2 ,程序會把 3 當成 2 的, 這就出現了 X 軸上實際數值對應的問題,對於如何使不可能出現的得數不將它作為橫坐標,而不使圖表出現對應錯誤的問題,經過我的嘗試,目前還沒有想到比較好的辦法,因為程序的計數就是很直接的從 1 開始計數,或許在不久的將來,我能夠找到解決這種問題的方法,畢竟對於我這樣的強迫症患者來說,明明不該出現的東西出現了,還占了一個礙眼的位置是很難受的。我們依舊以投擲骰子 1000 次為例,具體代碼如下:

1 import pygal 2 3 from die import Die 4 5 # 創建兩個D6骰子 6 die_1 = Die() 7 die_2 = Die() 8 9 # 擲1000次骰子,並將結果存儲在一個列表中 10 results = [] 11 for roll_num in range(1000): 12 result = die_1.roll() * die_2.roll() 13 results.append(result) 14 15 # print(results) 16 17 # 分析結果 18 frequencies = [] 19 max_result = die_1.num_sides * die_2.num_sides 20 for value in range(1, max_result+1): 21 frequency = results.count(value) 22 frequencies.append(frequency) 23 # print(frequencies) 24 # 對結果進行可視化 25 hist = pygal.Bar() 26 27 hist.title = 'Results of rolling two D6 1000 times.' 28 hist.x_labels = ['1', '2', '3', '4', '5', '6', '7','8', 29 '9', '10', '11', '12', '13', '14', '15', '16', 30 '17', '18', '19', '20', '21', '22', '23', '24', 31 '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36'] 32 hist.x_title = 'Result' 33 hist.y_title = 'Frequency of Result' 34 35 # add傳遞到圖標,這種文件的擴展名必須為.svg 36 hist.add('D6 * D6', frequencies) 37 hist.render_to_file('D6D6.svg')
注:中間空出來的東西我是看着真的不舒服,不過嘗試了幾個小時都沒能解決,就先讓它留着吧,當作日后進步的鞭策。
下面的這段代碼是我嘗試途中的一部分,問題還是比較大的,先讓它留在這里,日后慢慢再來修改:

1 # Author:Canvas 2 # -*- coding:utf-8 -*- 3 4 import pygal 5 6 from die import Die 7 8 # 創建兩個D6骰子 9 die_1 = Die() 10 die_2 = Die() 11 12 # 擲1000次骰子,並將結果存儲在一個列表中 13 results = [] 14 for roll_num in range(1000): 15 result = die_1.roll() * die_2.roll() 16 results.append(result) 17 18 # print(results) 19 20 # 分析結果 21 frequencies = [] 22 # max_result = die_1.num_sides * die_2.num_sides 23 # 此處不再使用max_result 因為我的X軸的數字總共只有20個 24 # max 有36 個,結果會和X坐標對應不起來 25 for value in range(1, 21): 26 frequency = results.count(value) 27 frequencies.append(frequency) 28 # print(frequencies) 29 # 對結果進行可視化 30 hist = pygal.Bar() 31 32 hist.title = 'Results of rolling two D6 1000 times.' 33 hist.x_labels = ['1', '2', '3', '4', '5', '6', '8', 34 '9', '10', '12', '13', '14', '15', 35 '16', '18', '20', '24', '25', '30', '36'] 36 hist.x_title = 'Result' 37 hist.y_title = 'Frequency of Result' 38 39 # add傳遞到圖標,這種文件的擴展名必須為.svg 40 hist.add('D6 * D6', frequencies) 41 hist.render_to_file('D6D6.svg')
6.嘗試使用 matplotlib 通過可視化來模擬擲骰子的情況,並嘗試使用 Pygal 通過可視化來模擬隨機漫步的情況。
關於代碼除了書本上摘錄的,個人的學習筆記篇幅有限,主要是為了方便自己日后學習查閱,所以你如果對這個代碼感興趣,對其中有疑問的地方可以問一下我,我會盡我所能提供解疑方法與途徑,或者你可以直接查閱這篇文章所查閱的書籍——《python編程:從入門到實踐》。