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