Pygal畫廊——擲骰子


  本人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)
Class_Die
 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)
Results_100
 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)
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 # 使用瀏覽器打開這個圖表
Die_visual

  個人提示:不要用系統自帶的圖像查看器查看,你很有可能看到的是一堆黑的,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')
Dice_visual

  

  這些圖片不是我給它更改了大小,而是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)
die1
 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')
D6_D10

  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)
Class_Die
 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')
D8_D8

注:上面我把鼠標放在 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')
D6_D6_D6

注:結果是隨機的,因為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')
D6D6

注:中間空出來的東西我是看着真的不舒服,不過嘗試了幾個小時都沒能解決,就先讓它留着吧,當作日后進步的鞭策。

  下面的這段代碼是我嘗試途中的一部分,問題還是比較大的,先讓它留在這里,日后慢慢再來修改:

 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')
Try_2

 

  6.嘗試使用 matplotlib 通過可視化來模擬擲骰子的情況,並嘗試使用 Pygal 通過可視化來模擬隨機漫步的情況。

 

  關於代碼除了書本上摘錄的,個人的學習筆記篇幅有限,主要是為了方便自己日后學習查閱,所以你如果對這個代碼感興趣,對其中有疑問的地方可以問一下我,我會盡我所能提供解疑方法與途徑,或者你可以直接查閱這篇文章所查閱的書籍——《python編程:從入門到實踐》。


免責聲明!

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



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