来源:《Python编程:从入门到实践》
文章目录
1 随机漫步
- 使用Python生成随机漫步数据,再使用matplotlib以引人瞩目的方式将这些数据呈现出来
随机漫步
是这样行走得到的路径:每次行走都完全是随机的,没有明确的方向,结果是由一系列随机决策决定的
1.1 创建RandomWalk()类
- 创建一个名为
RandomWalk
的类,它随机地选择前进方向 - 这个类需要三个属性,一个是存储随机漫步次数的变量,其他两个是列表(存储随机漫步经过的每个点的x&y坐标)
random_walk.py
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]
- 将所有可能的选择存储在一个列表中,并在每次做决策时都使用choice()来决定哪种选择
1.2 选择方向
random_walk.py
def fill_walk(self):
"""计算随机漫步包含的所有点"""
# 不断漫步,直到列表达到指定的长度
while len(self.x_values) < self.num_points:
# 决定前进方向以及沿这个方向前进的距离
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
# 计算下一个点的x和y的值
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)
- 这个方法的主要告诉Python如何模拟四种漫步决定:向右走还是向左走?沿指定的方向走多远?向上走还是向下走?沿选定的方向走多远?
1.3 绘制随机漫步图
rw_visual.py
import matplotlib.pyplot as plt
from random_walk import RandomWalk
# 创建一个RandomWalk实例,并将其包含的点都绘制出来
rw = RandomWalk()
rw.fill_walk()
plt.scatter(rw.x_values, rw.y_values, s=15)
plt.show()
- 导入
模块pyplot
和RandomWalk类
,然后创建了一个RandomWalk实例
,再调用fill_walk()
1.4 模拟多次随机漫步
- 要想不每次都费劲地执行程序,使用上面的代码模拟多次随机漫步,一种方法是将这些代码放在一个while循环中
rw_visual.py
import matplotlib.pyplot as plt
from random_walk import RandomWalk
# 只要程序处于活动状态,就不断地模拟随机漫步
while True:
# 创建一个RandomWalk实例,并将其包含的点都绘制出来
rw = RandomWalk()
rw.fill_walk()
plt.scatter(rw.x_values, rw.y_values, s=15)
plt.show()
keep_running = input("再漫步一次嘛? (y/n):")
if keep_running == 'n':
break
1.5 设置随机漫步图的样式
- 下面来定制图表,以突出每次漫步的重要特征,不突出那些分散注意力的元素
1.6 给点着色
- 使用颜色映射来指出漫步中各点的先后顺序,并删除每个点的黑色轮廓,让它们颜色更明显
- 根据漫步的各点先后顺序进行着色,
传递参数c,将其设置为一个列表,其中包含各点的先后顺序
rw_visual.py
--snip--
while True:
# 创建一个RandomWalk实例,并将其包含的点都绘制出来
rw = RandomWalk()
rw.fill_walk()
point_numbers = list(range(rw.num_points))
plt.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
edgecolor='none', s=15)
plt.show()
keep_running = input("再漫步一次嘛? (y/n):")
if keep_running == 'n':
break
1.7 重新绘制起点和终点
- 在绘制随机漫步图后重新绘制起点和终点
- 让起点&终点变得更大,并显示为不同的颜色,以突出它们
rw_visual.py
--snip--
while True:
# 创建一个RandomWalk实例,并将其包含的点都绘制出来
rw = RandomWalk()
rw.fill_walk()
point_numbers = list(range(rw.num_points))
plt.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
edgecolor='none', s=15)
# 突出起点和终点
plt.scatter(0, 0, c='green', edgecolor='none', s=100)
plt.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none',
s=100)
plt.show()
--snip--
- 务必将这部分代码放在调用plt.show()的代码前面,确保在其他点的上面绘制起点&终点
1.8 隐藏坐标轴
rw_visual.py
--snip--
while True:
--snip--
plt.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none',
s=100)
# 隐藏坐标轴
plt.axes().get_xaxis().set_visible(False)
plt.axes().get_yaxis().set_visible(False)
plt.show()
--snip--
1.9 增加点数
- 增加点数以提供更多的数据
创建RandomWalk实例时,增大num_points的值,并在绘图时调整每个点的大小
rw_visual.py
--snip--
while True:
# 创建一个RandomWalk实例,并将其包含的点都绘制出来
rw = RandomWalk(50000)
rw.fill_walk()
point_numbers = list(range(rw.num_points))
plt.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
edgecolor='none', s=1)
--snip--
1.10 调整尺寸以适合屏幕
让绘图窗口更适合屏幕大小,可调整matplotlib输出的尺寸
rw_visual.py
--snip--
while True:
# 创建一个RandomWalk实例,并将其包含的点都绘制出来
rw = RandomWalk(50000)
rw.fill_walk()
# 设置绘图窗口的尺寸
plt.figure(figsize=(10, 6))
--snip--
函数figure()用于指定图表的宽度、高度、分辨率和背景色
- 给形参figsize指定一个元组,向matplotlib指出绘图窗口的尺寸,单位:英寸
figure语法说明
figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True)
num:图像编号或名称,数字为编号 ,字符串为名称
figsize:指定figure的宽和高,单位为英寸;
dpi参数指定绘图对象的分辨率,即每英寸多少个像素
facecolor:背景颜色
edgecolor:边框颜色
frameon:是否显示边框
2 练习
15-3 分子运动:修改rw_visuai.py,将其中的plt.scatter()替换为plt.plot()。为模拟花粉在水滴表面的运动路径,向plt.plot()传递rw.x_values和rw.y_values,并指定实参值linewidth。使用5000个点而不是50000个点
- solution:
import matplotlib.pyplot as plt
from random_walk import RandomWalk
# 只要程序处于活动状态,就不断地模拟随机漫步
while True:
# 创建一个RandomWalk实例,并将其包含的点都绘制出来
rw = RandomWalk()
rw.fill_walk()
# 设置绘图窗口的尺寸
plt.figure(dpi=128, figsize=(10, 6))
point_numbers = list(range(rw.num_points))
plt.plot(rw.x_values, rw.y_values, linewidth=1)
# 突出起点和终点
plt.scatter(0, 0, c='green', edgecolor='none', s=100)
plt.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none',
s=100)
# 隐藏坐标轴
plt.axes().get_xaxis().set_visible(False)
plt.axes().get_yaxis().set_visible(False)
plt.show()
keep_running = input("再漫步一次嘛? (y/n):")
if keep_running == 'n':
break
- Output:
**15-4 改进的随机漫步:**在类RandomWalk中,x_step和y_step是根据相同的条件生成的:从列表[-1, 1]中随机地选择方向,并从列表[0, 1, 2, 3, 4]中随机地选择距离。请修改这些列表中的值,看看对随机漫步路径有何影响。尝试使用更长的距离选择列表,如0~8;或者将-1从x或y方向列表中删除
- solution:
这个自己尝试改进,就跳了先
15-5 重构: 方法fill_walk()很长。请新建一个名为get_step(0的方法,用于确定每次漫步的距离和方向,并计算这次漫步将如何移动。然后,在fill_walk()中调用get_step两次:
x_step = self.get_step()
y_step = self.get_step()
通过这样的重构,可缩小fill_walk()的规模,让这个方法阅读和理解起来更容易
- solution:
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 get_step(self):
"""Determine the direction and distance for a step."""
direction = choice([1, -1])
distance = choice([0, 1, 2, 3, 4])
step = direction * distance
return step
def fill_walk(self):
"""计算随机漫步包含的所有点"""
# 不断漫步,直到列表达到指定的长度
while len(self.x_values) < self.num_points:
# 决定前进方向以及沿这个方向前进的距离
x_step = self.get_step()
y_step = self.get_step()
# 拒绝原地踏步
if x_step == 0 and y_step == 0:
continue
# 计算下一个点的x和y的值
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)
- Output: