本文与课本稍有出入,本文采用的工具是pycharm,与课本稍有出入
15.1 安装Matplotlib
-
win + R ,并输入 cmd , 进入命令行界面
如下图:
2. 使用 python -m pip list , 查看本机的安装的所有模块如下图::
-
按提示信息,将 pip 版本升级至最新
如下图:
: -
升级成功后, 使用 python -m pip install matplotlib 安装Matplotlib
如下图:
: -
安装成功后,再次使用 python -m pip list ,发现matpoltlib已经存在了
如下图:
: -
打开pycharm,新建一个项目:date_study
如下图:
: -
新建一个测试文件:test.py,将以下代码复制进去,然后运行
import matplotlib.pyplot as plt
labels='frogs','hogs','dogs','logs'
sizes=15,20,45,10
colors='yellowgreen','gold','lightskyblue','lightcoral'
explode=0,0.1,0,0
plt.pie(sizes,explode=explode,labels=labels,colors=colors,autopct='%1.1f%%',shadow=True,startangle=50)
plt.show()
-
运行结果如下图:
-
15.2 绘制简单的折线图
- subplots()函数
- plot()函数
- show()函数
新建 test.py,输入以下代码
import matplotlib.pyplot as plt
squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(squares)
plt.show()
实现效果如下图:
15.2.1 修改标签文字和线条粗细
- set_title()
- set_xlabel()
- set_ylabel()
- tick_params()
改善图表的可读性
import matplotlib.pyplot as plt
squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(squares, linewidth=3) # 参数2设置线条粗细
ax.set_title("平方数", fontsize=24) #该方法设置标题
ax.set_xlabel("值", fontsize=14) #该方法设置x轴标题
ax.set_ylabel("值的平法数", fontsize=14) #该方法设置y轴标题
#参数1设置刻度的样式,参数2设置字号
ax.tick_params(axis="both", labelsize=14)
plt.show()
此时,运行程序,大概率会出现中文不能显示的情况,可以遵循以下方法解决
- Win + R ,输入 cmd 打开命令行窗口
- 输入 python,进入python界面
- 输入 import matplotlib 导入该模块
- 输入 matplotlib.matplotlib_fname() 查找该文件路径,查询结果为:
C:\Users\zhangxy\AppData\Roaming\Python\Python39\site-packages\matplotlib\mpl-data\matplotlibrc
(“\\“需要改为”\“)
5 .用文本方式打开该文件,搜索 font.family ,找到 # font.family: sans-serif ,将其改为
font.family: Microsoft YaHei
此时运行程序,即可达到与课本相同的效果,如图:
15.2.2 校正图形
我们发现图形的终点4.0的平方是25,这很明显不对,这是因为:没有输入值时,假设的第一个x数据点是0,我们修复这个问题
import matplotlib.pyplot as plt
input_values = [1, 2, 3, 4, 5] # 为plot()提供输入值
squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(input_values, squares, linewidth=3) # 参数2设置线条粗细
ax.set_title("平方数", fontsize=24) #该方法设置标题
ax.set_xlabel("值", fontsize=14) #该方法设置x轴标题
ax.set_ylabel("值的平法数", fontsize=14) #该方法设置y轴标题
#参数1设置刻度的样式,参数2设置字号
ax.tick_params(axis="both", labelsize=14)
plt.show()
此时输出的图形是正确的,如下图:
15.2.3 使用内置样式
matplotlib提供了很多样式
执行程序
import matplotlib.pyplot as plt
print(plt.style.available)
输出:
[‘Solarize_Light2’, ‘_classic_test_patch’, ‘_mpl-gallery’, ‘_mpl-gallery-nogrid’, ‘bmh’, ‘classic’, ‘dark_background’, ‘fast’, ‘fivethirtyeight’, ‘ggplot’, ‘grayscale’, ‘seaborn’, ‘seaborn-bright’, ‘seaborn-colorblind’, ‘seaborn-dark’, ‘seaborn-dark-palette’, ‘seaborn-darkgrid’, ‘seaborn-deep’, ‘seaborn-muted’, ‘seaborn-notebook’, ‘seaborn-paper’, ‘seaborn-pastel’, ‘seaborn-poster’, ‘seaborn-talk’, ‘seaborn-ticks’, ‘seaborn-white’, ‘seaborn-whitegrid’, ‘tableau-colorblind10’]
使用其中的某一个样式,如:Solarize_Light2
使用 seaborn 又会出现汉语无法显示的问题
实现代码如下:
import matplotlib.pyplot as plt
input_values = [1, 2, 3, 4, 5] # 为plot()提供输入值
squares = [1, 4, 9, 16, 25]
plt.style.use("Solarize_Light2")
fig, ax = plt.subplots()
ax.plot(input_values, squares, linewidth=3) # 参数2设置线条粗细
ax.set_title("平方数", fontsize=24) #该方法设置标题
ax.set_xlabel("值", fontsize=14) #该方法设置x轴标题
ax.set_ylabel("值的平法数", fontsize=14) #该方法设置y轴标题
#参数1设置刻度的样式,参数2设置字号
ax.tick_params(axis="both", labelsize=14)
plt.show()
执行程序,显示如下图:
15.2.4 使用scatter()绘制散点图并设置样式
绘制单个点,使用scatter()方法
import matplotlib.pyplot as plt
plt.style.use('Solarize_Light2')
fig, ax = plt.subplots()
ax.scatter(2, 4) # 使用该方法绘制一个(2,4)的点
plt.show()
执行结果如下图:
设置图标的样式,包括标题、坐标轴标签等
import matplotlib.pyplot as plt
plt.style.use('Solarize_Light2')
fig, ax = plt.subplots()
ax.scatter(2, 4, s=200)
# 使用该方法绘制一个(2,4)的点,s表示点的尺寸
#设置图标的标题和坐标轴标签
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.2.5 使用scatter()绘制一系列点
要绘制一系列点,可以传递两个包含x,y的列表,列表值按下标组合成元素点坐标
x=[1,2,3];y=[4,5,6],那么点就是(1,4)、(2,5)、(3,6)三个
程序如下图:
import matplotlib.pyplot as plt
x_values = [1, 2, 3, 4, 5]
y_values = [1, 4, 9, 16, 25]
plt.style.use('Solarize_Light2')
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.2.6 自动计算数据
如果数据量大,手动输入值效率低下,我们可以用python循环来完成
# 绘制1000个点的代码
import matplotlib.pyplot as plt
x_values = range(1,1001)
y_values = [x**2 for x in x_values]
plt.style.use('Solarize_Light2')
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)
# 设置x,y坐标轴的取值范围
ax.axis = ([0, 1100, 0, 1100000]) #四个值分别是x的最小最大,y的最小最大
plt.show()
执行效果如下图:
15.2.7 自定义颜色
要修改数据点的颜色,只需要向scatter()传递参数c即可
c 可以是颜色的名称,如 c=‘red’,也可以是RGB颜色,如 c=(0,0.8,0),三个值分别代表红、绿、蓝的分量,取值范围都是0-1
# 绘制1000个点的代码
import matplotlib.pyplot as plt
x_values = range(1,1001)
y_values = [x**2 for x in x_values]
plt.style.use('Solarize_Light2')
fig, ax = plt.subplots()
#ax.scatter(x_values, y_values, c= 'red', s=10)
#或者,这两行取其中一行即可
ax.scatter(x_values, y_values, c=(0, 0.8, 0), 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)
# 设置x,y坐标轴的取值范围
ax.axis = ([0, 1100, 0, 1100000]) #四个值分别是x的最小最大,y的最小最大
plt.show()
执行结果如下图:
15.2.8 使用颜色映射
颜色映射首先将scatter()方法中的c设置为一个列表,然后用cmap参数进行颜色映射,小的值为浅色,大的值为深色
# 绘制1000个点的代码
import matplotlib.pyplot as plt
x_values = range(1,1001)
y_values = [x**2 for x in x_values]
plt.style.use('Solarize_Light2')
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)
# 设置x,y坐标轴的取值范围
ax.axis = ([0, 1100, 0, 1100000]) #四个值分别是x的最小最大,y的最小最大
plt.show()
执行效果如下图:
15.2.9 自动保存图标
只需将plt.show()改为调用plt.savefig()
# 绘制1000个点的代码
import matplotlib.pyplot as plt
x_values = range(1,1001)
y_values = [x**2 for x in x_values]
plt.style.use('Solarize_Light2')
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)
# 设置x,y坐标轴的取值范围
ax.axis = ([0, 1100, 0, 1100000]) #四个值分别是x的最小最大,y的最小最大
plt.savefig('squares_plot.png', bbox_inches='tight')
#第一个参数是保存图片的文件名字,第二个参数是剪掉多余的空白
执行程序,发现.py同目录下多了一个Png文件,如下图一:
打开该图片:
15.3 随机漫步
随机漫步指每次行走都是完全随机的,没有明确的方向,没有明确的步数
15.3.1 创建RandomWalk类 & 15.3.2 选择方向
RandomWalk类应该包括三个属性:
- 随机漫步的次数
- 随机漫步每次的x坐标
- 随机漫步每次的y坐标
x,y坐标合起来就是一个点
RandomWalk类还有2个方法:
- 初始化方法
- fill_walk()方法,该方法用来计算随机漫步经过的所有点
# randomwalk.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]
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_distance * x_direction
y_direction = choice([1, -1])
y_distance = choice([0, 1, 2, 3, 4])
y_step = y_distance * y_direction
# 拒绝原地踏步
if x_step == 0 and y_step == 0:
continue
# 计算下一个点的x和y的值
x = self.x_values[-1] + x_step
y = self.y_values[-1] + y_step
self.x_values.append(x)
self.y_values.append(y)
15.3.3 绘制随机漫步图
代码如下:
# rw.py
import matplotlib.pyplot as plt
from randomwalk 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.3.4 模拟多次随机漫步
使用while循环,实现多次随机漫步,只需修改rw.py代码:
# rw.py
import matplotlib.pyplot as plt
from randomwalk 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("Make another walk?(y/n): ")
if keep_running == 'n':
break
执行效果如图:
15.3.5 设置随机漫步图的样式
1 给着色点
本小节我们完成的任务是按照漫步的先后顺序给生成点着色,并去掉每个生成点 的外圈
修改rw.py的代码
# rw.py
import matplotlib.pyplot as plt
from randomwalk import RandomWalk
while True:
# 创建一个RandomWalk实例
rw = RandomWalk()
rw.fill_walk()
# 将所有点都绘制出来
plt.style.use('classic')
fig, ax = plt.subplots()
point_numbers = range(rw.num_points)
ax.scatter(rw.x_values, rw.y_values,c=point_numbers,cmap=plt.cm.Blues,edgecolor='none', s=15)
plt.show()
keep_running = input("Make another walk?(y/n): ")
if keep_running == 'n':
break
文中说range()生成一个数字列表,我认为不妥,应该是一个可迭代对象,因为执行 range(100),生成的是 range(0,100)这个对象,不是列表
执行结果如下图:
2 重新绘制起点和终点
本小节的工作是将起点和终点突出显示
修改rw.py代码
# rw.py
import matplotlib.pyplot as plt
from randomwalk import RandomWalk
while True:
# 创建一个RandomWalk实例
rw = RandomWalk()
rw.fill_walk()
# 将所有点都绘制出来
plt.style.use('classic')
fig, ax = plt.subplots()
point_numbers = range(rw.num_points)
ax.scatter(rw.x_values, rw.y_values,c=point_numbers,cmap=plt.cm.Blues,edgecolor='none', s=15)
# 突出起点和终点
ax.scatter(0, 0, c='green', edgecolor='none', s=100)
ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none', s=100)
plt.show()
keep_running = input("Make another walk?(y/n): ")
if keep_running == 'n':
break
执行结果如下图:
3 隐藏坐标轴
修改rw.py代码,隐藏坐标轴
# rw.py
import matplotlib.pyplot as plt
from randomwalk import RandomWalk
while True:
# 创建一个RandomWalk实例
rw = RandomWalk()
rw.fill_walk()
# 将所有点都绘制出来
plt.style.use('classic')
fig, ax = plt.subplots()
point_numbers = range(rw.num_points)
ax.scatter(rw.x_values, rw.y_values,c=point_numbers,cmap=plt.cm.Blues,edgecolor='none', s=15)
# 突出起点和终点
ax.scatter(0, 0, c='green', edgecolor='none', s=100)
ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none', s=100)
# 隐藏坐标轴
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
keep_running = input("Make another walk?(y/n): ")
if keep_running == 'n':
break
执行后,如图:
4 增加点数
增加随机漫步的点数,只需在生成对象时传递一个较大的实参即可
# rw.py
import matplotlib.pyplot as plt
from randomwalk import RandomWalk
while True:
# 创建一个RandomWalk实例
rw = RandomWalk(50000)
rw.fill_walk()
# 将所有点都绘制出来
plt.style.use('classic')
fig, ax = plt.subplots()
point_numbers = range(rw.num_points)
ax.scatter(rw.x_values, rw.y_values,c=point_numbers,cmap=plt.cm.Blues,edgecolor='none', s=15)
# 突出起点和终点
ax.scatter(0, 0, c='green', edgecolor='none', s=100)
ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none', s=100)
# 隐藏坐标轴
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
keep_running = input("Make another walk?(y/n): ")
if keep_running == 'n':
break
执行结果如下图:
5 调整尺寸已适合屏幕
调整屏幕显示尺寸,需要调整plt.subplots()的参数
参数figsize=(10,6)表示在10X6英寸的屏幕上显示
参数dpi 默认值是100,表示分辨率
修改rw.py的代码,将生成实例时的实参去掉,还是按5000个点生成
# rw.py
import matplotlib.pyplot as plt
from randomwalk import RandomWalk
while True:
# 创建一个RandomWalk实例
rw = RandomWalk()
rw.fill_walk()
# 将所有点都绘制出来
plt.style.use('classic')
fig, ax = plt.subplots(figsize=(10,6), dpi=128)
point_numbers = range(rw.num_points)
ax.scatter(rw.x_values, rw.y_values,c=point_numbers,cmap=plt.cm.Blues,edgecolor='none', s=15)
# 突出起点和终点
ax.scatter(0, 0, c='green', edgecolor='none', s=100)
ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none', s=100)
# 隐藏坐标轴
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
keep_running = input("Make another walk?(y/n): ")
if keep_running == 'n':
break
执行程序后,显示如下图:
15.4 使用 Plotly 模拟掷色子
如果掷一个色子,出现1-6的几率时持平的,但是如果同时投掷两个色子,出现某些点数的可能性就会高,Plotly是一个python包,可以将数据绘成可交互图形
15.4.1 安装Plotly
Plotly 安装包安装速度很慢,使用 python -m install plotly 都会因为超时而失败
但如果使用镜像,命令为 python -m pip install http://pypi.douban.com/simple/ plotly 会出现无法解压的错误
以下是亲测有效的安装方法:
- win + r 输入 cmd 打开命令行窗口
- 输入 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn plotly
- 安装成功后 输入 python -> import plotly -> plotly.__ version__验证是否安装成功
如下图所示:
15.4.2 创建Die 类
创建Die类的 die.py模块如下所示:
# die.py
from random import randint
class Die:
'''表示一个色子的类'''
def __init__(self, num_sides=6):
'''色子默认为6面'''
self.num_sides = num_sides
def roll(self):
'''返回一个位于1-6的随机数'''
return randint(1, self.num_sides)
15.4.3 掷色子
创建一个实例,验证创建的类是否合理
在die_visual.py中编写代码
# die_visual.py
from die import Die
die = Die()
# 掷几次色子并将结果存在一个列表中
results = []
for roll_num in range(10):
result = die.roll()
results.append(result)
print(results)
掷色子10次,发现结果符合预期
如下图:
15.4.4 分析结果
掷1000次色子,计算每个点数出现的次数,并将出现的次数存在一个列表中
直接修改 die_visual.py的代码
# die_visual.py
from die import Die
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)
执行结果:
[162, 160, 177, 153, 182, 166]
15.4.5 绘制直方图
修改 die_visual.py文件
# die_visual.py
from plotly.graph_objs import Bar, Layout
from plotly import offline
from die import Die
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)) # x轴数据
data =[Bar(x=x_values, y=frequencies)] # 直方图数据
x_axis_config ={'title': '结果'} # x坐标轴标签
y_axis_config ={'title': '结果的频率'} # y坐标轴标签
#类Layout()返回一个指定图表布局和配置的对象
my_layout = Layout(title='掷一个D6色子 1000次的结果', xaxis=x_axis_config, yaxis=y_axis_config)
#函数offline.plot()第一个参数接受一个图表的数据和配置对象,第二个参数是一个生成要保存的图表
offline.plot({'data': data, 'layout': my_layout}, filename='d6.html')
执行程序,在浏览器生成一个直方图。见下图:
15.4.6 同时掷两个色子
同时掷两个色子,则横坐标数据就变为两个色子点数相加,结果仍然存在results列表中
重新创建一个dice_visual.py文件,将die_visual.py文件代码复制过来, 然后进行修改
# dice_visual.py
from plotly.graph_objs import Bar, Layout
from plotly import offline
from die import Die
#创建2个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)) # x轴数据
data =[Bar(x=x_values, y=frequencies)] # 直方图数据
x_axis_config ={'title': '结果', 'dtick': 1} # x坐标轴标签,'dtick'键为刻度间距,会让图形显示每个刻度值,即x坐标值
y_axis_config ={'title': '结果的频率'} # y坐标轴标签
#类Layout()返回一个指定图表布局和配置的对象
my_layout = Layout(title='掷2个D6色子 1000次的结果', xaxis=x_axis_config, yaxis=y_axis_config)
#函数offline.plot()第一个参数接受一个图表的数据和配置对象,第二个参数是一个生成要保存的图表
offline.plot({'data': data, 'layout': my_layout}, filename='d6_d6.html')
程序执行如下图:
15.4.7 同时掷两个面数不同的色子
同时掷一个6面和一个10面的色子,一共掷5000次,结果会如何?
新建一个dice_6_10_visual.py 文件,将dice_visual.py代码复制过来进行修改
# dice_6_10_visual.py
from plotly.graph_objs import Bar, Layout
from plotly import offline
from die import Die
#创建2个D6
die_1 = Die()
die_2 = Die(10)
# 掷几次色子并将结果存在一个列表中
results = []
for roll_num in range(5000):
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)) # x轴数据
data =[Bar(x=x_values, y=frequencies)] # 直方图数据
x_axis_config ={'title': '结果', 'dtick': 1} # x坐标轴标签,'dtick'键为刻度间距,会让图形显示每个刻度值,即x坐标值
y_axis_config ={'title': '结果的频率'} # y坐标轴标签
#类Layout()返回一个指定图表布局和配置的对象
my_layout = Layout(title='掷1个D6和1个D10色子 5000次的结果', xaxis=x_axis_config, yaxis=y_axis_config)
#函数offline.plot()第一个参数接受一个图表的数据和配置对象,第二个参数是一个生成要保存的图表
offline.plot({'data': data, 'layout': my_layout}, filename='d6_d10.html')
程序执行结果如下图:
15.5 小结
略