第15章 生成数据

15.1 安装 Matplotlib

python -m pip install --user matplotlib

15.2 绘制简单的折线图

import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(squares)

plt.show()

图 15-1

15.2.1 修改标签文字和线条粗细

import matplotlib.pyplot as plt
from matplotlib import rcParams  # 引入 rcParams 模块以修改字体

rcParams['font.family'] = 'SimHei'  # 修改字体以解决中文乱码问题

squares = [1, 4, 9, 16, 25]

fig, ax = plt.subplots()
ax.plot(squares, linewidth=3)  # linewidth=3 决定了线条粗细

# 设置图表标题并给坐标轴加上标签
ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("值的平方", fontsize=14)

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

plt.show()

图 15-2

15.2.2 校正图形

当我们想 X 轴以1开始,可以向 plot() 同时提供输入值和输出值:

import matplotlib.pyplot as plt
from matplotlib import rcParams

rcParams['font.family'] = 'SimHei'

input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]

fig, ax = plt.subplots()
ax.plot(input_values, squares, linewidth=3)  # 此处提供了输入值和输出值

ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("值的平方", fontsize=14)

ax.tick_params(axis='both', labelsize=14)

plt.show()

图 15-3

15.2.3 使用内置样式

import matplotlib.pyplot as plt
from matplotlib import rcParams

plt.style.use('seaborn')  # 此处设置使用'seaborn'样式

rcParams['font.family'] = 'SimHei'

input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]

fig, ax = plt.subplots()
ax.plot(input_values, squares, linewidth=3)

ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("值的平方", fontsize=14)

ax.tick_params(axis='both', labelsize=14)

plt.show()

注意:为防止中文乱码,设置样式代码需在 rcParams 模块前。

图 15-4

如果要查看可以使用哪些内置样式,可以使用以下代码:

import matplotlib.pyplot as plt
print(plt.style.available)

15.2.4 使用 scatter() 绘制散点图并设置样式

要绘制单个点,可使用方法 scatter():

import matplotlib.pyplot as plt
from matplotlib import rcParams

plt.style.use('seaborn')
rcParams['font.family'] = 'SimHei'

fig, ax = plt.subplots()
ax.scatter(2, 4, s=200)  # s=200用于设置点的大小

# 设置图表标题并给坐标轴加上标签
ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("值的平方", fontsize=14)

# 设置刻度标记的大小
ax.tick_params(axis='both', which='major', labelsize=14)

plt.show()

图 15-5

15.2.5 使用 scatter() 绘制一系列点

import matplotlib.pyplot as plt
from matplotlib import rcParams

plt.style.use('seaborn')
rcParams['font.family'] = 'SimHei'

"""传递X, Y轴坐标值"""
x_values = [1, 2, 3, 4, 5]
y_values = [1, 4, 9, 16, 25]

fig, ax = plt.subplots()
ax.scatter(x_values, y_values, s=100)

# 设置图表标题并给坐标轴加上标签
ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("值的平方", fontsize=14)

# 设置刻度标记的大小
ax.tick_params(axis='both', which='major', labelsize=14)

plt.show()

图 15-6

15.2.6 自动计算数据

使用循环来自动计算值:

import matplotlib.pyplot as plt
from matplotlib import rcParams

plt.style.use('seaborn')
rcParams['font.family'] = 'SimHei'

"""传递X, Y轴坐标值"""
x_values = range(1, 1001)
y_values = [x ** 2 for x in x_values]

fig, ax = plt.subplots()
ax.scatter(x_values, y_values, s=10)

# 设置图表标题并给坐标轴加上标签
ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("值的平方", fontsize=14)

# 设置刻度标记字体
ax.tick_params(axis='both', which='major', labelsize=14)

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

plt.show()

图 15-7

15.2.7 自定义颜色

要修改数据点的颜色,可以向 scatter() 传递参数 c,并将其设置为要使用的颜色的名称:

import matplotlib.pyplot as plt
from matplotlib import rcParams

plt.style.use('seaborn')
rcParams['font.family'] = 'SimHei'

"""传递X, Y轴坐标值"""
x_values = range(1, 1001)
y_values = [x ** 2 for x in x_values]

