Python学习之路14-生成数据

《Python编程:从入门到实践》笔记。
从本篇起将用三篇的篇幅介绍如何用Python进行数据可视化。

1. 前言

从本篇开始,我们将用三篇的篇幅来初步介绍如何使用Python来进行数据可视化操作。本篇的内容包括:

  • 绘制简单的折线图;
  • 随机漫步;
  • 使用Pygal模拟掷骰子。

在正式开始之前,需要安装两个扩展包:matplotlibpygal。Python中安装第三方库的方式已在上一个项目中介绍过了,这里不再赘述。

2. 绘制简单的折线图

2.1 简单的折线图

首先我们绘制一个简单的折线图,代码保存到mpl_squares.py文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import matplotlib.pyplot as plt

# 输入数据, x轴
input_values = [1, 2, 3, 4, 5]
# 输出数据, y轴
squares = [1, 4, 9, 16, 25]
# linewidth表示线条的粗细
plt.plot(input_values, squares, linewidth=5)

# 设置图标标题,并给坐标轴加上标签
plt.title("Square Numbers", fontsize=24)
plt.xlabel("Value", fontsize=14)
plt.ylabel("Square of Value", fontsize=14)

# 设置刻度标记的大小
plt.tick_params(axis="both", labelsize=14)

plt.show()

matplotlib.pyplot.plot()函数可以只传入一个squares参数,表示y轴的值,此时将从x轴0点处开始一一对应。有时这样很简便,但在此例中图标将不正确,所以我们传入了input_values列表,将其与squares列表一一对应。

代码从第10行到15行都可以省了,这些代码只是让图表的信息更全。最终的结果如下:

2.2 生成散点图

我们使用matplotlib.pyplot中的scatter()函数来生成散点图,将代码保存到scatter_squares.py文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import matplotlib.pyplot as plt

x_values = list(range(1, 1001))
y_values = [x ** 2 for x in x_values]

# s表示点的大小,edgecolor表示点的轮廓的颜色,c表示数据点的颜色(可以使用RGB颜色)
# plt.scatter(x_values, y_values, s=4, edgecolor="none", c="red")

# 使用渐变色, 给c赋值了一个y值列表,并使用参数cmap告诉pylot使用哪个颜色来映射
plt.scatter(x_values, y_values, s=40, edgecolor="none", c=y_values, cmap=plt.cm.Blues)

# 设置图表标题并给坐标轴加上标签
plt.title("Square Number", fontsize=24)
plt.xlabel("Value", fontsize=14)
plt.ylabel("Square of Value", fontsize=14)

# 设置刻度的大小
plt.tick_params(axis="both", which="major", labelsize=14)

# 每个坐标轴的取值范围
plt.axis([0, 1100, 0, 1100000])

# 第一个参数是路径名,第二个参数指定将图表多余的空白区域裁减掉。
plt.savefig("squares.png", bbox_inches="tight")

plt.show()

我们使用了列表生成式来生成y轴的数据,并使用渐变色来绘制图像,matplotlib.pyplot.cm.Bluesmatplotlib自带的渐变色,它和c的每一个值对应。通过pyplotaxis()函数来设置每个轴的取值范围。最后将图像保存到本地。生成的图像如下:

3. 随机漫步

随机漫步指的是:每次行走都完全随机,没有明确的方向,结果是由一系列随机决策决定的。在自然界、物理学、生物学、化学和经济领域,随机漫步都有其实际用途。

使用Python生成随机漫步数据,再使用matplotlib将这些数据绘制出来。首先创建RandomWalk类,代码保存到random_walk.py文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from random import choice

class RandomWalk:
"""一个生成随机漫步数据的类"""

def __init__(self, num_points=5000):
"""初始化随机漫步的属性"""
self.num_points = num_points

# 所有随机漫步都始于(0, 0),这两个列表用于存储随机漫步数据
self.x_values = [0]
self.y_values = [0]

def fill_walk(self):
"""计算随机漫步包含的所有点"""

# 不断漫步,直到列表到达指定的长度
while len(self.x_values) < self.num_points:
# 决定前进方向以及沿这个方向前进的距离
# 通过choice从给定值中随机选取
x_direction = choice([1, -1]) # 正向还是负向
x_distance = choice([0, 1, 2, 3, 4]) # 移动的距离
x_step = x_direction * x_distance

y_direction = choice([1, -1])
y_distance = choice([0, 1, 2, 3, 4])
y_step = y_direction * y_distance

# 拒绝原地踏步
if x_step == 0 and y_step == 0:
continue

# 计算下一个点的坐标
next_x = self.x_values[-1] + x_step
next_y = self.y_values[-1] + y_step

self.x_values.append(next_x)
self.y_values.append(next_y)

下面的代码用于生成随机漫步图像,代码保存到rw_visual.py文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import matplotlib.pyplot as plt
from random_walk import RandomWalk

while True:
rw = RandomWalk(50000)
rw.fill_walk()

# 设置绘图窗口的尺寸
plt.figure(figsize=(10, 6))

# 绘制随机漫步的图像
point_number = list(range(rw.num_points))
plt.scatter(rw.x_values, rw.y_values, s=1, c=point_number,
edgecolors="none", cmap=plt.cm.Blues)

# 突出起点和终点
plt.scatter(0, 0, c="green", edgecolors="none", s=100)
plt.scatter(rw.x_values[-1], rw.y_values[-1], c="red", edgecolors="none",
s=100)

# 隐藏坐标轴
plt.axes().get_xaxis().set_visible(False)
plt.axes().get_yaxis().set_visible(False)

plt.show()

if input("Make another walk?(y/n)") == "n":
break

程序通过一个循环类多次绘制随机漫步图;通过pyplotfigure()函数来设置图像的尺寸,figsize的单位是英寸;通过渐变色来绘制图像的路径,颜色由浅到深,并且我们将起点(绿色)和终点(红色)显著标出;最后隐藏坐标轴。最终的图像如下(每次运行的效果都不同):

4. 使用Pygal模拟掷骰子

首先我们需要创建一个骰子类Dice,将其保存到dice.py中:

1
2
3
4
5
6
7
8
9
10
11
from random import randint

class Dice:
"""表示一个骰子类"""
def __init__(self, num_sides=6):
"""骰子默认为6面"""
self.num_sides = num_sides

def roll(self):
"""返回一个位于1和骰子面数之间的随机值"""
return randint(1, self.num_sides)

可以自行设定骰子的面数。下面是掷两个骰子50000次,统计俩骰子点数之和的分布的模拟,最后生成了一个矢量文件.svg文件,它能在浏览器中打开,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import pygal
from dice import Dice

dice_1 = Dice()
dice_2 = Dice(10)

# 掷骰子多次,并将结果存储在一个列表中
results = []
for roll_num in range(50000):
results.append(dice_1.roll() + dice_2.roll())

# 分析结果
frequences = []
# 能够模拟掷任何双骰子的情况,不管这些骰子有多少面
max_result = dice_1.num_sides + dice_2.num_sides
for value in range(2, max_result + 1):
# 统计每个结果的频数
frequences.append(results.count(value))

# 对结果进行可视化
# 创建条形图
hist = pygal.Bar()

hist.title = "Result of rolling a D6 and a D10 50000 times."
# 创建x轴上的刻度
hist.x_labels = [str(value) for value in range(2, max_result + 1)]
hist.x_title = "Result"
hist.y_title = "Frequency of Result"

# 给这组数据起个名字,并加到图表中
hist.add("D6 + D10", frequences)
# 将图像渲染为svg文件,矢量图
hist.render_to_file("dice_visual.svg")

注意,frequences中的数据依次与hist.x_labels对应。下面是最终结果:

Pygal让这个图表具有交互性:如果你将鼠标指向该图中的任何数据条,将看到它的具体数据。

5. 小结

本篇主要讲述了:

  • 如何生成数据集以及如何对其进行可视化;
  • 如何使用matplotlib创建简单的图表;
  • 如果使用散点图来探索随机漫步过程;
  • 如何使用Pygal创建直方图,以及如何使用直方图来探索同时掷两个面数不同的骰子的结果。
VPointer wechat
欢迎大家关注我的微信公众号"代码港"~~
您的慷慨将鼓励我继续创作~~