fig, ax = plt.subplots()
ax.scatter(x_values, y_values, c='red', s=10)  # 使用 c='red' 来设置数据点颜色

# 设置图表标题并给坐标轴加上标签
ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("值的平方", fontsize=14)

# 设置刻度标记字体
ax.tick_params(axis='both', which='major', labelsize=14)

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

plt.show()

图 15-8

还可以使用RGB颜色模式自定义颜色:

ax.scatter(x_values, y_values, c=(0.2, 0.5, 0.4), s=10)  # 使用 c=(0.2, 0.5, 0.4) 来设置数据点颜色

图 15-9

也可以使用16进制颜色模式自定义颜色:

ax.scatter(x_values, y_values, c='#F4B084', s=10)  # 使用 c='#F4B084' 来设置数据点颜色

图 15-10

15.2.8 使用颜色映射

颜色映射(colormap)是一系列渐变颜色:

import matplotlib.pyplot as plt
from matplotlib import rcParams

plt.style.use('seaborn')
rcParams['font.family'] = 'SimHei'

"""传递X, Y轴坐标值"""
x_values = range(1, 1001)
y_values = [x ** 2 for x in x_values]

fig, ax = plt.subplots()
ax.scatter(x_values, y_values, c=y_values, cmap=plt.cm.Blues, s=10)

# 设置图表标题并给坐标轴加上标签
ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("值的平方", fontsize=14)

# 设置刻度标记字体
ax.tick_params(axis='both', which='major', labelsize=14)

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

plt.show()

这里将参数 c 设置成了一个y值的列表,并使用参数 cmap 告诉 pyplot 使用哪个颜色映射。

图 15-11

15.2.9 自动保存图表

要自动保存图表,可将调用 plt.show() 替换为 plt.savefig() :

plt.savefig('img_1.png', bbox_inches='tight')

第一个参数指定要以什么文件名保存图表,第二个参数指定将图表多余的空白区域裁剪掉。

15.3 随机漫步

15.3.1 创建 RandomWalk 类

RandomWalk 类包含两个方法:方法init()和 fillwalk(),我们先来看看_init(),如下所示:

from random import choice

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

    def __init__(self, num_point=5000):
        self.num_point = num_point

        # 所有随机漫步都始于(0, 0)
        self.x_values = [0]
        self.y_values = [0]

将随机漫步包含的默认点数设置为5000,然后,创建两个用于储存x值和y值的列表,并让每次漫步都从(0,0)出发。

15.3.2 选择方向

使用方法 fill_walk() 来生成漫步包含的点并决定每次漫步的方向:

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

        # 不断漫步,直到列表达到指定的长度
        while len(self.x_values) < self.num_point:

            # 决定前进方向以及沿这个方向前进的距离
            x_derection = choice([1, -1])
            x_distance = choice([0, 1, 2, 3, 4])
            x_step = x_derection * x_distance

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

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

            x = self.x_values[-1] + x_step
            y = self.y_values[-1] + y_step

            self.x_values.append(x)
            self.y_values.append(y)

将以上两段代码保存至 random_walk.py 文件。

15.3.3 绘制随机漫步图

import matplotlib.pyplot as plt

from random_walk import RandomWalk

# 创建一个 RandomWalk 实例
rw = RandomWalk()
rw.fill_walk()
# 将所有的点都绘制出来
plt.style.use('classic')
fig, ax = plt.subplots()
ax.scatter(rw.x_values, rw.y_values, s=15)
plt.show()

图 15-12

15.3.4 模拟多次随机漫步

import matplotlib.pyplot as plt

from random_walk import RandomWalk


# 只要程序处于活动状态,就不断模拟
while True:
    # 创建一个 RandomWalk 实例
    rw = RandomWalk()
    rw.fill_walk()
    # 将所有的点都绘制出来
    plt.style.use('classic')
    fig, ax = plt.subplots()
    ax.scatter(rw.x_values, rw.y_values, s=15)
    plt.show()

    keep_running = input("再次生成另外一个随机漫步?(y/n)")  # 判断是否再次生成随机漫步
    if keep_running == 'n':
        break

15.3.5 设置随机漫步图的样式

1.给点着色

import matplotlib.pyplot as plt

from random_walk import RandomWalk

# 创建一个 RandomWalk 实例
rw = RandomWalk()
rw.fill_walk()
# 将所有的点都绘制出来
plt.style.use('classic')
fig, ax = plt.subplots()
point_numbers = range(rw.num_point)  # 生成 point_numbers 列表用于后面设置每个点的颜色
ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolors='none', s=15)
plt.show()

参数 c 设置为 point_numbers,指定颜色映射 Blues,并传递实参 edgecolors='none' 以删除每个点周围的轮廓。

图 15-13

2.重新绘制起点和终点

import matplotlib.pyplot as plt

from random_walk import RandomWalk

# 创建一个 RandomWalk 实例
rw = RandomWalk()
rw.fill_walk()
# 将所有的点都绘制出来
plt.style.use('classic')
fig, ax = plt.subplots()
point_numbers = range(rw.num_point)
ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolors='none', s=15)

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

图 15-14

3.隐藏坐标轴

import matplotlib.pyplot as plt

from random_walk import RandomWalk

# 创建一个 RandomWalk 实例
rw = RandomWalk()
rw.fill_walk()
# 将所有的点都绘制出来
plt.style.use('classic')
fig, ax = plt.subplots()
point_numbers = range(rw.num_point)
ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolors='none', s=15)

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

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

plt.show()

图 15-15

4.增加点数

import matplotlib.pyplot as plt

from random_walk import RandomWalk

# 创建一个 RandomWalk 实例
rw = RandomWalk(50_000)  # 增加点数
rw.fill_walk()

plt.style.use('classic')
fig, ax = plt.subplots()
point_numbers = range(rw.num_point)
ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolors='none', s=1)  # 每个点的大小设置为1

ax.scatter(0, 0, c='green', edgecolors='none', s=100)
ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none', s=100)

ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)

plt.show()

图 15-16

5.调整尺寸以适合屏幕

import matplotlib.pyplot as plt

from random_walk import RandomWalk

# 创建一个 RandomWalk 实例
rw = RandomWalk(50_000)  # 增加点数
rw.fill_walk()

plt.style.use('classic')
# 使用 figsize=(10, 6) 设置输出图形的尺寸(单位:英尺);使用 dpi 来设置分辨率
fig, ax = plt.subplots(figsize=(10, 6), dpi=128)  
point_numbers = range(rw.num_point)
ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolors='none', s=1)  # 每个点的大小设置为1

ax.scatter(0, 0, c='green', edgecolors='none', s=100)
ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none', s=100)

ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)

plt.show()

图 15-17

15.4 使用 Plotly 模拟掷骰子

15.4.1 安装 Plotly

python -m pip install --user plotly

15.4.2 创建 Die 类

新建一个 die.py 文件:

from random import randint


class Die:
    """表示一个骰子的类"""

    def __init__(self, num_sides=6):
        """骰子默认为6面"""
        self.num_sides = num_sides

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

方法init()接受一个可选参数,如没有指定任何实参,面数默认为6;
方法 roll() 使用函数 randint() 来返回一个1和面之间的随机数。

15.4.3 掷骰子

from die import Die

# 创建一个 D6
die = Die()

# 掷几次骰子并将结果存储在一个列表里面
results = []
for roll_num in range(100):
    result = die.roll()
    results.append(result)

print(results)

>>>
[1, 3, 6, 3, 3, 6, 5, 5, 5, 5, 5, 2, 2, 5, 1, 6, 5, 4, 1, 4, 2, 5, 6, 6, 1, 4, 5, 4, 3, 5, 2, 4, 4, 5, 5, 2, 5, 2, 1, 6, 5, 6, 5, 2, 1, 4, 5, 1, 5, 1, 3, 3, 3, 5, 4, 3, 5, 6, 6, 5, 4, 4, 6, 3, 1, 6, 3, 5, 3, 2, 5, 3, 5, 5, 1, 1, 5, 6, 2, 6, 1, 5, 6, 6, 4, 5, 5, 6, 3, 1, 4, 2, 6, 6, 5, 5, 6, 4, 4, 1]

15.4.4 分析结果

from die import Die

# 创建一个 D6
die = Die()

# 掷几次骰子并将结果存储在一个列表里面
results = []
for roll_num in range(1000):
    result = die.roll()
    results.append(result)

# 分析结果
frequencies = []
for value in range(1, die.num_sides + 1):
    frequency = results.count(value)
    frequencies.append(frequency)

print(frequencies)

>>>
[153, 179, 174, 143, 164, 187]

15.4.5 绘制直方图

from plotly.graph_objs import Bar, Layout
from plotly import offline

from die import Die

# 创建一个 D6
die = Die()

# 掷几次骰子并将结果存储在一个列表里面
results = []
for roll_num in range(1000):
    result = die.roll()
    results.append(result)

# 分析结果
frequencies = []
for value in range(1, die.num_sides + 1):
    frequency = results.count(value)
    frequencies.append(frequency)

# 对结果进行可视化
x_values = list(range(1, die.num_sides + 1))
data = [Bar(x=x_values, y=frequencies)]

x_axis_config = {'title': '结果'}
y_axis_config = {'title': '结果的频率'}
my_layout = Layout(title='掷一个D6 1000次的结果', xaxis=x_axis_config, yaxis=y_axis_config)
offline.plot({'data': data, 'layout': my_layout}, filename='d6.html')

为创建直方图:

  • 将可能出现的点数存储在一个名为 x_values 的列表中。Plotly 不能直接接受函数 range() 的结果,因此需要使用函数 list() 转为列表;
  • Plotly 类 Bar()表示用于绘制条形图的数据集,需要一个存储x值的列表和一个存储y值的列表,且这个类必须放在方括号内;
  • 每个坐标轴都能以不同的方式进行配置,而每个配置选项都是一个字典元素;
  • 类 Layout() 返回一个指定图表布局和配置的对象;
  • 函数 offline.plot() 需要一个包含数据和布局对象的字典,还接受一个文件名。

图 15-18

15.4.6 同时掷两个骰子

from plotly.graph_objs import Bar, Layout
from plotly import offline

from die import Die

# 创建两个 D6
die_1 = Die()
die_2 = Die()

# 掷几次骰子并将结果存储在一个列表里面
results = []
for roll_num in range(1000):
    result = die_1.roll() + die_2.roll()
    results.append(result)

# 分析结果
frequencies = []
max_result = die_1.num_sides + die_2.num_sides  # 最大结果值
for value in range(2, max_result + 1):
    frequency = results.count(value)
    frequencies.append(frequency)

# 对结果进行可视化
x_values = list(range(2, max_result + 1))
data = [Bar(x=x_values, y=frequencies)]

x_axis_config = {'title': '结果', 'dtick': 1}  # 'dtick':1 指定了x轴的间距,并显示每个刻度值
y_axis_config = {'title': '结果的频率'}
my_layout = Layout(title='掷两个D6 1000次的结果', xaxis=x_axis_config, yaxis=y_axis_config)
offline.plot({'data': data, 'layout': my_layout}, filename='d6_d6.html')

图 15-19

15.4.7 同时掷两个面数不同的骰子

from plotly.graph_objs import Bar, Layout
from plotly import offline

from die import Die

# 创建一个 D6 和一个D10
die_1 = Die()
die_2 = Die(10)

# 掷几次骰子并将结果存储在一个列表里面
results = []
for roll_num in range(50_000):
    result = die_1.roll() + die_2.roll()
    results.append(result)

# 分析结果
frequencies = []
max_result = die_1.num_sides + die_2.num_sides  # 最大结果值
for value in range(2, max_result + 1):
    frequency = results.count(value)
    frequencies.append(frequency)

# 对结果进行可视化
x_values = list(range(2, max_result + 1))
data = [Bar(x=x_values, y=frequencies)]

x_axis_config = {'title': '结果', 'dtick': 1}  # 'dtick':1 指定了x轴的间距,并显示每个刻度值
y_axis_config = {'title': '结果的频率'}
my_layout = Layout(title='掷一个D6和一个D10 50000次的结果', xaxis=x_axis_config, yaxis=y_axis_config)
offline.plot({'data': data, 'layout': my_layout}, filename='d6_d10.html')

图 15-20

results matching ""

    No results matching ""

    results matching ""

      No results matching ""