3Matplotlib
约 45359 字大约 151 分钟
2025-01-20
1. Matplotlib基础
1.1 Matplotlib简介
1.1.1 Matplotlib的功能与应用
Matplotlib 是一个用于Python编程语言的绘图库,广泛应用于数据可视化。它提供了丰富的绘图功能,能够生成高质量的静态、动态和交互式图表。Matplotlib的主要功能和应用包括:
- 数据可视化:创建各种类型的图表,如折线图、散点图、柱状图、直方图、饼图、箱线图等。
- 科学计算与工程绘图:在科学研究和工程领域,用于绘制实验数据、模拟结果等。
- 报告与展示:生成高质量的图形用于报告、论文和演示文稿中。
- 交互式应用:结合其他库(如Jupyter Notebook)实现交互式数据探索和分析。
Matplotlib的灵活性使其成为数据科学家、工程师和研究人员进行数据分析和可视化的首选工具之一。
1.1.2 Matplotlib的安装与配置
安装Matplotlib 可以通过多种方式完成,最常用的是使用Python的包管理工具pip
或conda
。以下是安装步骤:
使用pip安装:
pip install matplotlib
使用conda安装:
conda install matplotlib
验证安装:
安装完成后,可以通过以下Python代码验证是否安装成功:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [4, 5, 6])
plt.show()
如果能够正常显示一条简单的折线图,说明Matplotlib已成功安装。
配置Matplotlib:
Matplotlib允许用户通过matplotlibrc
配置文件自定义默认设置,如图表风格、字体、颜色等。配置文件可以放在用户主目录下的.matplotlib
文件夹中。
常见的配置选项包括:
图表风格:通过
plt.style.use()
加载预定义的样式(如ggplot
、seaborn
等)。import matplotlib matplotlib.use('TkAgg') # 使用 TkAgg 后端 import matplotlib.pyplot as plt plt.style.use('ggplot')
字体设置:通过
rcParams
设置默认字体、大小等。import matplotlib matplotlib.use('TkAgg') # 使用 TkAgg 后端 import matplotlib.pyplot as plt plt.rcParams['font.size'] = 12 plt.rcParams['font.family'] = 'Arial'
1.1.3 Matplotlib的基本结构
Matplotlib的基本绘图结构由以下几个核心组件组成:
- Figure(图形):整个图表的容器,可以包含多个子图(Axes)。
- Axes(子图):图形中的一个绘图区域,包含坐标轴、刻度和绘图元素。
- Axis(坐标轴):子图中的x轴和y轴,用于表示数据的尺度。
- Artist(艺术家):图形元素的基类,包括线条、文本、图例等。
面向对象的绘图方式:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 创建一个Figure和一个Axes
fig, ax = plt.subplots()
# 在Axes上绘图
ax.plot([1, 2, 3], [4, 5, 6])
# 显示图形
plt.show()
状态管理的绘图方式(常用且简单):
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [4, 5, 6])
plt.show()
面向对象的方式更适合复杂图形的创建和定制,而状态管理方式更适合快速绘图和简单应用。
1.2 绘制简单图形
1.2.1 绘制基本折线图
折线图是最常见的图表类型之一,用于展示数据点的变化趋势。使用plt.plot()
函数可以轻松绘制折线图。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 数据
x = [1, 2, 3, 4, 5]
y = [2, 3, 5, 7, 11]
# 绘制折线图
plt.plot(x, y)
# 显示图形
plt.show()
输出效果:
1.2.2 设置图表标题、标签和图例
通过添加标题、坐标轴标签和图例,可以使图表更具可读性和信息量。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 数据
x = [1, 2, 3, 4, 5]
y1 = [2, 3, 5, 7, 11]
y2 = [1, 4, 6, 8, 10]
# 绘制折线图
plt.plot(x, y1, label='Prime Numbers')
plt.plot(x, y2, label='Even Numbers')
# 设置标题和标签
plt.title('Sample Line Plot')
plt.xlabel('X-axis Label')
plt.ylabel('Y-axis Label')
# 显示图例
plt.legend()
# 显示图形
plt.show()
输出效果:
1.2.3 修改坐标轴范围
通过设置坐标轴的范围,可以更好地控制图表的显示区域。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 数据
x = [1, 2, 3, 4, 5]
y = [2, 3, 5, 7, 11]
# 绘制折线图
plt.plot(x, y)
# 设置坐标轴范围
plt.xlim(0, 6)
plt.ylim(0, 12)
# 设置标题和标签
plt.title('Line Plot with Custom Axes')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
# 显示图形
plt.show()
输出效果:
1.2.4 控制线条样式、颜色和宽度
通过调整线条的样式、颜色和宽度,可以增强图表的视觉效果和信息表达。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 数据
x = [1, 2, 3, 4, 5]
y1 = [2, 3, 5, 7, 11]
y2 = [1, 4, 6, 8, 10]
# 绘制折线图,设置线条样式、颜色和宽度
plt.plot(x, y1, linestyle='--', color='r', linewidth=2, label='Prime Numbers')
plt.plot(x, y2, linestyle='-', color='b', linewidth=1, label='Even Numbers')
# 设置标题和标签
plt.title('Customized Line Styles')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
# 显示图例
plt.legend()
# 显示图形
plt.show()
输出效果:
常用的线条样式和颜色:
- 线条样式(linestyle):
'-'
或'solid'
:实线'--'
或'dashed'
:虚线'-.'
或'dashdot'
:点划线':'
或'dotted'
:点线
- 颜色(color):
- 名称:
'red'
,'blue'
,'green'
等 - 简写:
'r'
,'b'
,'g'
等 - 十六进制:
'#FF5733'
等 - RGB元组:
(0.1, 0.2, 0.5)
- 名称:
1.3 使用Pyplot模块
1.3.1 理解Pyplot的函数(plt.plot()
, plt.figure()
等)
Pyplot 是Matplotlib的一个子模块,提供了类似MATLAB的绘图接口,使绘图过程更加简洁和直观。以下是一些常用的Pyplot函数及其功能:
plt.plot()
:绘制折线图或散点图。plt.figure()
:创建一个新的图形对象,或获取当前图形对象。plt.subplot()
:在一个图形中创建多个子图。plt.title()
:设置图表的标题。plt.xlabel()
和plt.ylabel()
:设置x轴和y轴的标签。plt.legend()
:显示图例。plt.grid()
:添加网格线。plt.xlim()
和plt.ylim()
:设置x轴和y轴的显示范围。plt.savefig()
:将当前图形保存为文件。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 创建一个新的图形
plt.figure(figsize=(8, 6))
# 绘制折线图
plt.plot([1, 2, 3], [4, 5, 6], label='Line 1')
# 设置标题和标签
plt.title('Understanding Pyplot Functions')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
# 显示图例
plt.legend()
# 显示图形
plt.show()
1.3.2 创建与显示图形(plt.show()
)
plt.show()
是用于显示所有绘制的图形。它会阻塞代码执行,直到所有图形窗口被关闭。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 数据
x = [0, 1, 2, 3, 4]
y = [0, 1, 4, 9, 16]
# 创建一个图形
plt.figure()
# 绘制折线图
plt.plot(x, y, marker='o')
# 设置标题和标签
plt.title('Quadratic Function')
plt.xlabel('X')
plt.ylabel('Y')
# 显示图形
plt.show()
输出效果:
注意事项:
- 在一些交互式环境(如Jupyter Notebook)中,图形可能会自动显示,无需显式调用
plt.show()
。 - 如果在脚本中多次调用
plt.show()
,每次调用后会生成一个新的图形窗口。
1.3.3 保存图形(plt.savefig()
)
plt.savefig()
用于将当前图形保存为文件,支持多种格式,如PNG、JPEG、SVG、PDF等。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 数据
x = [1, 2, 3, 4, 5]
y = [10, 20, 25, 30, 40]
# 绘制折线图
plt.plot(x, y, marker='s', linestyle='--', color='g', label='Growth')
# 设置标题和标签
plt.title('Growth Over Time')
plt.xlabel('Time (years)')
plt.ylabel('Growth (%)')
# 显示图例
plt.legend()
# 保存图形为PNG格式
plt.savefig('growth_over_time.png')
# 保存图形为PDF格式
plt.savefig('growth_over_time.pdf')
# 显示图形
plt.show()
输出效果:
上述代码将生成并保存两个文件:growth_over_time.png
和 growth_over_time.pdf
,同时在屏幕上显示图形。
常用参数:
fname
:文件名或路径。dpi
:分辨率,默认为100。format
:保存的文件格式,可以根据文件名自动推断。bbox_inches
:图形边界,通常设置为'tight'
以减少空白区域。transparent
:是否保存透明背景,布尔值。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [4, 5, 6])
# 以300 DPI的分辨率保存图形,紧凑边界并使用透明背景
plt.savefig('plot.png', dpi=300, bbox_inches='tight', transparent=True)
这将以300 DPI的分辨率保存图形,紧凑边界并使用透明背景。
2. 图表定制
图表定制是创建具有高可读性和专业外观的图表的关键步骤。通过定制图形、坐标轴、标题、标签和图形样式,可以更好地展示数据的特点和趋势。以下内容将详细介绍如何进行图表定制。
2.1 图形与坐标轴
图形与坐标轴的定制是控制图表布局和数据展示的重要部分。以下小节将介绍如何创建多个子图、调整图形大小、自定义坐标轴以及使用对数坐标轴。
2.1.1 创建多个子图(plt.subplot()
, plt.subplots()
)
创建多个子图可以在一个图形窗口中展示多个图表,便于比较和分析不同的数据集。Matplotlib提供了两种主要的方法来创建子图:plt.subplot()
和plt.subplots()
。
使用 plt.subplot()
创建子图
plt.subplot()
允许你在一个图形中创建一个网格,并在指定的位置绘制子图。其语法为 plt.subplot(nrows, ncols, index)
,其中 nrows
和 ncols
定义网格的行数和列数,index
指定当前子图的位置。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 创建一个2x2的子图网格
plt.figure(figsize=(10, 8))
# 第一个子图
plt.subplot(2, 2, 1)
plt.plot([1, 2, 3], [4, 5, 6])
plt.title('子图 1')
# 第二个子图
plt.subplot(2, 2, 2)
plt.scatter([1, 2, 3], [4, 5, 6])
plt.title('子图 2')
# 第三个子图
plt.subplot(2, 2, 3)
plt.bar(['A', 'B', 'C'], [5, 7, 3])
plt.title('子图 3')
# 第四个子图
plt.subplot(2, 2, 4)
plt.hist([1, 2, 2, 3, 3, 3, 4, 4, 4, 4], bins=4)
plt.title('子图 4')
# 调整布局
plt.tight_layout()
# 显示图形
plt.show()
输出效果:
使用 plt.subplots()
创建子图
plt.subplots()
是一种更为灵活和现代的方法,用于创建子图。它返回一个 Figure
对象和一个包含所有 Axes
对象的数组,便于后续的操作和定制。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 创建一个2x2的子图网格
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
# 绘制第一个子图
axes[0, 0].plot([1, 2, 3], [4, 5, 6])
axes[0, 0].set_title('子图 1')
# 绘制第二个子图
axes[0, 1].scatter([1, 2, 3], [4, 5, 6])
axes[0, 1].set_title('子图 2')
# 绘制第三个子图
axes[1, 0].bar(['A', 'B', 'C'], [5, 7, 3])
axes[1, 0].set_title('子图 3')
# 绘制第四个子图
axes[1, 1].hist([1, 2, 2, 3, 3, 3, 4, 4, 4, 4], bins=4)
axes[1, 1].set_title('子图 4')
# 调整布局
plt.tight_layout()
# 显示图形
plt.show()
输出效果:
2.1.2 调整图形大小(figsize
)
调整图形大小可以确保图表在不同展示环境中具有良好的可读性和布局。Matplotlib允许通过 figsize
参数来设置图形的宽度和高度。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 设置图形大小为12x6英寸
plt.figure(figsize=(12, 6))
# 绘制折线图
plt.plot([0, 1, 2, 3], [0, 1, 4, 9], marker='o')
# 设置标题和标签
plt.title('调整图形大小示例')
plt.xlabel('X轴')
plt.ylabel('Y轴')
# 显示图形
plt.show()
输出效果:
使用 plt.subplots()
设置图形大小
同样,使用 plt.subplots()
时也可以通过 figsize
参数设置图形大小。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 创建一个图形,设置大小为10x5英寸
fig, ax = plt.subplots(figsize=(10, 5))
# 绘制散点图
ax.scatter([1, 2, 3, 4, 5], [10, 20, 25, 30, 40], color='green')
# 设置标题和标签
ax.set_title('调整图形大小的另一个示例')
ax.set_xlabel('时间 (年)')
ax.set_ylabel('增长 (%)')
# 显示图形
plt.show()
输出效果:
2.1.3 自定义坐标轴(ax.set()
)
自定义坐标轴可以包括设置坐标轴的标签、范围、刻度等,以更好地展示数据。通过 ax.set()
方法,可以同时设置多个坐标轴属性。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 数据
x = [1, 2, 3, 4, 5]
y = [2, 3, 5, 7, 11]
# 绘制折线图
ax.plot(x, y, marker='o', linestyle='-', color='b')
# 自定义坐标轴
ax.set(
title='自定义坐标轴示例',
xlabel='自定义 X 轴标签',
ylabel='自定义 Y 轴标签',
xlim=(0, 6),
ylim=(0, 12),
xticks=[0, 1, 2, 3, 4, 5, 6],
yticks=[0, 2, 4, 6, 8, 10, 12]
)
# 显示图形
plt.show()
输出效果:
更多坐标轴定制示例:
隐藏坐标轴线:
import matplotlib matplotlib.use('TkAgg') # 使用 TkAgg 后端 import matplotlib.pyplot as plt # 全局设置中文字体和负号显示 plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体 plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题 fig, ax = plt.subplots(figsize=(8, 6)) ax.plot([1, 2, 3], [4, 5, 6]) # 隐藏顶部和右侧的坐标轴线 ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) # 仅显示底部和左侧的坐标轴线 ax.spines['bottom'].set_position('zero') ax.spines['left'].set_position('zero') plt.title('隐藏部分坐标轴线') plt.show()
输出效果:
自定义刻度标签:
import matplotlib matplotlib.use('TkAgg') # 使用 TkAgg 后端 import matplotlib.pyplot as plt # 全局设置中文字体和负号显示 plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体 plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题 fig, ax = plt.subplots(figsize=(8, 6)) ax.plot([0, 1, 2, 3], [0, 1, 4, 9]) # 设置自定义的刻度标签 ax.set_xticks([0, 1, 2, 3]) ax.set_xticklabels(['零', '一', '二', '三']) ax.set_yticks([0, 1, 4, 9]) ax.set_yticklabels(['零', '一', '四', '九']) plt.title('自定义刻度标签示例') plt.show()
输出效果:
2.1.4 使用对数坐标轴和自定义坐标轴
对数坐标轴用于展示跨越多个数量级的数据,能够更好地显示指数增长或幂律分布的数据。Matplotlib提供了设置对数坐标轴的方法。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 生成指数增长数据
x = np.linspace(1, 10, 100)
y = np.exp(x)
# 绘制折线图
ax.plot(x, y, label='指数增长')
# 设置对数坐标轴
ax.set_yscale('log')
# 设置标题和标签
ax.set_title('对数坐标轴示例')
ax.set_xlabel('X轴')
ax.set_ylabel('对数 Y轴')
# 显示图例
ax.legend()
# 显示图形
plt.show()
输出效果:
更多对数坐标轴示例:
双对数坐标轴(Log-Log Scale):
import matplotlib matplotlib.use('TkAgg') # 使用 TkAgg 后端 import matplotlib.pyplot as plt import numpy as np # 全局设置中文字体和负号显示 plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体 plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题 # 创建图形和子图 fig, ax = plt.subplots(figsize=(8, 6)) # 生成数据 x = np.logspace(0.1, 2, 100) y = x ** 2 # 绘制折线图 ax.plot(x, y, label='y = x^2') # 设置双对数坐标轴 ax.set_xscale('log') ax.set_yscale('log') # 设置标题和标签 ax.set_title('双对数坐标轴示例') ax.set_xlabel('对数 X轴') ax.set_ylabel('对数 Y轴') # 显示图例 ax.legend() # 显示图形 plt.show()
输出效果:
半对数坐标轴(Semi-Log Scale):
import matplotlib matplotlib.use('TkAgg') # 使用 TkAgg 后端 import matplotlib.pyplot as plt import numpy as np # 全局设置中文字体和负号显示 plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体 plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题 # 创建图形和子图 fig, ax = plt.subplots(figsize=(8, 6)) # 生成数据 x = np.linspace(1, 10, 100) y = np.exp(x) # 绘制折线图 ax.plot(x, y, label='指数增长') # 设置半对数坐标轴(y轴对数) ax.set_yscale('log') # 设置标题和标签 ax.set_title('半对数坐标轴示例 (y轴对数)') ax.set_xlabel('X轴') ax.set_ylabel('对数 Y轴') # 显示图例 ax.legend() # 显示图形 plt.show()
输出效果:
2.2 标题与标签
添加和定制标题、标签和图例可以显著提高图表的可读性和信息传达效果。以下小节将介绍如何添加标题与标签、设置图例以及自定义标题和标签的字体、大小与样式。
2.2.1 添加标题与标签(plt.title()
, plt.xlabel()
, plt.ylabel()
)
标题和标签用于描述图表的整体内容和各个坐标轴的数据含义,是数据可视化中不可或缺的部分。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 数据
x = [0, 1, 2, 3, 4, 5]
y = [0, 1, 4, 9, 16, 25]
# 绘制折线图
ax.plot(x, y, marker='o', linestyle='-', color='purple')
# 添加标题和标签
ax.set_title('抛物线示例')
ax.set_xlabel('时间 (秒)')
ax.set_ylabel('位移 (米)')
# 显示图形
plt.show()
输出效果:
2.2.2 设置图例(plt.legend()
)
图例用于标识图表中不同的数据系列,使读者能够快速理解各条线条或图形元素所代表的数据。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 数据
x = [1, 2, 3, 4, 5]
y1 = [2, 3, 5, 7, 11]
y2 = [1, 4, 6, 8, 10]
# 绘制折线图,并添加标签
ax.plot(x, y1, label='质数', marker='o', linestyle='-', color='blue')
ax.plot(x, y2, label='偶数', marker='s', linestyle='--', color='red')
# 添加标题和标签
ax.set_title('质数与偶数比较')
ax.set_xlabel('数字')
ax.set_ylabel('值')
# 添加图例
ax.legend()
# 显示图形
plt.show()
输出效果:
图例的位置和样式:
你可以通过 loc
参数来指定图例的位置,例如 'upper left'
、'lower right'
等。此外,还可以调整图例的字体大小和框架样式。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
fig, ax = plt.subplots(figsize=(8, 6))
x = [1, 2, 3, 4, 5]
y1 = [2, 3, 5, 7, 11]
y2 = [1, 4, 6, 8, 10]
ax.plot(x, y1, label='质数', marker='o', linestyle='-', color='blue')
ax.plot(x, y2, label='偶数', marker='s', linestyle='--', color='red')
ax.set_title('质数与偶数比较')
ax.set_xlabel('数字')
ax.set_ylabel('值')
# 设置图例的位置为右上角,字体大小为12,无边框
ax.legend(loc='upper right', fontsize=12, frameon=False)
plt.show()
输出效果:
2.2.3 设置标题、标签的字体、大小与样式
通过自定义标题和标签的字体、大小和样式,可以使图表更加美观和专业。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
fig, ax = plt.subplots(figsize=(8, 6))
x = [0, 1, 2, 3, 4, 5]
y = [0, 1, 4, 9, 16, 25]
ax.plot(x, y, marker='o', linestyle='-', color='green')
# 设置标题和标签,调整字体、大小和样式
ax.set_title('抛物线示例', fontsize=16, fontweight='bold', fontfamily='serif')
ax.set_xlabel('时间 (秒)', fontsize=14, color='darkblue')
ax.set_ylabel('位移 (米)', fontsize=14, color='darkblue')
# 自定义刻度标签字体大小
ax.tick_params(axis='both', which='major', labelsize=12)
plt.show()
输出效果:
更多字体和样式定制:
使用斜体和粗体:
ax.set_title('斜体标题', fontsize=16, fontstyle='italic') ax.set_xlabel('斜体标签', fontsize=14, fontstyle='italic')
更改字体颜色:
ax.set_ylabel('彩色标签', fontsize=14, color='purple')
使用不同的字体家族:
ax.set_title('不同字体家族', fontsize=16, fontfamily='Comic Sans MS')
2.3 图形样式
图形样式的定制包括更改线条样式、颜色、宽度,以及调整图形的背景和网格样式。这些定制可以使图表更具视觉吸引力和信息表达力。
2.3.1 更改线条样式(实线、虚线、点线等)
Matplotlib允许通过 linestyle
参数更改线条的样式,以区分不同的数据系列或强调特定的趋势。
常用的线条样式:
'-'
或'solid'
:实线'--'
或'dashed'
:虚线'-.'
或'dashdot'
:点划线':'
或'dotted'
:点线
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
fig, ax = plt.subplots(figsize=(8, 6))
x = [0, 1, 2, 3, 4, 5]
y1 = [0, 1, 4, 9, 16, 25]
y2 = [25, 16, 9, 4, 1, 0]
# 绘制不同线条样式的折线图
ax.plot(x, y1, linestyle='-', label='实线', color='blue')
ax.plot(x, y2, linestyle='--', label='虚线', color='red')
ax.plot(x, [y + 5 for y in y1], linestyle='-.', label='点划线', color='green')
ax.plot(x, [y - 5 for y in y2], linestyle=':', label='点线', color='purple')
# 设置标题和标签
ax.set_title('不同线条样式示例')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
# 添加图例
ax.legend()
# 显示图形
plt.show()
输出效果:
2.3.2 设置线条颜色与宽度
调整线条的颜色和宽度可以增强图表的对比度和可读性,突出显示关键数据。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
fig, ax = plt.subplots(figsize=(8, 6))
x = [0, 1, 2, 3, 4, 5]
y = [0, 1, 4, 9, 16, 25]
# 绘制不同颜色和宽度的折线图
ax.plot(x, y, color='orange', linewidth=3, label='较粗的线条')
ax.plot(x, [val + 5 for val in y], color='cyan', linewidth=1, label='较细的线条')
# 设置标题和标签
ax.set_title('线条颜色与宽度示例')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
# 添加图例
ax.legend()
# 显示图形
plt.show()
输出效果:
更多颜色设置方法:
使用颜色名称:
ax.plot(x, y, color='magenta')
使用简写颜色代码:
ax.plot(x, y, color='k') # 黑色
使用十六进制颜色代码:
ax.plot(x, y, color='#FF5733')
使用RGB元组:
ax.plot(x, y, color=(0.1, 0.2, 0.5))
2.3.3 更改图形背景、网格样式
图形背景和网格样式的定制可以提高图表的可读性,帮助读者更好地理解数据分布和趋势。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
fig, ax = plt.subplots(figsize=(8, 6))
x = [0, 1, 2, 3, 4, 5]
y = [0, 1, 4, 9, 16, 25]
# 绘制折线图
ax.plot(x, y, marker='o', linestyle='-', color='blue')
# 更改图形背景颜色
fig.patch.set_facecolor('lightgray')
# 更改子图背景颜色
ax.set_facecolor('whitesmoke')
# 添加网格线,设置网格线样式
ax.grid(True, which='both', linestyle='--', linewidth=0.5, color='gray', alpha=0.7)
# 设置标题和标签
ax.set_title('图形背景与网格样式示例')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
plt.show()
输出效果:
更多背景和网格样式定制:
隐藏网格线:
ax.grid(False)
仅显示主网格线或次网格线:
ax.grid(True, which='major') # 仅显示主网格线 ax.grid(True, which='minor') # 仅显示次网格线
自定义网格线颜色和透明度:
ax.grid(True, color='red', alpha=0.3)
设置网格线为主要刻度线:
ax.minorticks_on() ax.grid(which='both', linestyle=':', linewidth='0.5', color='black')
3. 绘制各种图像
在数据可视化过程中,不同类型的图表适用于展示不同类型的数据和信息。Matplotlib提供了丰富的图表类型,包括线形图、散点图、柱状图、直方图、饼图和箱线图等。以下内容将详细介绍如何使用Matplotlib绘制各种图像,并通过多个示例代码深入理解每种图表的绘制方法和定制技巧。
3.1 线形图(Line Plot)
线形图是最基本也是最常用的图表类型之一,用于展示数据随时间或其他连续变量的变化趋势。以下小节将介绍如何绘制基本线形图、绘制多条线以及自定义坐标轴范围。
3.1.1 绘制基本线形图
绘制基本线形图是使用Matplotlib进行数据可视化的起点。通过简单的ax.plot()
方法,可以快速展示数据的趋势。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 数据
x = [0, 1, 2, 3, 4, 5]
y = [0, 1, 4, 9, 16, 25]
# 绘制基本线形图
ax.plot(x, y, marker='o', linestyle='-', color='blue', label='平方数')
# 添加标题和标签
ax.set_title('基本线形图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴', fontsize=14)
ax.set_ylabel('Y轴', fontsize=14)
# 添加图例
ax.legend()
# 显示图形
plt.show()
代码说明:
- 导入和配置:
- 导入
matplotlib
并设置后端为TkAgg
。 - 配置全局中文字体和负号显示,避免中文乱码和负号显示问题。
- 导入
- 创建图形:
- 使用
plt.subplots()
创建一个图形和子图,设置图形大小为8x6英寸。
- 使用
- 数据准备:
- 定义
x
和y
两个列表,分别表示横轴和纵轴的数据。
- 定义
- 绘制线形图:
- 使用
ax.plot()
方法绘制线形图,设置标记样式为圆圈(marker='o'
)、线条样式为实线(linestyle='-'
)、颜色为蓝色(color='blue'
),并添加标签label='平方数'
用于图例显示。
- 使用
- 添加标题和标签:
- 使用
ax.set_title()
设置图表标题,ax.set_xlabel()
和ax.set_ylabel()
设置横轴和纵轴的标签。
- 使用
- 添加图例:
- 使用
ax.legend()
显示图例。
- 使用
- 显示图形:
- 使用
plt.show()
显示绘制的图形。
- 使用
3.1.2 绘制多条线
在一个图表中绘制多条线,可以用于比较不同数据系列的趋势。通过多次调用ax.plot()
方法,可以在同一个坐标轴上绘制多条线。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 数据
x = [1, 2, 3, 4, 5]
y1 = [2, 3, 5, 7, 11] # 质数
y2 = [1, 4, 6, 8, 10] # 偶数
y3 = [1, 8, 27, 64, 125] # 立方数
# 绘制多条线
ax.plot(x, y1, marker='o', linestyle='-', color='green', label='质数')
ax.plot(x, y2, marker='s', linestyle='--', color='red', label='偶数')
ax.plot(x, y3, marker='^', linestyle='-.', color='blue', label='立方数')
# 添加标题和标签
ax.set_title('多条线形图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴', fontsize=14)
ax.set_ylabel('Y轴', fontsize=14)
# 添加图例
ax.legend()
# 显示图形
plt.show()
代码说明:
- 数据准备:
- 定义三个数据系列
y1
、y2
和y3
,分别代表质数、偶数和立方数。
- 定义三个数据系列
- 绘制多条线:
- 分别调用
ax.plot()
方法绘制三条线,使用不同的标记样式、线条样式和颜色,以区分不同的数据系列。
- 分别调用
- 图例区分:
- 每条线都设置了
label
参数,用于在图例中标识不同的数据系列。
- 每条线都设置了
3.1.3 自定义坐标轴范围
通过自定义坐标轴的范围,可以更好地控制图表的显示区域,突出特定的数据范围。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 数据
x = [0, 1, 2, 3, 4, 5, 6]
y = [0, 1, 4, 9, 16, 25, 36]
# 绘制线形图
ax.plot(x, y, marker='o', linestyle='-', color='purple', label='平方数')
# 自定义坐标轴范围
ax.set_xlim(-1, 7) # 设置X轴范围
ax.set_ylim(-5, 40) # 设置Y轴范围
# 添加标题和标签
ax.set_title('自定义坐标轴范围示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴', fontsize=14)
ax.set_ylabel('Y轴', fontsize=14)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5, color='gray')
# 添加图例
ax.legend()
# 显示图形
plt.show()
代码说明:
- 自定义坐标轴范围:
- 使用
ax.set_xlim()
和ax.set_ylim()
方法分别设置横轴和纵轴的显示范围。 - 例如,
ax.set_xlim(-1, 7)
将X轴范围设置为-1到7,ax.set_ylim(-5, 40)
将Y轴范围设置为-5到40。
- 使用
- 添加网格线:
- 使用
ax.grid()
方法添加网格线,并自定义网格线的样式,包括线条样式、宽度和颜色。
- 使用
3.2 散点图(Scatter Plot)
散点图用于展示两个变量之间的关系,适合用于观察数据的分布和相关性。Matplotlib的ax.scatter()
方法提供了丰富的定制选项。
3.2.1 绘制基础散点图
基础散点图用于展示数据点的分布情况,适用于观察变量之间的相关性。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 数据
x = [5, 7, 8, 7, 2, 17, 2, 9, 4, 11, 12, 9, 6]
y = [99, 86, 87, 88, 100, 86, 103, 87, 94, 78, 77, 85, 86]
# 绘制基础散点图
ax.scatter(x, y, label='学生分数')
# 添加标题和标签
ax.set_title('基础散点图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('数学成绩', fontsize=14)
ax.set_ylabel('语文成绩', fontsize=14)
# 添加图例
ax.legend()
# 显示图形
plt.show()
代码说明:
- 数据准备:
- 定义
x
和y
两个列表,分别表示数学成绩和语文成绩。
- 定义
- 绘制散点图:
- 使用
ax.scatter()
方法绘制散点图,label='学生分数'
用于图例标识。
- 使用
- 添加标题和标签:
- 使用
ax.set_title()
设置图表标题,ax.set_xlabel()
和ax.set_ylabel()
设置横轴和纵轴的标签。
- 使用
3.2.2 设置点的大小、颜色和透明度
通过设置散点的大小、颜色和透明度,可以更好地展示数据的特征和分布密度。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 数据
x = [5, 7, 8, 7, 2, 17, 2, 9, 4, 11, 12, 9, 6]
y = [99, 86, 87, 88, 100, 86, 103, 87, 94, 78, 77, 85, 86]
sizes = [20, 50, 80, 200, 160, 20, 50, 80, 200, 160, 20, 50, 80]
colors = ['red', 'blue', 'green', 'purple', 'orange', 'cyan', 'magenta', 'yellow', 'black', 'gray', 'brown', 'pink', 'lime']
# 绘制散点图,设置大小、颜色和透明度
scatter = ax.scatter(x, y, s=sizes, c=colors, alpha=0.6, edgecolors='w', linewidth=0.5, label='学生分数')
# 添加标题和标签
ax.set_title('设置点的大小、颜色与透明度示例', fontsize=16, fontweight='bold')
ax.set_xlabel('数学成绩', fontsize=14)
ax.set_ylabel('语文成绩', fontsize=14)
# 添加图例
ax.legend()
# 显示图形
plt.show()
代码说明:
数据准备:
- 除了
x
和y
,还定义了sizes
和colors
列表,用于设置每个点的大小和颜色。
- 除了
绘制散点图:
使用
ax.scatter()
方法绘制散点图,参数说明:
s=sizes
:设置每个点的大小。c=colors
:设置每个点的颜色。alpha=0.6
:设置点的透明度,范围为0到1。edgecolors='w'
:设置点的边框颜色为白色。linewidth=0.5
:设置点边框的线宽。
添加标题和标签:
- 使用
ax.set_title()
、ax.set_xlabel()
和ax.set_ylabel()
设置图表标题和轴标签。
- 使用
添加图例:
- 使用
ax.legend()
显示图例。
- 使用
3.2.3 绘制回归线与拟合曲线
在散点图中添加回归线或拟合曲线,可以更清晰地展示数据的趋势和相关性。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 数据
x = np.array([5, 7, 8, 7, 2, 17, 2, 9, 4, 11, 12, 9, 6])
y = np.array([99, 86, 87, 88, 100, 86, 103, 87, 94, 78, 77, 85, 86])
# 绘制散点图
ax.scatter(x, y, label='学生分数', color='blue', alpha=0.6)
# 计算回归线
slope, intercept = np.polyfit(x, y, 1)
regression_line = slope * x + intercept
# 绘制回归线
ax.plot(x, regression_line, color='red', linewidth=2, label='回归线')
# 计算拟合曲线(二次多项式)
coefficients = np.polyfit(x, y, 2)
poly_fit = np.poly1d(coefficients)
x_fit = np.linspace(min(x), max(x), 100)
y_fit = poly_fit(x_fit)
# 绘制拟合曲线
ax.plot(x_fit, y_fit, color='green', linestyle='--', linewidth=2, label='拟合曲线(二次)')
# 添加标题和标签
ax.set_title('绘制回归线与拟合曲线示例', fontsize=16, fontweight='bold')
ax.set_xlabel('数学成绩', fontsize=14)
ax.set_ylabel('语文成绩', fontsize=14)
# 添加图例
ax.legend()
# 显示图形
plt.show()
代码说明:
- 数据准备:
- 使用
numpy
数组x
和y
表示数学成绩和语文成绩。
- 使用
- 绘制散点图:
- 使用
ax.scatter()
方法绘制散点图。
- 使用
- 计算和绘制回归线:
- 使用
numpy.polyfit(x, y, 1)
计算一元线性回归的斜率和截距。 - 根据回归方程
y = slope * x + intercept
计算回归线的y值。 - 使用
ax.plot()
方法绘制回归线。
- 使用
- 计算和绘制拟合曲线(二次多项式):
- 使用
numpy.polyfit(x, y, 2)
计算二次多项式的系数。 - 创建多项式函数
poly_fit
。 - 生成更密集的x值
x_fit
,并计算对应的y值y_fit
。 - 使用
ax.plot()
方法绘制拟合曲线。
- 使用
- 添加标题、标签和图例:
- 设置图表标题和轴标签。
- 使用
ax.legend()
显示图例,区分散点图、回归线和拟合曲线。
3.3 柱状图(Bar Plot)
柱状图用于展示分类数据的比较,适合用于展示不同类别的数量、频率或其他指标的差异。Matplotlib的ax.bar()
方法提供了绘制柱状图的功能。
3.3.1 绘制基本柱状图(垂直/水平)
柱状图可以是垂直的,也可以是水平的,用于展示不同类别的数据比较。
示例代码(垂直柱状图):
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 数据
categories = ['苹果', '香蕉', '樱桃', '日期', '葡萄']
values = [20, 35, 30, 35, 27]
# 绘制垂直柱状图
ax.bar(categories, values, color='skyblue', edgecolor='black')
# 添加标题和标签
ax.set_title('基本垂直柱状图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('水果种类', fontsize=14)
ax.set_ylabel('销售量', fontsize=14)
# 显示图形
plt.show()
示例代码(水平柱状图):
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 数据
categories = ['苹果', '香蕉', '樱桃', '日期', '葡萄']
values = [20, 35, 30, 35, 27]
# 绘制水平柱状图
ax.barh(categories, values, color='lightgreen', edgecolor='black')
# 添加标题和标签
ax.set_title('基本水平柱状图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('销售量', fontsize=14)
ax.set_ylabel('水果种类', fontsize=14)
# 显示图形
plt.show()
代码说明:
- 数据准备:
- 定义
categories
列表表示水果种类,values
列表表示对应的销售量。
- 定义
- 绘制柱状图:
- 使用
ax.bar()
方法绘制垂直柱状图。 - 使用
ax.barh()
方法绘制水平柱状图。 - 设置柱子的颜色和边框颜色。
- 使用
- 添加标题和标签:
- 使用
ax.set_title()
设置图表标题,ax.set_xlabel()
和ax.set_ylabel()
设置轴标签。
- 使用
3.3.2 绘制分组柱状图
分组柱状图用于比较多个数据系列在不同类别上的表现,适合用于展示不同组别之间的对比。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 7))
# 数据
categories = ['2018', '2019', '2020', '2021', '2022']
group1 = [20, 35, 30, 35, 27]
group2 = [25, 32, 34, 20, 25]
# 设置柱状图的位置
x = np.arange(len(categories)) # 类别位置
width = 0.35 # 柱子的宽度
# 绘制分组柱状图
rects1 = ax.bar(x - width/2, group1, width, label='A组', color='lightblue', edgecolor='black')
rects2 = ax.bar(x + width/2, group2, width, label='B组', color='salmon', edgecolor='black')
# 添加标题和标签
ax.set_title('分组柱状图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('年份', fontsize=14)
ax.set_ylabel('销售量', fontsize=14)
ax.set_xticks(x)
ax.set_xticklabels(categories)
# 添加图例
ax.legend()
# 添加数据标签
def autolabel(rects):
"""在柱状图上添加数据标签"""
for rect in rects:
height = rect.get_height()
ax.annotate('{}'.format(height),
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3), # 3 points vertical offset
textcoords="offset points",
ha='center', va='bottom', fontsize=12)
autolabel(rects1)
autolabel(rects2)
# 显示图形
plt.show()
代码说明:
- 数据准备:
- 定义两个数据系列
group1
和group2
,分别代表A组和B组在不同年份的销售量。
- 定义两个数据系列
- 设置柱状图位置:
- 使用
numpy.arange()
生成类别的位置。 - 定义柱子的宽度
width
。
- 使用
- 绘制分组柱状图:
- 使用
ax.bar()
方法分别绘制A组和B组的柱状图,调整柱子的位置以实现分组效果。
- 使用
- 添加数据标签:
- 定义
autolabel()
函数,在每个柱子上方添加数据标签,显示具体数值。
- 定义
- 添加标题、标签和图例:
- 设置图表标题和轴标签。
- 使用
ax.legend()
显示图例,区分A组和B组。
3.3.3 绘制堆积柱状图
堆积柱状图用于展示多个数据系列在同一类别上的累积值,适合用于展示部分与整体的关系。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 7))
# 数据
categories = ['第一季度', '第二季度', '第三季度', '第四季度']
group1 = [15, 25, 35, 45] # 产品A
group2 = [10, 20, 25, 30] # 产品B
group3 = [5, 15, 20, 25] # 产品C
# 绘制堆积柱状图
ax.bar(categories, group1, label='产品A', color='skyblue', edgecolor='black')
ax.bar(categories, group2, bottom=group1, label='产品B', color='lightgreen', edgecolor='black')
bottom_group = np.array(group1) + np.array(group2)
ax.bar(categories, group3, bottom=bottom_group, label='产品C', color='salmon', edgecolor='black')
# 添加标题和标签
ax.set_title('堆积柱状图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('季度', fontsize=14)
ax.set_ylabel('销售量', fontsize=14)
# 添加图例
ax.legend()
# 添加数据标签
def autolabel_stacked(ax, categories, group1, group2, group3):
"""在堆积柱状图上添加数据标签"""
for i, category in enumerate(categories):
total = group1[i] + group2[i] + group3[i]
ax.text(i, total + 1, str(total), ha='center', va='bottom', fontsize=12)
autolabel_stacked(ax, categories, group1, group2, group3)
# 显示图形
plt.show()
代码说明:
- 数据准备:
- 定义三个数据系列
group1
、group2
和group3
,分别代表产品A、产品B和产品C在不同季度的销售量。
- 定义三个数据系列
- 绘制堆积柱状图:
- 使用
ax.bar()
方法绘制产品A的柱状图。 - 使用
bottom
参数绘制产品B的柱状图,堆叠在产品A之上。 - 计算堆叠的底部位置
bottom_group
,绘制产品C的柱状图,堆叠在产品A和产品B之上。
- 使用
- 添加数据标签:
- 定义
autolabel_stacked()
函数,在每个堆积柱状图的顶部添加数据标签,显示总销售量。
- 定义
- 添加标题、标签和图例:
- 设置图表标题和轴标签。
- 使用
ax.legend()
显示图例,区分产品A、产品B和产品C。
3.4 直方图(Histogram)
直方图用于展示数据的分布情况,通过将数据分组并统计每组的频数,可以直观地观察数据的集中趋势和分散程度。
3.4.1 绘制基础直方图
基础直方图用于展示单变量数据的分布情况,适用于观察数据的频率分布和形态。
示例代码:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成随机数据
np.random.seed(0)
data = np.random.normal(loc=50, scale=15, size=200)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制基础直方图
ax.hist(data, bins=10, color='skyblue', edgecolor='black')
# 添加标题和标签
ax.set_title('基础直方图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('数值', fontsize=14)
ax.set_ylabel('频数', fontsize=14)
# 显示图形
plt.show()
代码说明:
- 数据生成:
- 使用
numpy.random.normal()
生成符合正态分布的随机数据,均值为50,标准差为15,数量为200个数据点。
- 使用
- 绘制直方图:
- 使用
ax.hist()
方法绘制直方图,设置柱子的数量bins=10
,颜色为浅蓝色,边框颜色为黑色。
- 使用
- 添加标题和标签:
- 设置图表标题和轴标签。
3.4.2 设置区间数量与颜色
通过调整直方图的区间数量和颜色,可以更好地展示数据的分布细节和视觉效果。
在Matplotlib中,ax.hist()
函数的color
参数用于设置柱状图的颜色。当绘制单个数据集时,color
参数应该是一个单一的颜色,或者与数据集数量相同的颜色列表。然而,您在代码中为一个数据集(即一个直方图)提供了10种颜色,这导致了上述错误。
如果您希望为直方图的每个柱子(即每个区间)设置不同的颜色,可以在绘制直方图后,遍历每个柱子(patch),并分别设置其颜色。以下是修改后的代码示例:
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 生成随机数据
np.random.seed(42)
data = np.random.exponential(scale=2, size=500)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 设置不同的区间数量和颜色
bins = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet', 'cyan', 'magenta', 'lime']
# 绘制直方图,不设置颜色,获取patches
n, bins, patches = ax.hist(data, bins=bins, edgecolor='black', align='left')
# 为每个柱子设置不同的颜色
for patch, color in zip(patches, colors):
patch.set_facecolor(color)
# 添加标题和标签
ax.set_title('设置区间数量与颜色示例', fontsize=16, fontweight='bold')
ax.set_xlabel('值', fontsize=14)
ax.set_ylabel('频数', fontsize=14)
# 显示图形
plt.show()
- 导入和配置:
- 导入
matplotlib
并设置后端为TkAgg
,确保图形在不同环境下正常显示。 - 使用
plt.rcParams
全局配置中文字体SimHei
,并设置axes.unicode_minus
为False
,以避免中文字符和负号显示乱码。
- 导入
- 数据生成:
- 使用
numpy.random.exponential()
生成符合指数分布的随机数据,scale=2
表示尺度参数,生成500个数据点。
- 使用
- 创建图形和子图:
- 使用
plt.subplots()
创建一个图形和子图,设置图形大小为10x6英寸。
- 使用
- 设置区间和颜色:
- 定义
bins
列表,表示直方图的区间边界,共10个区间。 - 定义
colors
列表,为每个区间指定不同的颜色,共10种颜色。
- 定义
- 绘制直方图:
- 使用
ax.hist()
方法绘制直方图,设置bins
和edgecolor
参数,align='left'
将柱子左对齐。 ax.hist()
返回三个值:计数n
、区间边界bins
和柱子patches
。
- 使用
- 设置柱子颜色:
- 遍历
patches
和colors
,使用zip
函数将每个柱子与对应的颜色配对。 - 使用
patch.set_facecolor(color)
方法为每个柱子设置指定颜色。
- 遍历
- 添加标题和标签:
- 使用
ax.set_title()
设置图表标题,字体大小为16,字体加粗。 - 使用
ax.set_xlabel()
和ax.set_ylabel()
设置X轴和Y轴的标签,字体大小为14。
- 使用
- 显示图形:
- 使用
plt.show()
显示绘制的直方图。
- 使用
示例1:使用Colormap自动分配颜色
如果不想手动指定每个柱子的颜色,可以使用Matplotlib的颜色映射(Colormap)自动分配颜色。
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 生成随机数据
np.random.seed(100)
data = np.random.normal(loc=50, scale=10, size=1000)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 设置区间数量
bins = 20
# 绘制直方图,使用Colormap
counts, bins, patches = ax.hist(data, bins=bins, edgecolor='black', align='mid')
# 使用Colormap为每个柱子设置颜色
colormap = plt.cm.viridis
colors = colormap(np.linspace(0, 1, len(patches)))
for patch, color in zip(patches, colors):
patch.set_facecolor(color)
# 添加标题和标签
ax.set_title('使用Colormap自动分配颜色的直方图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('值', fontsize=14)
ax.set_ylabel('频数', fontsize=14)
# 添加颜色条
sm = plt.cm.ScalarMappable(cmap=colormap, norm=plt.Normalize(vmin=min(data), vmax=max(data)))
sm.set_array([])
fig.colorbar(sm, ax=ax, label='值的范围')
# 显示图形
plt.show()
代码说明:
- 使用
plt.cm.viridis
作为颜色映射。 - 通过
np.linspace(0, 1, len(patches))
生成与柱子数量相同的等间隔数值,用于映射颜色。 - 设置每个柱子的颜色。
- 添加颜色条(Colorbar)来展示颜色与数据值的对应关系。
示例2:透明度和边框设置
设置直方图柱子的透明度和边框样式,可以增强图表的视觉效果。
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 生成随机数据
np.random.seed(200)
data = np.random.beta(a=2, b=5, size=1000)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制直方图,设置透明度和边框样式
counts, bins, patches = ax.hist(data, bins=30, color='skyblue', edgecolor='black', alpha=0.7, linewidth=1.5)
# 添加标题和标签
ax.set_title('设置透明度与边框的直方图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('值', fontsize=14)
ax.set_ylabel('频数', fontsize=14)
# 显示图形
plt.show()
代码说明:
- 设置
color='skyblue'
为柱子的颜色。 - 设置
edgecolor='black'
和linewidth=1.5
,为柱子添加黑色边框,边框线宽为1.5。 - 设置
alpha=0.7
为柱子的透明度,范围为0到1。
总结
- 获取柱子(patches)对象: 使用
ax.hist()
绘制直方图时,返回的patches
对象代表每个柱子。 - 设置每个柱子的颜色: 遍历
patches
并为每个柱子设置颜色,实现每个区间不同颜色的效果。 - 使用Colormap自动分配颜色: 利用Matplotlib的颜色映射功能,自动为柱子分配颜色,并添加颜色条以展示颜色与数据值的对应关系。
- 调整透明度和边框样式: 通过
alpha
参数设置透明度,edgecolor
和linewidth
参数设置边框样式,增强图表的视觉效果。
注意事项
- 颜色数量匹配: 确保
colors
列表的长度与直方图的柱子数量相匹配,否则会导致错误。 - 字体支持: 确保系统中已安装指定的中文字体(如
SimHei
),否则可能无法正确显示中文字符。 - 后端设置: 使用
matplotlib.use('TkAgg')
可以确保图形在不同环境下正常显示,特别是在某些IDE或操作系统中。
3.4.3 设置透明度与边框
通过设置直方图的透明度和边框样式,可以增强图表的视觉效果,使数据分布更加清晰。
示例代码:
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成随机数据
np.random.seed(7)
data = np.random.uniform(low=0, high=100, size=300)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制直方图,设置透明度和边框样式
ax.hist(data, bins=20, color='skyblue', edgecolor='black', alpha=0.7, linewidth=1.5)
# 添加标题和标签
ax.set_title('设置透明度与边框示例', fontsize=16, fontweight='bold')
ax.set_xlabel('数值', fontsize=14)
ax.set_ylabel('频数', fontsize=14)
# 显示图形
plt.show()
代码说明:
- 数据生成:
- 使用
numpy.random.uniform()
生成均匀分布的随机数据,范围从0到100,数量为300个数据点。
- 使用
- 绘制直方图:
- 使用
ax.hist()
方法绘制直方图,设置alpha=0.7
使柱子具有70%的透明度。 - 设置
edgecolor='black'
和linewidth=1.5
,为柱子添加黑色边框,边框线宽为1.5。
- 使用
- 添加标题和标签:
- 设置图表标题和轴标签。
3.5 饼图(Pie Chart)
饼图用于展示各部分在整体中的比例关系,适合用于展示各类别所占比例的情况。Matplotlib的ax.pie()
方法提供了绘制饼图的功能。
3.5.1 绘制基础饼图
基础饼图用于展示各类别在整体中所占的比例,通过不同颜色区分各部分。
示例代码:
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 数据
labels = ['苹果', '香蕉', '樱桃', '日期', '葡萄']
sizes = [15, 30, 45, 10, 20]
colors = ['gold', 'yellowgreen', 'lightcoral', 'lightskyblue', 'lightgreen']
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 8))
# 绘制基础饼图
ax.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=140)
# 设置标题
ax.set_title('基础饼图示例', fontsize=16, fontweight='bold')
# 保持饼图为圆形
ax.axis('equal')
# 显示图形
plt.show()
代码说明:
数据准备:
- 定义
labels
列表表示各类别名称,sizes
列表表示各类别的比例,colors
列表定义各类别的颜色。
- 定义
绘制饼图:
使用
ax.pie()
方法绘制饼图,参数说明:
sizes
:各部分的比例。labels
:各部分的标签。colors
:各部分的颜色。autopct='%1.1f%%'
:显示每部分的百分比,保留一位小数。startangle=140
:起始绘制角度,使饼图旋转一定角度。
保持饼图为圆形:
- 使用
ax.axis('equal')
确保饼图为正圆形。
- 使用
3.5.2 自定义颜色与标签
通过自定义饼图的颜色和标签,可以更好地展示数据的分类和比例,同时增强视觉效果。
示例代码:
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 数据
labels = ['苹果', '香蕉', '樱桃', '日期', '葡萄']
sizes = [15, 30, 45, 10, 20]
colors = ['#FF9999','#66B3FF','#99FF99','#FFCC99','#C2C2F0']
explode = (0.05, 0, 0, 0, 0) # 仅突出显示第一部分
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 8))
# 绘制自定义颜色与标签的饼图
ax.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', shadow=True, startangle=140)
# 设置标题
ax.set_title('自定义颜色与标签的饼图示例', fontsize=16, fontweight='bold')
# 保持饼图为圆形
ax.axis('equal')
# 显示图形
plt.show()
代码说明:
- 数据准备:
- 定义
colors
列表,使用十六进制颜色代码自定义每个类别的颜色。 - 定义
explode
元组,用于突出显示某些部分,例如突出显示第一部分苹果。
- 定义
- 绘制饼图:
- 使用
ax.pie()
方法绘制饼图,添加explode
参数实现部分突出显示。 - 设置
shadow=True
为饼图添加阴影效果。
- 使用
- 保持饼图为圆形:
- 使用
ax.axis('equal')
确保饼图为正圆形。
- 使用
3.5.3 绘制带有百分比的饼图
在饼图中显示每个部分的百分比,可以更直观地展示各部分在整体中的比例关系。
示例代码:
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 数据
labels = ['苹果', '香蕉', '樱桃', '日期', '葡萄']
sizes = [15, 30, 45, 10, 20]
colors = ['#FF9999','#66B3FF','#99FF99','#FFCC99','#C2C2F0']
explode = (0, 0, 0.1, 0, 0) # 突出显示第三部分
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 8))
# 绘制带有百分比的饼图
wedges, texts, autotexts = ax.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', shadow=True, startangle=140,
textprops={'fontsize': 12, 'color':'black'})
# 设置标题
ax.set_title('带有百分比的饼图示例', fontsize=16, fontweight='bold')
# 自定义百分比文本样式
for autotext in autotexts:
autotext.set_color('white')
autotext.set_weight('bold')
# 保持饼图为圆形
ax.axis('equal')
# 显示图形
plt.show()
代码说明:
- 数据准备:
- 定义
labels
、sizes
、colors
和explode
参数,突出显示第三部分樱桃。
- 定义
- 绘制饼图:
- 使用
ax.pie()
方法绘制饼图,并返回wedges
(扇形)、texts
(标签文本)和autotexts
(百分比文本)。 - 设置
autopct='%1.1f%%'
显示每个部分的百分比。
- 使用
- 自定义百分比文本样式:
- 遍历
autotexts
,设置百分比文本的颜色为白色,并加粗显示。
- 遍历
- 保持饼图为圆形:
- 使用
ax.axis('equal')
确保饼图为正圆形。
- 使用
3.6 箱线图(Box Plot)
箱线图用于展示数据的分布情况,包括中位数、四分位数、异常值等信息。通过箱线图,可以直观地了解数据的集中趋势和离散程度。
3.6.1 绘制基础箱线图
基础箱线图用于展示单一数据集的分布情况,适合用于比较不同数据集的分布特征。
示例代码:
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成随机数据
np.random.seed(10)
data = [np.random.normal(0, std, 100) for std in range(1, 5)]
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制基础箱线图
ax.boxplot(data, patch_artist=True, notch=True,
boxprops=dict(facecolor='lightblue', color='blue'),
medianprops=dict(color='red'),
whiskerprops=dict(color='blue'),
capprops=dict(color='blue'),
flierprops=dict(color='red', markeredgecolor='red'))
# 添加标题和标签
ax.set_title('基础箱线图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('样本组', fontsize=14)
ax.set_ylabel('值', fontsize=14)
# 设置X轴刻度标签
ax.set_xticklabels(['组1', '组2', '组3', '组4'])
# 显示图形
plt.show()
代码说明:
数据生成:
- 使用
numpy.random.normal()
生成四组数据,每组100个数据点,标准差分别为1到4。
- 使用
绘制箱线图:
使用
ax.boxplot()
方法绘制箱线图,设置参数:
patch_artist=True
:填充箱体颜色。notch=True
:绘制缺口箱线图,用于显示中位数的置信区间。- 自定义箱体、边界、中位数线、须和异常值的颜色和样式。
添加标题和标签:
- 设置图表标题和轴标签。
- 使用
ax.set_xticklabels()
设置X轴的刻度标签,分别为组1到组4。
3.6.2 多组数据箱线图比较
通过在同一图表中绘制多组箱线图,可以比较不同数据集的分布特征,如中位数、四分位数和异常值等。
示例代码:
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成多组随机数据
np.random.seed(20)
group1 = np.random.normal(50, 10, 200)
group2 = np.random.normal(55, 15, 200)
group3 = np.random.normal(60, 20, 200)
group4 = np.random.normal(65, 25, 200)
data = [group1, group2, group3, group4]
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 7))
# 绘制多组数据箱线图
box = ax.boxplot(data, patch_artist=True, notch=False,
boxprops=dict(facecolor='lightgreen', color='green'),
medianprops=dict(color='red'),
whiskerprops=dict(color='green'),
capprops=dict(color='green'),
flierprops=dict(color='red', markeredgecolor='red'))
# 添加标题和标签
ax.set_title('多组数据箱线图比较示例', fontsize=16, fontweight='bold')
ax.set_xlabel('样本组', fontsize=14)
ax.set_ylabel('值', fontsize=14)
# 设置X轴刻度标签
ax.set_xticklabels(['组1', '组2', '组3', '组4'])
# 添加图例说明
import matplotlib.patches as mpatches
green_patch = mpatches.Patch(color='lightgreen', label='数据分布')
red_line = mpatches.Patch(color='red', label='中位数')
plt.legend(handles=[green_patch, red_line], loc='upper right')
# 显示图形
plt.show()
代码说明:
- 数据生成:
- 生成四组数据
group1
到group4
,分别具有不同的均值和标准差,模拟不同的数据分布。
- 生成四组数据
- 绘制箱线图:
- 使用
ax.boxplot()
方法绘制多组数据的箱线图,设置箱体颜色为浅绿色,边界为绿色,中位数线为红色。
- 使用
- 添加图例说明:
- 使用
matplotlib.patches
创建图例标识,区分数据分布和中位数。
- 使用
- 添加标题和标签:
- 设置图表标题和轴标签。
- 使用
ax.set_xticklabels()
设置X轴的刻度标签,分别为组1到组4。
3.6.3 调整箱线图样式
通过调整箱线图的样式参数,可以更好地展示数据的分布特征,并增强图表的视觉效果。
示例代码:
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成随机数据
np.random.seed(30)
data = [np.random.normal(0, std, 100) for std in range(1, 4)]
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制箱线图,调整样式参数
box = ax.boxplot(data, patch_artist=True, notch=True,
boxprops=dict(facecolor='lightblue', color='blue', linewidth=2),
medianprops=dict(color='darkred', linewidth=2),
whiskerprops=dict(color='blue', linewidth=2),
capprops=dict(color='blue', linewidth=2),
flierprops=dict(marker='D', markerfacecolor='red', markersize=6, linestyle='none'),
showfliers=True)
# 添加标题和标签
ax.set_title('调整箱线图样式示例', fontsize=16, fontweight='bold')
ax.set_xlabel('样本组', fontsize=14)
ax.set_ylabel('值', fontsize=14)
# 设置X轴刻度标签
ax.set_xticklabels(['组1', '组2', '组3'])
# 添加网格线
ax.yaxis.grid(True, linestyle='--', which='major', color='grey', alpha=0.5)
# 显示图形
plt.show()
代码说明:
数据生成:
- 生成三组数据,标准差分别为1到3,模拟不同的数据分布。
绘制箱线图:
使用
ax.boxplot()
方法绘制箱线图,设置以下样式参数:
patch_artist=True
:填充箱体颜色。notch=True
:绘制缺口箱线图。boxprops
:设置箱体颜色、边界颜色和线宽。medianprops
:设置中位数线的颜色和线宽。whiskerprops
、capprops
:设置须和帽子的颜色和线宽。flierprops
:设置异常值的标记样式,包括标记形状、颜色和大小。
添加网格线:
- 使用
ax.yaxis.grid()
方法添加Y轴的网格线,设置线条样式、类型和颜色。
- 使用
添加标题和标签:
- 设置图表标题和轴标签。
- 使用
ax.set_xticklabels()
设置X轴的刻度标签,分别为组1到组3。
4. 高级图形
在数据可视化中,除了基础的图表类型外,Matplotlib还提供了许多高级图形功能,如子图布局、极坐标图、热图和三维图形等。这些高级功能能够帮助你创建更复杂和信息丰富的图表,以满足不同的数据展示需求。以下内容将详细介绍这些高级图形的绘制方法和定制技巧。
4.1 子图布局与定制
在一个图形中创建多个子图,可以同时展示多个图表,便于比较和分析不同的数据集。Matplotlib提供了多种方法来创建和定制子图布局,包括plt.subplots()
和plt.subplot()
,以及调整子图间距和大小的方法。
4.1.1 plt.subplots()
与plt.subplot()
的区别
plt.subplots()
和plt.subplot()
都是用于创建子图的方法,但它们在用法和功能上有所不同。
plt.subplots()
:创建一个图形和一组子图(Axes对象)的更现代和灵活的方法。它返回一个Figure对象和一个包含所有子图的数组,便于后续的操作和定制。plt.subplot()
:在一个图形中创建一个子图的较老方法。它通常用于在一个图形中依次创建多个子图,但不如plt.subplots()
灵活。
示例代码:使用 plt.subplots()
创建子图
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 使用 plt.subplots() 创建2x2的子图网格
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
# 第一子图:折线图
axes[0, 0].plot([1, 2, 3], [4, 5, 6], marker='o', linestyle='-', color='blue')
axes[0, 0].set_title('子图 1 - 折线图')
axes[0, 0].set_xlabel('X轴')
axes[0, 0].set_ylabel('Y轴')
# 第二子图:散点图
axes[0, 1].scatter([1, 2, 3], [4, 5, 6], color='green')
axes[0, 1].set_title('子图 2 - 散点图')
axes[0, 1].set_xlabel('X轴')
axes[0, 1].set_ylabel('Y轴')
# 第三子图:柱状图
axes[1, 0].bar(['A', 'B', 'C'], [5, 7, 3], color='orange')
axes[1, 0].set_title('子图 3 - 柱状图')
axes[1, 0].set_xlabel('类别')
axes[1, 0].set_ylabel('值')
# 第四子图:直方图
data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
axes[1, 1].hist(data, bins=4, color='purple', edgecolor='black')
axes[1, 1].set_title('子图 4 - 直方图')
axes[1, 1].set_xlabel('值')
axes[1, 1].set_ylabel('频数')
# 调整子图之间的间距
plt.tight_layout()
# 显示图形
plt.show()
示例代码:使用 plt.subplot()
创建子图
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建一个图形
plt.figure(figsize=(12, 8))
# 第一子图:折线图
plt.subplot(2, 2, 1) # 2行2列的第1个子图
plt.plot([1, 2, 3], [4, 5, 6], marker='o', linestyle='-', color='blue')
plt.title('子图 1 - 折线图')
plt.xlabel('X轴')
plt.ylabel('Y轴')
# 第二子图:散点图
plt.subplot(2, 2, 2) # 2行2列的第2个子图
plt.scatter([1, 2, 3], [4, 5, 6], color='green')
plt.title('子图 2 - 散点图')
plt.xlabel('X轴')
plt.ylabel('Y轴')
# 第三子图:柱状图
plt.subplot(2, 2, 3) # 2行2列的第3个子图
plt.bar(['A', 'B', 'C'], [5, 7, 3], color='orange')
plt.title('子图 3 - 柱状图')
plt.xlabel('类别')
plt.ylabel('值')
# 第四子图:直方图
data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
plt.subplot(2, 2, 4) # 2行2列的第4个子图
plt.hist(data, bins=4, color='purple', edgecolor='black')
plt.title('子图 4 - 直方图')
plt.xlabel('值')
plt.ylabel('频数')
# 调整子图之间的间距
plt.tight_layout()
# 显示图形
plt.show()
代码说明:
plt.subplots()
:
- 创建一个图形和一个包含所有子图的数组。
- 更加灵活,适合处理复杂的子图布局。
plt.subplot()
:
- 按顺序在一个图形中创建多个子图。
- 使用较为简单,但不如
plt.subplots()
灵活。
4.1.2 设置子图的间距(plt.subplots_adjust()
)
当在一个图形中创建多个子图时,可能需要调整子图之间的间距,以避免标题和标签的重叠。plt.subplots_adjust()
方法可以用来调整子图之间的水平和垂直间距。
示例代码:调整子图间距
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建2x2的子图
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
# 绘制简单的图表
for i in range(2):
for j in range(2):
axes[i, j].plot([1, 2, 3], [4, 5, 6])
axes[i, j].set_title(f'子图 {i*2 + j + 1}')
# 调整子图之间的间距
plt.subplots_adjust(wspace=0.3, hspace=0.5) # 设置宽度和高度的间距
# 显示图形
plt.show()
代码说明:
plt.subplots_adjust()
:
wspace
:子图之间的水平间距,默认为0.2。hspace
:子图之间的垂直间距,默认为0.2。- 通过增加
wspace
和hspace
的值,可以增加子图之间的空白区域,避免重叠。
4.1.3 调整子图的大小与布局
通过调整子图的大小和布局,可以更好地控制图形的整体外观和信息展示。Matplotlib提供了多种布局调整方法,如GridSpec
和subplot2grid
,以实现更复杂的子图布局。
示例代码:使用 GridSpec
调整子图布局
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建图形
fig = plt.figure(figsize=(14, 8))
# 创建GridSpec布局,3行2列
gs = gridspec.GridSpec(3, 2, width_ratios=[1, 1], height_ratios=[2, 1, 1])
# 第一子图:占两列
ax1 = fig.add_subplot(gs[0, :])
ax1.plot([1, 2, 3], [4, 5, 6], marker='o', linestyle='-', color='blue')
ax1.set_title('子图 1 - 占两列')
ax1.set_xlabel('X轴')
ax1.set_ylabel('Y轴')
# 第二子图
ax2 = fig.add_subplot(gs[1, 0])
ax2.bar(['A', 'B', 'C'], [5, 7, 3], color='orange')
ax2.set_title('子图 2')
ax2.set_xlabel('类别')
ax2.set_ylabel('值')
# 第三子图
ax3 = fig.add_subplot(gs[1, 1])
ax3.scatter([1, 2, 3], [4, 5, 6], color='green')
ax3.set_title('子图 3')
ax3.set_xlabel('X轴')
ax3.set_ylabel('Y轴')
# 第四子图
ax4 = fig.add_subplot(gs[2, 0])
ax4.hist([1, 2, 2, 3, 3, 3, 4, 4, 4, 4], bins=4, color='purple', edgecolor='black')
ax4.set_title('子图 4')
ax4.set_xlabel('值')
ax4.set_ylabel('频数')
# 第五子图
ax5 = fig.add_subplot(gs[2, 1])
ax5.boxplot([1, 2, 3, 4, 5], patch_artist=True, boxprops=dict(facecolor='lightblue'))
ax5.set_title('子图 5')
ax5.set_xlabel('组别')
ax5.set_ylabel('值')
# 调整整体布局
plt.tight_layout()
# 显示图形
plt.show()
代码说明:
GridSpec
:
GridSpec
允许创建更加灵活和复杂的子图布局。- 在示例中,创建了一个3行2列的网格布局。
创建子图
:
ax1
:使用gs[0, :]
占据第一行的所有列,实现跨列子图。ax2
、ax3
:分别占据第二行的第一个和第二个位置。ax4
、ax5
:分别占据第三行的第一个和第二个位置。
绘制不同类型的图表
:
- 每个子图绘制不同类型的图表,如折线图、柱状图、散点图、直方图和箱线图。
布局调整
:
- 使用
plt.tight_layout()
自动调整子图间的间距,避免标题和标签重叠。
- 使用
4.2 极坐标图(Polar Plot)
极坐标图是一种特殊类型的图表,使用极坐标系统(角度和半径)来展示数据。它适用于展示周期性数据或具有方向性的数据,如风向分布、季节性趋势等。
4.2.1 绘制基础极坐标图
Matplotlib允许将子图的坐标系统设置为极坐标,通过设置projection='polar'
参数来创建极坐标图。
示例代码:绘制基础极坐标图
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建极坐标子图
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(8, 8))
# 数据
theta = np.linspace(0, 2 * np.pi, 100) # 角度从0到2π
r = np.abs(np.sin(theta)) # 半径为sin(theta)的绝对值
# 绘制极坐标图
ax.plot(theta, r, color='red', linewidth=2, label='sin(theta)')
# 添加标题和图例
ax.set_title('基础极坐标图示例', fontsize=16, fontweight='bold', va='bottom')
ax.legend(loc='upper right')
# 显示图形
plt.show()
代码说明:
创建极坐标子图
:
- 使用
subplot_kw={'projection': 'polar'}
参数,将子图的坐标系统设置为极坐标。
- 使用
数据准备
:
theta
:角度,从0到2π,分成100个点。r
:半径,为sin(theta)
的绝对值,确保半径为正值。
绘制极坐标图
:
- 使用
ax.plot()
方法绘制线条,颜色为红色,线宽为2。
- 使用
添加标题和图例
:
- 使用
ax.set_title()
设置图表标题,ax.legend()
添加图例。
- 使用
4.2.2 自定义角度与半径
通过自定义角度和半径,可以更灵活地展示数据的方向性和大小。Matplotlib提供了多种方式来调整极坐标图的角度起点、方向和半径范围。
示例代码:自定义角度起点和方向
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建极坐标子图
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(8, 8))
# 数据
theta = np.linspace(0, 2 * np.pi, 100)
r = 1 + np.sin(5 * theta)
# 自定义极坐标参数
ax.set_theta_zero_location('N') # 角度起点设置为北方(上方)
ax.set_theta_direction(-1) # 逆时针方向
# 设置半径范围
ax.set_ylim(0, 2)
# 绘制极坐标图
ax.plot(theta, r, color='blue', linewidth=2, label='1 + sin(5θ)')
# 添加标题和图例
ax.set_title('自定义角度与半径的极坐标图示例', fontsize=16, fontweight='bold', va='bottom')
ax.legend(loc='upper right')
# 显示图形
plt.show()
代码说明:
自定义角度起点
:
ax.set_theta_zero_location('N')
:将角度的起点设置为北方(图的上方)。
自定义角度方向
:
ax.set_theta_direction(-1)
:设置角度的递增方向为逆时针方向(默认为顺时针)。
设置半径范围
:
ax.set_ylim(0, 2)
:设置半径的显示范围,从0到2。
数据准备与绘制
:
r = 1 + np.sin(5 * theta)
:半径随角度变化,形成五瓣花的形状。- 绘制蓝色线条,线宽为2,并添加标签用于图例。
4.2.3 绘制极坐标中的线图和散点图
在极坐标系统中,除了绘制线图外,还可以绘制散点图,以展示数据点的方向和大小。
示例代码:绘制极坐标中的散点图
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建极坐标子图
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(8, 8))
# 数据
theta = np.random.uniform(0, 2 * np.pi, 100)
r = np.random.uniform(0, 1, 100)
colors = np.random.rand(100)
sizes = 100 * np.random.rand(100)
# 绘制散点图
scatter = ax.scatter(theta, r, c=colors, s=sizes, alpha=0.75, cmap='hsv', edgecolors='w', linewidth=0.5)
# 添加颜色条
cbar = plt.colorbar(scatter, ax=ax, pad=0.1)
cbar.set_label('颜色映射')
# 添加标题
ax.set_title('极坐标中的散点图示例', fontsize=16, fontweight='bold', va='bottom')
# 显示图形
plt.show()
代码说明:
数据准备
:
theta
:随机生成100个角度,从0到2π。r
:随机生成100个半径值,从0到1。colors
:随机生成100个颜色映射值。sizes
:随机生成100个点的大小。
绘制散点图
:
- 使用
ax.scatter()
方法绘制散点图,设置颜色映射cmap='hsv'
,透明度alpha=0.75
,边框颜色edgecolors='w'
(白色),边框线宽linewidth=0.5
。
- 使用
添加颜色条
:
- 使用
plt.colorbar()
方法添加颜色条,展示颜色映射的范围。
- 使用
添加标题
:
- 使用
ax.set_title()
设置图表标题。
- 使用
4.3 热图(Heatmap)
热图是一种二维图表,用颜色的深浅来表示数据的数值大小,适用于展示矩阵形式的数据分布和相关性。Matplotlib的imshow()
方法提供了绘制热图的功能。
4.3.1 使用 imshow()
绘制热图
imshow()
方法可以将二维数组数据以图像的形式展示出来,颜色深浅代表数值大小。
示例代码:使用 imshow()
绘制基础热图
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成二维数据
data = np.random.rand(10, 10) # 10x10的随机数据
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 绘制热图
cax = ax.imshow(data, cmap='viridis', interpolation='nearest')
# 添加颜色条
cbar = fig.colorbar(cax)
cbar.set_label('数值大小')
# 添加标题和标签
ax.set_title('基础热图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
# 设置X轴和Y轴的刻度
ax.set_xticks(np.arange(10))
ax.set_yticks(np.arange(10))
# 设置X轴和Y轴的标签
ax.set_xticklabels([f'列{i}' for i in range(1, 11)])
ax.set_yticklabels([f'行{i}' for i in range(1, 11)])
# 显示图形
plt.show()
代码说明:
数据生成
:
- 使用
np.random.rand(10, 10)
生成一个10x10的二维随机数组,数值范围为0到1。
- 使用
绘制热图
:
- 使用
ax.imshow()
方法绘制热图,cmap='viridis'
指定颜色映射,interpolation='nearest'
确保每个数据点对应一个明确的颜色块。
- 使用
添加颜色条
:
- 使用
fig.colorbar()
添加颜色条,显示数值与颜色的对应关系。
- 使用
设置刻度和标签
:
- 使用
ax.set_xticks()
和ax.set_yticks()
设置X轴和Y轴的刻度位置。 - 使用
ax.set_xticklabels()
和ax.set_yticklabels()
设置刻度标签名称。
- 使用
4.3.2 自定义颜色映射(colormap)
通过自定义颜色映射,可以更好地展示数据的特征和分布。Matplotlib提供了多种内置的颜色映射(colormap),也支持自定义颜色映射。
示例代码:使用不同的颜色映射绘制热图
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成二维数据
data = np.random.randn(10, 10) # 10x10的标准正态分布数据
# 创建图形和子图
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
# 定义不同的颜色映射
colormaps = ['viridis', 'plasma', 'inferno']
for ax, cmap in zip(axes, colormaps):
cax = ax.imshow(data, cmap=cmap, interpolation='nearest')
ax.set_title(f'颜色映射:{cmap}', fontsize=14)
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_xticks(np.arange(10))
ax.set_yticks(np.arange(10))
ax.set_xticklabels([f'列{i}' for i in range(1, 11)])
ax.set_yticklabels([f'行{i}' for i in range(1, 11)])
fig.colorbar(cax, ax=ax, label='数值大小')
# 添加总体标题
fig.suptitle('自定义颜色映射的热图示例', fontsize=18, fontweight='bold')
# 显示图形
plt.show()
代码说明:
颜色映射定义
:
- 使用
colormaps
列表定义三种不同的颜色映射:viridis
、plasma
和inferno
。
- 使用
绘制多个热图
:
- 使用循环遍历每个子图和颜色映射,分别绘制不同颜色映射的热图。
添加颜色条
:
- 为每个热图添加对应的颜色条,标明数值大小。
4.3.3 调整热图坐标轴和颜色条
通过调整热图的坐标轴和颜色条,可以增强图表的可读性和信息传达效果。
示例代码:调整热图的坐标轴和颜色条
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成二维数据
data = np.random.rand(12, 12) # 12x12的随机数据
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 8))
# 绘制热图
cax = ax.imshow(data, cmap='coolwarm', interpolation='nearest')
# 添加颜色条,并设置颜色条的位置和大小
cbar = fig.colorbar(cax, ax=ax, orientation='vertical', fraction=0.046, pad=0.04)
cbar.set_label('数值大小', fontsize=12)
# 添加标题和标签
ax.set_title('调整坐标轴与颜色条的热图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴', fontsize=14)
ax.set_ylabel('Y轴', fontsize=14)
# 设置X轴和Y轴的刻度标签,并旋转X轴标签
ax.set_xticks(np.arange(12))
ax.set_yticks(np.arange(12))
ax.set_xticklabels([f'列{i}' for i in range(1, 13)])
ax.set_yticklabels([f'行{i}' for i in range(1, 13)])
plt.setp(ax.get_xticklabels(), rotation=45, ha='right', rotation_mode='anchor')
# 调整坐标轴的边框颜色和线宽
for spine in ax.spines.values():
spine.set_edgecolor('black')
spine.set_linewidth(1.2)
# 显示网格线(可选)
ax.grid(False)
# 显示图形
plt.tight_layout()
plt.show()
代码说明:
颜色条调整
:
orientation='vertical'
:设置颜色条为垂直方向。fraction=0.046
和pad=0.04
:调整颜色条的大小和位置。
刻度标签设置
:
- 设置X轴和Y轴的刻度标签,并使用
plt.setp()
方法旋转X轴标签,以避免重叠。
- 设置X轴和Y轴的刻度标签,并使用
坐标轴边框设置
:
- 遍历坐标轴的spines(边框),设置边框颜色和线宽,增强视觉效果。
网格线
:
- 使用
ax.grid(False)
关闭网格线,保持图表简洁。
- 使用
4.4 3D图形
Matplotlib支持三维图形的绘制,能够展示更复杂的数据关系和结构。通过mpl_toolkits.mplot3d
模块,可以创建三维坐标轴,并绘制三维图形。
4.4.1 绘制三维图形(Axes3D
)
要绘制三维图形,需要导入Axes3D
模块,并在创建子图时指定projection='3d'
。
示例代码:绘制基础三维图形
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # 导入3D绘图工具
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建3D子图
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# 数据
X = np.linspace(-5, 5, 100)
Y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(X, Y)
Z = np.sin(np.sqrt(X**2 + Y**2))
# 绘制三维曲面图
ax.plot_surface(X, Y, Z, cmap='viridis')
# 添加标题和标签
ax.set_title('基础三维曲面图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')
# 显示图形
plt.show()
代码说明:
导入3D工具
:
- 使用
from mpl_toolkits.mplot3d import Axes3D
导入3D绘图工具。
- 使用
创建3D子图
:
- 使用
fig.add_subplot(111, projection='3d')
创建一个三维子图。
- 使用
数据准备
:
- 使用
np.meshgrid()
生成二维网格数据。 - 计算
Z
值为sinf(sqrt(X^2 + Y^2))
,形成波浪状曲面。
- 使用
绘制三维曲面图
:
- 使用
ax.plot_surface()
方法绘制三维曲面图,cmap='viridis'
指定颜色映射。
- 使用
添加标题和标签
:
- 设置图表标题和轴标签。
4.4.2 绘制3D散点图、3D线图
在三维坐标系统中,可以绘制散点图和线图,以展示数据点在三维空间中的分布和关系。
示例代码:绘制3D散点图和3D线图
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建3D子图
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
# 生成散点数据
np.random.seed(0)
X_scatter = np.random.rand(100) * 10
Y_scatter = np.random.rand(100) * 10
Z_scatter = np.random.rand(100) * 10
colors = np.random.rand(100)
sizes = 50 * np.random.rand(100)
# 绘制3D散点图
scatter = ax.scatter(X_scatter, Y_scatter, Z_scatter, c=colors, s=sizes, cmap='coolwarm', alpha=0.6, edgecolors='w')
# 生成线数据
X_line = np.linspace(0, 10, 100)
Y_line = np.sin(X_line) + np.random.rand(100)
Z_line = np.cos(X_line) + np.random.rand(100)
# 绘制3D线图
ax.plot(X_line, Y_line, Z_line, color='black', linewidth=2, label='随机线')
# 添加颜色条
cbar = fig.colorbar(scatter, ax=ax, pad=0.1)
cbar.set_label('颜色映射')
# 添加标题和标签
ax.set_title('3D散点图与3D线图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')
# 添加图例
ax.legend()
# 显示图形
plt.show()
代码说明:
散点数据生成
:
- 使用
np.random.rand()
生成100个随机点的X、Y、Z坐标。 - 使用随机数生成颜色和大小。
- 使用
绘制3D散点图
:
- 使用
ax.scatter()
方法绘制散点图,设置颜色映射cmap='coolwarm'
,透明度alpha=0.6
,边框颜色edgecolors='w'
(白色)。
- 使用
线数据生成
:
- 使用
np.linspace()
生成100个X值,从0到10。 - 使用
sinf
和cosf
函数加上随机扰动生成Y和Z值。
- 使用
绘制3D线图
:
- 使用
ax.plot()
方法绘制线图,颜色为黑色,线宽为2。
- 使用
添加颜色条和图例
:
- 使用
fig.colorbar()
添加颜色条,显示散点的颜色映射。 - 使用
ax.legend()
添加图例,区分散点和线图。
- 使用
4.4.3 绘制3D表面图
三维表面图用于展示三维数据的连续表面,适合用于展示函数的三维形态或地形数据等。
示例代码:绘制3D表面图
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建3D子图
fig = plt.figure(figsize=(14, 10))
ax = fig.add_subplot(111, projection='3d')
# 生成网格数据
X = np.linspace(-5, 5, 100)
Y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(X, Y)
Z = np.sin(np.sqrt(X**2 + Y**2)) / np.sqrt(X**2 + Y**2)
# 绘制3D表面图
surface = ax.plot_surface(X, Y, Z, cmap='plasma', edgecolor='none', alpha=0.8)
# 添加颜色条
cbar = fig.colorbar(surface, ax=ax, shrink=0.5, aspect=10)
cbar.set_label('函数值')
# 添加标题和标签
ax.set_title('3D表面图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')
# 调整视角
ax.view_init(elev=30, azim=45)
# 显示图形
plt.show()
代码说明:
网格数据生成
:
- 使用
np.meshgrid()
生成二维网格数据。 - 计算
Z
值为sinf(sqrt(X^2 + Y^2)) / sqrt(X^2 + Y^2)
,形成一个衰减的波纹表面。
- 使用
绘制3D表面图
:
- 使用
ax.plot_surface()
方法绘制表面图,设置颜色映射cmap='plasma'
,去除边框edgecolor='none'
,设置透明度alpha=0.8
。
- 使用
添加颜色条
:
- 使用
fig.colorbar()
添加颜色条,标明函数值的范围。
- 使用
调整视角
:
- 使用
ax.view_init(elev=30, azim=45)
调整视角的高度和方位角,使表面图更具立体感。
- 使用
总结
子图布局与定制
:
- 使用
plt.subplots()
和plt.subplot()
创建多个子图。 - 调整子图之间的间距和布局,使用
GridSpec
实现复杂布局。
- 使用
极坐标图
:
- 创建基础极坐标图,定制角度起点和方向。
- 在极坐标系统中绘制线图和散点图,增强数据的方向性展示。
热图
:
- 使用
imshow()
绘制基础热图,调整颜色映射和坐标轴。 - 自定义颜色映射(colormap)和颜色条,提升数据的可读性。
- 使用
三维图形
:
- 创建三维子图,绘制基础三维图形(曲面图)。
- 绘制三维散点图和线图,展示数据的空间分布。
- 绘制三维表面图,展示复杂的数据关系和函数形态。
5. 图表美化与优化
在数据可视化中,图表的美观与优化不仅能够提升信息的传达效果,还能增强图表的专业性和吸引力。Matplotlib提供了丰富的工具和方法,帮助用户美化和优化图表。以下内容将详细介绍颜色映射(Colormaps)、图形美化技巧以及交互式图形的创建方法。
5.1 颜色映射(Colormaps)
颜色映射是指将数据值映射到颜色空间,以通过颜色的变化展示数据的差异和趋势。选择合适的颜色映射对于数据的可读性和信息传达至关重要。
5.1.1 选择合适的颜色映射
不同类型的数据适合使用不同的颜色映射。Matplotlib提供了多种内置的颜色映射,主要分为以下几类:
- 顺序型颜色映射(Sequential Colormaps):适用于有序数据,颜色从浅到深或从一种颜色渐变到另一种颜色,适合展示数据的大小、密度等。
- 发散型颜色映射(Diverging Colormaps):适用于有中心点的数据,颜色从中心向两端发散,适合展示数据的正负偏差、变化趋势等。
- 定性颜色映射(Qualitative Colormaps):适用于分类数据,不同类别使用不同的颜色,适合展示离散的分类信息。
示例代码:选择合适的颜色映射
以下示例展示了如何在不同类型的数据上选择合适的颜色映射,并对比不同颜色映射的效果。
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
# 生成顺序型数据
data_sequential = np.random.rand(10, 10)
# 生成发散型数据
data_diverging = np.random.randn(10, 10)
# 定义定性颜色映射
labels = ['类别A', '类别B', '类别C', '类别D']
colors_qualitative = ['#FF9999','#66B3FF','#99FF99','#FFCC99']
# 创建图形和子图
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
# 顺序型颜色映射
cmap_sequential = 'Blues'
im1 = axes[0].imshow(data_sequential, cmap=cmap_sequential)
axes[0].set_title('顺序型颜色映射:Blues')
fig.colorbar(im1, ax=axes[0])
# 发散型颜色映射
cmap_diverging = 'coolwarm'
im2 = axes[1].imshow(data_diverging, cmap=cmap_diverging)
axes[1].set_title('发散型颜色映射:coolwarm')
fig.colorbar(im2, ax=axes[1])
# 定性颜色映射
for i in range(data_sequential.shape[0]):
for j in range(data_sequential.shape[1]):
axes[2].add_patch(plt.Rectangle((j, i), 1, 1, color=colors_qualitative[i % len(colors_qualitative)]))
axes[2].set_xlim(0, data_sequential.shape[1])
axes[2].set_ylim(0, data_sequential.shape[0])
axes[2].set_title('定性颜色映射:类别区分')
axes[2].set_xticks([])
axes[2].set_yticks([])
for i, label in enumerate(labels):
axes[2].text(-1, i, label, va='center', fontsize=12)
# 调整布局
plt.tight_layout()
# 显示图形
plt.show()
代码说明:
- 数据生成:
data_sequential
:生成10x10的随机数,适合顺序型颜色映射。data_diverging
:生成10x10的标准正态分布数据,适合发散型颜色映射。
- 颜色映射选择:
cmap_sequential
:选择Blues
作为顺序型颜色映射。cmap_diverging
:选择coolwarm
作为发散型颜色映射。colors_qualitative
:定义定性颜色映射的颜色列表,用于分类区分。
- 绘制图表:
- 使用
imshow()
方法绘制顺序型和发散型热图,并添加颜色条。 - 对于定性颜色映射,使用
Rectangle
补丁手动绘制颜色块,并添加类别标签。
- 使用
- 布局调整:
- 使用
plt.tight_layout()
自动调整子图间的间距,避免重叠。
- 使用
5.1.2 设置渐变颜色映射
渐变颜色映射通过颜色的连续变化,能够更细腻地展示数据的渐变趋势。Matplotlib提供了多种内置的渐变颜色映射,并支持自定义渐变颜色。
示例代码:应用渐变颜色映射到热图
以下示例展示了如何使用渐变颜色映射来增强热图的视觉效果。
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成二维数据
data = np.random.rand(10, 10)
# 创建图形和子图
fig, axes = plt.subplots(1, 2, figsize=(16, 6))
# 使用内置渐变颜色映射 'viridis'
cmap_viridis = 'viridis'
im1 = axes[0].imshow(data, cmap=cmap_viridis, interpolation='nearest')
axes[0].set_title('渐变颜色映射:viridis')
fig.colorbar(im1, ax=axes[0])
# 创建自定义渐变颜色映射
from matplotlib.colors import LinearSegmentedColormap
# 定义颜色列表
colors = ['navy', 'blue', 'cyan', 'green', 'yellow', 'orange', 'red']
# 创建自定义颜色映射
custom_cmap = LinearSegmentedColormap.from_list('custom_cmap', colors, N=256)
# 应用自定义渐变颜色映射
im2 = axes[1].imshow(data, cmap=custom_cmap, interpolation='nearest')
axes[1].set_title('自定义渐变颜色映射')
fig.colorbar(im2, ax=axes[1])
# 调整布局
plt.tight_layout()
# 显示图形
plt.show()
代码说明:
- 数据生成:
- 使用
np.random.rand(10, 10)
生成10x10的随机数数据。
- 使用
- 内置渐变颜色映射:
- 选择
viridis
作为渐变颜色映射,并使用imshow()
绘制热图。 - 添加颜色条以展示颜色与数据值的对应关系。
- 选择
- 自定义渐变颜色映射:
- 导入
LinearSegmentedColormap
类,用于创建自定义颜色映射。 - 定义一个颜色列表,从深蓝色到红色,形成一个连续的渐变。
- 使用
LinearSegmentedColormap.from_list()
创建自定义颜色映射custom_cmap
。 - 使用自定义颜色映射绘制热图,并添加颜色条。
- 导入
- 布局调整:
- 使用
plt.tight_layout()
自动调整子图间的间距。
- 使用
5.1.3 配置颜色条(plt.colorbar()
)
颜色条用于展示颜色映射与数据值之间的对应关系,是热图等颜色映射图表的重要组成部分。Matplotlib提供了多种方式配置颜色条的位置、大小和标签。
示例代码:自定义颜色条的位置和标签
以下示例展示了如何自定义颜色条的位置、大小以及添加标签,以提升图表的可读性和信息传达效果。
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成二维数据
data = np.random.rand(10, 10)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 绘制热图
cax = ax.imshow(data, cmap='plasma', interpolation='nearest')
# 添加颜色条,设置位置和大小
cbar = fig.colorbar(cax, ax=ax, orientation='vertical', fraction=0.046, pad=0.04)
cbar.set_label('数值大小', fontsize=12)
# 添加标题和标签
ax.set_title('配置颜色条示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
# 设置X轴和Y轴的刻度
ax.set_xticks(np.arange(10))
ax.set_yticks(np.arange(10))
ax.set_xticklabels([f'列{i}' for i in range(1, 11)])
ax.set_yticklabels([f'行{i}' for i in range(1, 11)])
# 调整坐标轴标签的字体大小
ax.tick_params(axis='both', which='major', labelsize=10)
# 显示图形
plt.show()
代码说明:
- 数据生成:
- 使用
np.random.rand(10, 10)
生成10x10的随机数数据。
- 使用
- 绘制热图:
- 使用
ax.imshow()
绘制热图,选择plasma
作为颜色映射,并设置插值方法为nearest
,确保每个数据点对应一个颜色块。
- 使用
- 添加颜色条:
- 使用
fig.colorbar()
添加颜色条。 orientation='vertical'
:设置颜色条为垂直方向。fraction=0.046
和pad=0.04
:调整颜色条的大小和位置,fraction
控制颜色条相对于图形的宽度,pad
控制颜色条与图形的间距。- 使用
cbar.set_label()
添加颜色条的标签,并设置字体大小。
- 使用
- 设置刻度标签:
- 使用
ax.set_xticks()
和ax.set_yticks()
设置X轴和Y轴的刻度位置。 - 使用
ax.set_xticklabels()
和ax.set_yticklabels()
设置刻度标签名称。 - 使用
ax.tick_params()
调整刻度标签的字体大小。
- 使用
- 添加标题和标签:
- 使用
ax.set_title()
设置图表标题,ax.set_xlabel()
和ax.set_ylabel()
设置轴标签。
- 使用
- 显示图形:
- 使用
plt.show()
显示绘制的图表。
- 使用
5.2 图形美化技巧
图形美化技巧包括设置字体样式与大小、自定义坐标轴刻度以及使用LaTeX语法显示数学公式等。这些技巧能够显著提升图表的专业性和可读性。
5.2.1 设置字体样式与大小(plt.rcParams
)
通过设置全局字体样式与大小,可以统一图表的视觉风格,使多个图表之间保持一致性。此外,个别图表或元素也可以进行单独的字体设置。
示例代码:全局设置字体样式与大小
以下示例展示了如何通过plt.rcParams
全局设置字体样式与大小,并在单个图表中进行局部调整。
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示,以及字体样式与大小
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
plt.rcParams['font.size'] = 12 # 全局字体大小
plt.rcParams['font.family'] = 'sans-serif' # 全局字体家族
# 生成数据
x = np.linspace(0, 10, 100)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制折线图
ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
# 添加标题和标签,局部调整字体大小和样式
ax.set_title('全局与局部字体设置示例', fontsize=16, fontweight='bold')
ax.set_xlabel('时间 (秒)', fontsize=14, fontstyle='italic')
ax.set_ylabel('振幅', fontsize=14, fontstyle='italic')
# 添加图例,设置图例字体大小
legend = ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 显示图形
plt.show()
代码说明:
- 全局字体设置:
plt.rcParams['font.sans-serif']
:指定全局中文字体为SimHei
,避免中文乱码。plt.rcParams['axes.unicode_minus']
:设置为False
,解决负号显示问题。plt.rcParams['font.size']
:设置全局字体大小为12。plt.rcParams['font.family']
:设置全局字体家族为无衬线字体(sans-serif)。
- 数据生成:
- 使用
np.linspace()
生成0到10之间的100个点作为X轴数据。 - 计算Y轴数据为
sin(x)
。
- 使用
- 绘制图表:
- 使用
ax.plot()
绘制折线图,设置线条颜色为蓝色,线宽为2,并添加标签label='正弦波'
用于图例显示。
- 使用
- 局部字体调整:
ax.set_title()
:设置图表标题,字体大小为16,加粗显示。ax.set_xlabel()
和ax.set_ylabel()
:设置X轴和Y轴标签,字体大小为14,使用斜体显示。
- 图例设置:
- 使用
ax.legend()
添加图例,并设置图例字体大小为12。
- 使用
- 添加网格线:
- 使用
ax.grid()
方法添加网格线,设置线条样式为虚线,线宽为0.5。
- 使用
- 显示图形:
- 使用
plt.show()
显示绘制的图表。
- 使用
示例代码:单独设置特定元素的字体样式
以下示例展示了如何在同一个图表中,为不同元素(如标题、标签、图例)设置不同的字体样式和大小。
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示,以及字体大小
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.size'] = 12
# 生成数据
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制折线图
ax.plot(x, y, label='sin(x²)', color='green', linewidth=2)
# 添加标题,设置字体大小和颜色
ax.set_title('不同元素的字体样式设置示例', fontsize=18, color='purple', fontweight='bold')
# 添加轴标签,设置字体样式
ax.set_xlabel('角度 (弧度)', fontsize=14, fontstyle='italic')
ax.set_ylabel('振幅', fontsize=14, fontstyle='italic')
# 添加图例,设置图例字体样式和位置
legend = ax.legend(loc='upper right', fontsize=12, frameon=True, shadow=True)
# 自定义图例框的字体
for text in legend.get_texts():
text.set_fontfamily('serif')
text.set_fontstyle('normal')
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 显示图形
plt.show()
代码说明:
- 全局字体设置:
- 同前述示例,设置中文字体、解决负号显示问题和全局字体大小。
- 数据生成:
- 使用
np.linspace()
生成0到2π之间的400个点作为X轴数据。 - 计算Y轴数据为
sin(x²)
,形成一个振幅随角度变化的曲线。
- 使用
- 绘制图表:
- 使用
ax.plot()
绘制折线图,设置线条颜色为绿色,线宽为2,并添加标签label='sin(x²)'
用于图例显示。
- 使用
- 标题设置:
- 使用
ax.set_title()
设置图表标题,字体大小为18,颜色为紫色,加粗显示。
- 使用
- 轴标签设置:
- 使用
ax.set_xlabel()
和ax.set_ylabel()
设置X轴和Y轴标签,字体大小为14,使用斜体显示。
- 使用
- 图例设置:
- 使用
ax.legend()
添加图例,设置图例的位置为右上角,字体大小为12,并添加边框和阴影。 - 遍历图例文本,设置图例框内文本的字体家族为衬线字体(serif)和正常字体样式。
- 使用
- 添加网格线:
- 使用
ax.grid()
方法添加网格线,设置线条样式为虚线,线宽为0.5。
- 使用
- 显示图形:
- 使用
plt.show()
显示绘制的图表。
- 使用
5.2.2 自定义坐标轴刻度
自定义坐标轴刻度包括设置刻度的位置、标签的格式、旋转角度以及刻度线的样式等。通过这些设置,可以使图表更加清晰和符合展示需求。
示例代码:自定义坐标轴刻度的位置和标签格式
以下示例展示了如何自定义X轴和Y轴的刻度位置和标签格式,包括旋转标签以避免重叠。
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成数据
x = np.linspace(0, 10, 100)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制折线图
ax.plot(x, y, label='sin(x)', color='blue', linewidth=2)
# 设置X轴刻度位置和标签
ax.set_xticks(np.arange(0, 11, 1)) # 设置X轴刻度每隔1单位
ax.set_xticklabels([f'零点{i}' for i in range(11)], rotation=45, ha='right', fontsize=10)
# 设置Y轴刻度位置和标签
ax.set_yticks(np.arange(-1, 1.1, 0.5)) # 设置Y轴刻度每隔0.5单位
ax.set_yticklabels([f'{val}' for val in np.arange(-1, 1.1, 0.5)], fontsize=10)
# 添加标题和标签
ax.set_title('自定义坐标轴刻度示例', fontsize=16, fontweight='bold')
ax.set_xlabel('时间 (秒)', fontsize=14)
ax.set_ylabel('振幅', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 显示图形
plt.tight_layout()
plt.show()
代码说明:
数据生成:
- 使用
np.linspace()
生成0到10之间的100个点作为X轴数据。 - 计算Y轴数据为
sin(x)
。
- 使用
绘制图表:
- 使用
ax.plot()
绘制折线图,设置线条颜色为蓝色,线宽为2,并添加标签label='sin(x)'
用于图例显示。
- 使用
自定义X轴刻度:
ax.set_xticks(np.arange(0, 11, 1))
:设置X轴刻度位置为0到10,每隔1单位。ax.set_xticklabels([f'零点{i}' for i in range(11)], rotation=45, ha='right', fontsize=10)
:
- 设置X轴刻度标签为
零点0
到零点10
。 - 旋转刻度标签45度,水平对齐方式为右对齐,字体大小为10。
- 设置X轴刻度标签为
自定义Y轴刻度:
ax.set_yticks(np.arange(-1, 1.1, 0.5))
:设置Y轴刻度位置为-1到1,每隔0.5单位。ax.set_yticklabels([f'{val}' for val in np.arange(-1, 1.1, 0.5)], fontsize=10)
:设置Y轴刻度标签为-1到1,每隔0.5单位,字体大小为10。
添加标题和标签:
- 使用
ax.set_title()
设置图表标题,ax.set_xlabel()
和ax.set_ylabel()
设置轴标签。
- 使用
图例和网格线:
- 使用
ax.legend()
添加图例,设置字体大小为12。 - 使用
ax.grid()
方法添加网格线,设置线条样式为虚线,线宽为0.5。
- 使用
布局调整:
- 使用
plt.tight_layout()
自动调整子图间的间距。
- 使用
显示图形:
- 使用
plt.show()
显示绘制的图表。
- 使用
示例代码:自定义刻度线的样式
以下示例展示了如何自定义刻度线的长度、宽度和颜色,以增强图表的视觉效果。
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x ** 2)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制折线图
ax.plot(x, y, label='sin(x²)', color='blue', linewidth=2)
# 设置X轴和Y轴的刻度
ax.set_xticks(np.arange(0, 13, np.pi)) # 设置X轴刻度为π的倍数
ax.set_xticklabels([r'$0$', r'$\pi$', r'$2\pi$', r'$3\pi$', r'$4\pi$'], fontsize=12)
ax.set_yticks(np.arange(-1, 1.1, 0.5))
ax.set_yticklabels([f'{val}' for val in np.arange(-1, 1.1, 0.5)], fontsize=12)
# 自定义刻度线的样式
ax.tick_params(axis='both', which='major', length=10, width=2, colors='red')
ax.tick_params(axis='both', which='minor', length=5, width=1, colors='gray')
# 添加次刻度线
ax.minorticks_on()
# 添加标题和标签
ax.set_title('自定义刻度线样式示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 (弧度)', fontsize=14)
ax.set_ylabel('振幅', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线,区分主刻度和次刻度
ax.grid(True, which='major', linestyle='-', linewidth=1, color='black')
ax.grid(True, which='minor', linestyle='--', linewidth=0.5, color='gray')
# 显示图形
plt.tight_layout()
plt.show()
代码说明:
数据生成:
- 使用
np.linspace()
生成0到4π之间的400个点作为X轴数据。 - 计算Y轴数据为
sin(x²)
,形成一个复杂的振幅变化曲线。
- 使用
绘制图表:
- 使用
ax.plot()
绘制折线图,设置线条颜色为蓝色,线宽为2,并添加标签label='sin(x²)'
用于图例显示。
- 使用
设置刻度位置和标签:
ax.set_xticks(np.arange(0, 13, np.pi))
:设置X轴刻度位置为π的倍数。ax.set_xticklabels([r'$0$', r'$\pi$', r'$2\pi$', r'$3\pi$', r'$4\pi$'], fontsize=12)
:设置X轴刻度标签为LaTeX格式的数学符号,字体大小为12。ax.set_yticks(np.arange(-1, 1.1, 0.5))
:设置Y轴刻度位置为-1到1,每隔0.5单位。ax.set_yticklabels([f'{val}' for val in np.arange(-1, 1.1, 0.5)], fontsize=12)
:设置Y轴刻度标签为-1到1,每隔0.5单位,字体大小为12。
自定义刻度线样式:
ax.tick_params(axis='both', which='major', length=10, width=2, colors='red')
:
- 设置主刻度线的长度为10,宽度为2,颜色为红色。
ax.tick_params(axis='both', which='minor', length=5, width=1, colors='gray')
:
- 设置次刻度线的长度为5,宽度为1,颜色为灰色。
添加次刻度线:
- 使用
ax.minorticks_on()
开启次刻度线显示。
- 使用
添加标题和标签:
- 使用
ax.set_title()
设置图表标题,ax.set_xlabel()
和ax.set_ylabel()
设置轴标签。
- 使用
图例和网格线:
- 使用
ax.legend()
添加图例,设置字体大小为12。 - 使用
ax.grid()
方法添加网格线,区分主刻度和次刻度,主刻度使用实线,次刻度使用虚线。
- 使用
布局调整和显示:
- 使用
plt.tight_layout()
自动调整子图间的间距。 - 使用
plt.show()
显示绘制的图表。
- 使用
5.3 交互式图形
交互式图形允许用户通过鼠标操作(如缩放、平移、悬停等)与图表进行交互,提升数据探索和分析的体验。Matplotlib在不同的环境中支持不同类型的交互式功能,尤其是在Jupyter Notebook中。
5.3.1 在Jupyter中展示图形
在Jupyter Notebook中,可以嵌入Matplotlib图表,使其与笔记本的其他内容无缝集成。Matplotlib提供了多种魔法命令来控制图表的显示方式。
示例代码:在Jupyter Notebook中嵌入静态图表
以下示例展示了如何在Jupyter Notebook中嵌入静态Matplotlib图表。
# 在Jupyter Notebook中运行此代码
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成数据
x = np.linspace(0, 10, 100)
y = np.cos(x)
# 绘制折线图
plt.figure(figsize=(10, 6))
plt.plot(x, y, label='cos(x)', color='purple', linewidth=2)
# 添加标题和标签
plt.title('在Jupyter Notebook中展示的静态图表', fontsize=16, fontweight='bold')
plt.xlabel('时间 (秒)', fontsize=14)
plt.ylabel('振幅', fontsize=14)
# 添加图例
plt.legend(fontsize=12)
# 添加网格线
plt.grid(True, linestyle='--', linewidth=0.5)
# 显示图形
plt.show()
代码说明:
- 环境配置:
- 在Jupyter Notebook中运行,确保Matplotlib图表能够嵌入笔记本中。
- 使用
matplotlib.use('TkAgg')
设置后端为TkAgg
,确保图表正常显示。
- 数据生成:
- 使用
np.linspace()
生成0到10之间的100个点作为X轴数据。 - 计算Y轴数据为
cos(x)
。
- 使用
- 绘制图表:
- 使用
plt.plot()
绘制折线图,设置线条颜色为紫色,线宽为2,并添加标签label='cos(x)'
用于图例显示。
- 使用
- 添加标题和标签:
- 使用
plt.title()
设置图表标题,plt.xlabel()
和plt.ylabel()
设置轴标签。
- 使用
- 图例和网格线:
- 使用
plt.legend()
添加图例,设置字体大小为12。 - 使用
plt.grid()
方法添加网格线,设置线条样式为虚线,线宽为0.5。
- 使用
- 显示图形:
- 使用
plt.show()
显示绘制的图表。
- 使用
注意事项:
- 在Jupyter Notebook中,可以使用
%matplotlib inline
魔法命令将图表嵌入笔记本中,但在大多数现代Jupyter环境中,这一命令已自动启用。 - 确保在运行绘图代码之前,不要在同一个单元格中多次调用
plt.show()
,以避免重复显示图表。
5.3.2 控制图形显示的交互性(%matplotlib notebook
)
Matplotlib在Jupyter Notebook中提供了不同的后端模式,用于控制图形的交互性。使用%matplotlib notebook
魔法命令,可以启用交互式图表,使用户能够通过鼠标操作与图表进行交互,如缩放、平移和旋转。
示例代码:在Jupyter Notebook中启用交互式图表
以下示例展示了如何在Jupyter Notebook中启用交互式Matplotlib图表,并体验其交互功能。
# 如果在Jupyter Notebook中运行,请根据需要启用适当的后端
# %matplotlib inline # 用于静态图表
# %matplotlib notebook # 用于交互式图表(确保在Jupyter环境中)
import matplotlib
matplotlib.use('TkAgg') # 使用 TkAgg 后端,适用于大多数IDE
import matplotlib.pyplot as plt
import numpy as np
# 全局设置中文字体和负号显示,禁用LaTeX支持
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题
plt.rcParams['text.usetex'] = False # 禁用LaTeX语法
# 生成数据
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制折线图,使用mathtext语法
ax.plot(x, y, label=r'$\sin(x)$', color='blue', linewidth=2)
# 添加标题和标签,使用mathtext数学公式
ax.set_title('正弦函数 $y = \sin(x)$ 的图像', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例,使用mathtext公式
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 调整布局以避免重叠
plt.tight_layout()
# 显示图形
plt.show()
代码说明:
- 启用交互式图表:
- 在Jupyter Notebook中运行
%matplotlib notebook
魔法命令,启用Matplotlib的交互式后端。 - 这使得绘制的图表具备缩放、平移和旋转等交互功能。
- 在Jupyter Notebook中运行
- 数据生成:
- 使用
np.linspace()
生成0到4π之间的400个点作为X轴数据。 - 计算Y轴数据为
sin(x)
。
- 使用
- 绘制图表:
- 使用
ax.plot()
绘制折线图,设置线条颜色为蓝色,线宽为2,并使用LaTeX语法在标签中表示$\sin(x)$
。 - 将绘制的线条对象赋值给变量
line
,以便后续可能的交互操作。
- 使用
- 添加标题和标签:
- 使用
ax.set_title()
设置图表标题,包含LaTeX数学公式。 - 使用
ax.set_xlabel()
和ax.set_ylabel()
设置轴标签,包含LaTeX数学公式。
- 使用
- 图例和网格线:
- 使用
ax.legend()
添加图例,设置字体大小为12。 - 使用
ax.grid()
方法添加网格线,设置线条样式为虚线,线宽为0.5。
- 使用
- 显示图形:
- 使用
plt.show()
显示绘制的图表,并启用交互功能。
- 使用
交互功能体验:
- 缩放:通过鼠标滚轮可以缩放图表,放大或缩小特定区域。
- 平移:点击并拖动鼠标可以平移图表,查看不同的数据区域。
- 旋转(仅适用于3D图形):对于三维图形,可以通过拖动鼠标旋转视角。
注意事项:
- 在启用
%matplotlib notebook
后,某些功能可能会与特定的Jupyter扩展或前端界面产生冲突,导致图表显示异常。 - 关闭交互式模式,可以使用
%matplotlib inline
或重启Jupyter Notebook内核。
示例代码:动态更新交互式图表
以下示例展示了如何在交互式模式下动态更新图表的数据,实现动画效果。
# 在Jupyter Notebook中运行此代码
# 启用交互式图表
%matplotlib widget
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用LaTeX支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
# 生成初始数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y, label=r'$\sin(x)$', color='blue', linewidth=2)
# 添加标题和标签,使用mathtext数学公式
ax.set_title('动态更新的交互式图表示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 动态更新函数
def update(phase):
y = np.sin(x + phase)
line.set_ydata(y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 100),
interval=50, blit=True)
plt.show()
代码说明:
- 启用交互式图表:
- 使用
%matplotlib notebook
魔法命令启用交互式后端。
- 使用
- 数据生成与绘制:
- 生成初始X轴数据为0到4π之间的400个点。
- 计算初始Y轴数据为
sin(x)
。 - 使用
ax.plot()
绘制初始折线图,并获取线条对象line
。
- 添加标题、标签、图例和网格线:
- 设置图表标题和轴标签,包含LaTeX数学公式。
- 使用
ax.legend()
添加图例。 - 使用
ax.grid()
方法添加网格线。
- 动态更新数据:
- 使用
for
循环遍历相位角phase
,从0到2π,共100个阶段。 - 在每个阶段,更新Y轴数据为
sin(x + phase)
,实现波形的移动效果。 - 使用
line.set_ydata(y)
更新线条数据。 - 使用
fig.canvas.draw()
和fig.canvas.flush_events()
刷新图表。 - 使用
time.sleep(0.05)
控制更新速度,实现平滑动画效果。
- 使用
注意事项:
- 动态更新图表时,应避免过长的更新循环,以防止Jupyter Notebook卡顿或响应缓慢。
- 在交互式模式下运行动态更新代码时,图表会实时响应数据变化,提供更直观的数据探索体验。
6. 动画与动态图形
在数据可视化中,动画与动态图形能够有效地展示数据的变化趋势和动态过程。Matplotlib 提供了多种工具和方法来创建动画,包括动态折线图、动态散点图以及使用 FuncAnimation
生成复杂动画。此外,动画的保存与导出功能也使得可视化结果可以在不同的平台和格式中共享和展示。
6.1 创建动态图形
动态图形能够实时展示数据的变化,使观众更直观地理解数据背后的动态过程。以下将介绍如何创建动态折线图、动态散点图,以及使用 FuncAnimation
生成动画。在所有示例中,我们将确保正确设置 Matplotlib 的后端,解决中文字符显示问题,并禁用 LaTeX 渲染以避免潜在的错误。
6.1.1 动态折线图
动态折线图通过不断更新数据点,展示数据随时间或其他变量的变化。以下示例展示了如何使用 Matplotlib 在标准 Python 脚本中创建一个动态折线图。
代码示例
# demo_dynamic_line.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
import time
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体为“SimHei”
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
plt.rcParams['text.usetex'] = False # 禁用 LaTeX 渲染
def main():
# 生成初始数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('动态折线图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 开启交互模式
plt.ion()
plt.show()
# 动态更新数据
for phase in np.linspace(0, 2 * np.pi, 100):
y = np.sin(x + phase)
line.set_ydata(y) # 更新 Y 数据
fig.canvas.draw() # 重绘图形
fig.canvas.flush_events()# 刷新事件
time.sleep(0.05) # 控制更新速度
# 关闭交互模式
plt.ioff()
plt.show()
if __name__ == "__main__":
main()
运行说明
确保 Tkinter 已安装:
Windows:Tkinter 通常随 Python 一起安装。如果未安装,可以重新运行 Python 安装程序,确保选择了 Tkinter 组件。
Linux
:
sudo apt-get install python3-tk
macOS:Tkinter 通常随 Python 一起安装。如果使用 Homebrew 安装 Python,确保安装了带有 Tk 支持的版本。
运行脚本: 在命令行中运行以下命令:
python demo_dynamic_line.py
代码说明
后端设置:
import matplotlib matplotlib.use('TkAgg') # 设置后端为 TkAgg
确保 Matplotlib 使用
TkAgg
后端来渲染图形,适用于大多数标准 Python 脚本和 IDE(如 VS Code、PyCharm 等)。中文字体和负号处理:
plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False plt.rcParams['text.usetex'] = False
设置中文字体为“SimHei”,解决中文字符显示问题,并禁用 LaTeX 渲染以避免相关错误。
动态更新: 使用
plt.ion()
开启交互模式,使图形能够实时更新。在循环中,通过line.set_ydata(y)
更新折线的数据,并使用fig.canvas.draw()
和fig.canvas.flush_events()
刷新图形。
6.1.2 动态散点图
动态散点图适用于展示数据点随时间或其他变量的移动和变化。以下示例展示了如何创建一个动态散点图,并实时更新数据点的位置。
代码示例
# demo_dynamic_scatter.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
import time
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成初始数据
np.random.seed(0)
x = np.random.rand(20)
y = np.random.rand(20)
sizes = 100 * np.random.rand(20)
colors = np.random.rand(20)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始散点图
scatter = ax.scatter(x, y, s=sizes, c=colors, cmap='viridis', alpha=0.6, edgecolors='w', linewidth=0.5)
# 添加颜色条
cbar = fig.colorbar(scatter, ax=ax)
cbar.set_label('颜色映射值', fontsize=12)
# 添加标题和标签
ax.set_title('动态散点图示例', fontsize=16, fontweight='bold')
ax.set_xlabel('X轴', fontsize=14)
ax.set_ylabel('Y轴', fontsize=14)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
# 开启交互模式
plt.ion()
plt.show()
# 动态更新数据
for _ in range(100):
# 随机移动点的位置
x += (np.random.rand(20) - 0.5) * 0.1
y += (np.random.rand(20) - 0.5) * 0.1
# 确保数据点在坐标轴范围内
x = np.clip(x, 0, 1)
y = np.clip(y, 0, 1)
# 更新散点图数据
scatter.set_offsets(np.c_[x, y])
scatter.set_sizes(100 * np.random.rand(20))
scatter.set_array(np.random.rand(20))
# 刷新图形
fig.canvas.draw()
fig.canvas.flush_events()
time.sleep(0.1) # 控制更新速度
# 关闭交互模式
plt.ioff()
plt.show()
if __name__ == "__main__":
main()
运行说明
确保 Tkinter 已安装(参考 6.1.1 动态折线图)。
运行脚本: 在命令行中运行以下命令:
python demo_dynamic_scatter.py
代码说明
- 后端设置:同 6.1.1 动态折线图。
- 中文字体和负号处理:同 6.1.1 动态折线图。
- 动态更新:
- 使用
scatter.set_offsets(np.c_[x, y])
更新散点的位置。 - 使用
scatter.set_sizes()
和scatter.set_array()
动态更新散点的大小和颜色。
- 使用
- 确保数据在范围内: 使用
np.clip()
函数确保散点的位置不会超出设定的坐标轴范围。
6.1.3 使用 FuncAnimation
生成动画
FuncAnimation
是 Matplotlib 提供的一个强大工具,用于创建复杂的动画。它通过定义一个更新函数,在每一帧调用该函数来更新图表。以下示例展示了如何使用 FuncAnimation
生成一个动态更新的正弦波动画。
代码示例
# demo_funcanimation.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成初始数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('使用 FuncAnimation 生成动画', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
phase = frame
y = np.sin(x + phase)
line.set_ydata(y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
interval=50, blit=True)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
确保 Tkinter 已安装(参考 6.1.1 动态折线图)。
运行脚本: 在命令行中运行以下命令:
python demo_funcanimation.py
代码说明
- 后端设置:同 6.1.1 动态折线图。
- 中文字体和负号处理:同 6.1.1 动态折线图。
FuncAnimation
使用:FuncAnimation
的update
函数接收一个frame
参数,用于更新图形的数据。frames
参数指定动画的帧数,这里使用np.linspace(0, 2*np.pi, 128)
生成相位值。interval
参数控制每帧之间的时间间隔(毫秒)。blit=True
参数优化动画性能,仅更新变化的部分。
6.2 动画保存与导出
创建动画后,您可能希望将其保存为文件以便分享或嵌入到其他文档中。Matplotlib 支持将动画保存为 GIF 或视频格式(如 MP4)。以下将详细介绍如何实现这一功能,并确保在保存过程中处理中文字符和后端设置。
6.2.1 动画保存为 GIF
将动画保存为 GIF 格式可以方便地在网页或文档中展示。以下示例展示了如何使用 FuncAnimation
将动画保存为 GIF 文件。
代码示例
# demo_save_gif.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成初始数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('保存为 GIF 的动画示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
phase = frame
y = np.sin(x + phase)
line.set_ydata(y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
interval=50, blit=True)
# 保存动画为 GIF
ani.save('sine_wave_animation.gif', writer='imagemagick')
# 显示图形(可选)
plt.show()
if __name__ == "__main__":
main()
运行说明
安装 ImageMagick:
下载与安装: 访问 ImageMagick 官方网站 下载适用于 Windows 的版本,并按照安装向导完成安装。
添加到 PATH: 安装完成后,将 ImageMagick 的安装目录(通常包含
magick.exe
)添加到系统的PATH
环境变量中。验证安装: 在命令提示符中运行以下命令,确保 ImageMagick 安装正确:
magick -version
运行脚本: 在命令行中运行以下命令:
python demo_save_gif.py
查看生成的 GIF: 运行脚本后,将在当前工作目录生成
sine_wave_animation.gif
文件。使用支持 GIF 播放的应用程序(如浏览器、图片查看器等)打开查看动画效果。
代码说明
后端设置:同 6.1.1 动态折线图。
中文字体和负号处理:同 6.1.1 动态折线图。
保存动画:
ani.save('sine_wave_animation.gif', writer='imagemagick')
使用
imagemagick
编写器将动画保存为 GIF 格式。
注意事项
ImageMagick 安装:
- 确保 ImageMagick 安装正确,并且
magick.exe
在系统的PATH
中可用。
- 确保 ImageMagick 安装正确,并且
权限问题:
- 确保有权限在目标目录中创建和写入文件。
编写器名称:
在某些系统上,可能需要使用
ImageMagickWriter
:
from matplotlib.animation import ImageMagickWriter writer = ImageMagickWriter(fps=20) ani.save('sine_wave_animation.gif', writer=writer)
6.2.2 动画保存为视频格式
从 FFmpeg 官网 下载适用于你系统的版本。
解压后,将其 bin
文件夹路径添加到系统环境变量中。
如果程序还是没办法很好的识别环境变量的话,那就手动指定,如下代码
plt.rcParams['animation.ffmpeg_path'] = r'D:\ruanjian\ffmpeg-7.0.2-essentials_build\bin\ffmpeg.exe'
将动画保存为视频格式(如 MP4)可以在各种媒体播放器中播放,并便于嵌入到视频编辑软件中。以下示例展示了如何使用 FuncAnimation
将动画保存为 MP4 文件。
代码示例
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
from matplotlib.animation import FFMpegWriter
# 设置 ffmpeg 路径
plt.rcParams['animation.ffmpeg_path'] = r'D:\ruanjian\ffmpeg-7.0.2-essentials_build\bin\ffmpeg.exe'
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(12, 6))
line, = ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
ax.set_title('保存为 MP4 的动画示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
ax.legend(fontsize=12)
ax.grid(True, linestyle='--', linewidth=0.5)
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
def update(frame):
phase = frame
y = np.sin(x + phase)
line.set_ydata(y)
return line,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
interval=50, blit=True)
# 动态保存:优先保存为 MP4,如果 ffmpeg 不可用,则保存为 GIF
if FFMpegWriter.isAvailable():
print("ffmpeg 可用,保存为 MP4 格式")
ani.save('sine_wave_animation.mp4', writer='ffmpeg', fps=30)
else:
print("ffmpeg 不可用,保存为 GIF 格式")
ani.save('sine_wave_animation.gif', writer='pillow', fps=30)
plt.show()
if __name__ == "__main__":
main()
运行说明
安装 FFmpeg:
下载与安装: 访问 FFmpeg 官方网站 下载适用于 Windows 的版本,并按照安装向导完成安装。
添加到 PATH: 将 FFmpeg 的
bin
目录(包含ffmpeg.exe
)添加到系统的PATH
环境变量中。验证安装: 在命令提示符中运行以下命令,确保 FFmpeg 安装正确:
ffmpeg -version
运行脚本: 在命令行中运行以下命令:
python demo_save_mp4.py
查看生成的 MP4: 运行脚本后,将在当前工作目录生成
sine_wave_animation.mp4
文件。使用支持 MP4 播放的应用程序(如 VLC、Windows Media Player 等)打开查看动画效果。
代码说明
后端设置:同 6.1.1 动态折线图。
中文字体和负号处理:同 6.1.1 动态折线图。
保存动画:
ani.save('sine_wave_animation.mp4', writer='ffmpeg', fps=30)
使用
ffmpeg
编写器将动画保存为 MP4 格式,并设置帧率为 30 帧每秒。
注意事项
FFmpeg 安装:
- 确保 FFmpeg 安装正确,并且
ffmpeg.exe
在系统的PATH
中可用。
- 确保 FFmpeg 安装正确,并且
编写器名称:
在某些系统上,可能需要使用
FFMpegWriter
:
from matplotlib.animation import FFMpegWriter writer = FFMpegWriter(fps=30) ani.save('sine_wave_animation.mp4', writer=writer)
文件权限:
- 确保有权限在目标目录中创建和写入文件。
6.3 动画示例与实践
为了更好地理解动画的创建与保存,以下提供一个综合示例,展示如何使用 FuncAnimation
创建并同时保存一个动态正弦波动画为 GIF 和 MP4 两种格式。
代码示例
# demo_save_gif_mp4.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation, ImageMagickWriter, FFMpegWriter
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
plt.rcParams['animation.ffmpeg_path'] = r'D:\ruanjian\ffmpeg-7.0.2-essentials_build\bin\ffmpeg.exe'
def main():
# 生成初始数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('综合动画示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
phase = frame
y = np.sin(x + phase)
line.set_ydata(y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
interval=50, blit=True, repeat=True)
# 保存动画为 GIF
gif_writer = ImageMagickWriter(fps=20)
ani.save('sine_wave_animation.gif', writer=gif_writer)
# 保存动画为 MP4
mp4_writer = FFMpegWriter(fps=30)
ani.save('sine_wave_animation.mp4', writer=mp4_writer)
# 显示图形(可选)
plt.show()
if __name__ == "__main__":
main()
运行说明
安装 ImageMagick 和 FFmpeg(参考 6.2.1 动画保存为 GIF 和 6.2.2 动画保存为视频格式)。
运行脚本: 在命令行中运行以下命令:
python demo_save_gif_mp4.py
查看生成的文件:
sine_wave_animation.gif
:适合在网页或文档中嵌入展示。sine_wave_animation.mp4
:适合在视频播放器中播放或嵌入到视频编辑项目中。
代码说明
同时保存为 GIF 和 MP4: 使用
ImageMagickWriter
和FFMpegWriter
分别保存动画为 GIF 和 MP4 格式。编写器实例化:
gif_writer = ImageMagickWriter(fps=20) ani.save('sine_wave_animation.gif', writer=gif_writer) mp4_writer = FFMpegWriter(fps=30) ani.save('sine_wave_animation.mp4', writer=mp4_writer)
优化动画:
- 使用
blit=True
优化绘图性能,仅更新变化的部分。 - 设置合适的帧率(
fps
)以平衡动画的流畅性和文件大小。
- 使用
6.4 高级动画技巧
Matplotlib 的动画功能不仅限于简单的折线图和散点图,还支持更复杂的动画效果,如多子图动画、动态注释、动画中的交互元素等。以下是一些高级动画技巧的简要介绍。
6.4.1 多子图动画
在一个图形中包含多个子图,并分别为每个子图创建动画效果。例如,在一个窗口中同时展示正弦波和余弦波的动态变化。
代码示例
# demo_multi_subplot_animation.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
plt.rcParams['animation.ffmpeg_path'] = r'D:\ruanjian\ffmpeg-7.0.2-essentials_build\bin\ffmpeg.exe'
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
# 创建图形和子图
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))
# 绘制初始折线图
line1, = ax1.plot(x, np.sin(x), label='正弦波', color='blue', linewidth=2)
line2, = ax2.plot(x, np.cos(x), label='余弦波', color='green', linewidth=2)
# 添加标题和标签
ax1.set_title('正弦波动画', fontsize=14, fontweight='bold')
ax1.set_xlabel('角度 $x$ (弧度)', fontsize=12)
ax1.set_ylabel('函数值 $y$', fontsize=12)
ax1.legend(fontsize=10)
ax1.grid(True, linestyle='--', linewidth=0.5)
ax2.set_title('余弦波动画', fontsize=14, fontweight='bold')
ax2.set_xlabel('角度 $x$ (弧度)', fontsize=12)
ax2.set_ylabel('函数值 $y$', fontsize=12)
ax2.legend(fontsize=10)
ax2.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax1.set_xlim(0, 4 * np.pi)
ax1.set_ylim(-1.5, 1.5)
ax2.set_xlim(0, 4 * np.pi)
ax2.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
phase = frame
y1 = np.sin(x + phase)
y2 = np.cos(x + phase)
line1.set_ydata(y1)
line2.set_ydata(y2)
return line1, line2
# 创建动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
interval=50, blit=True, repeat=True)
# 保存动画为 GIF
ani.save('sine_cosine_animation.gif', writer='imagemagick')
# 保存动画为 MP4
ani.save('sine_cosine_animation.mp4', writer='ffmpeg', fps=30)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
确保 ImageMagick 和 FFmpeg 已安装(参考 6.2.1 动画保存为 GIF 和 6.2.2 动画保存为视频格式)。
运行脚本: 在命令行中运行以下命令:
python demo_multi_subplot_animation.py
查看生成的文件:
sine_cosine_animation.gif
:适合在网页或文档中嵌入展示。sine_cosine_animation.mp4
:适合在视频播放器中播放或嵌入到视频编辑项目中。
代码说明
- 创建多个子图: 使用
plt.subplots(2, 1)
创建两个子图,分别用于正弦波和余弦波。 - 独立绘图与注释: 为每个子图绘制初始折线图,并添加各自的标题、标签、图例和网格线。
- 更新函数: 在更新函数中,分别更新正弦波和余弦波的数据。
- 动画创建: 使用
FuncAnimation
同时更新两个子图,实现多子图动画效果。
6.4.2 动态注释与高亮
在动画中动态添加注释或高亮特定区域,增强数据的解释和展示效果。以下示例展示了如何在动画中动态添加注释,标注正弦波的峰值和谷值。
代码示例
# demo_dynamic_annotations.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
plt.rcParams['animation.ffmpeg_path'] = r'D:\ruanjian\ffmpeg-7.0.2-essentials_build\bin\ffmpeg.exe'
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, np.sin(x), label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('动态注释与高亮示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 添加初始注释(隐藏)
peak_annotation = ax.annotate('峰值', xy=(np.pi / 2, 1), xycoords='data',
xytext=(np.pi / 2 + 0.5, 1.3), textcoords='data',
arrowprops=dict(arrowstyle="->", connectionstyle="arc3"),
fontsize=12, color='red', visible=False)
trough_annotation = ax.annotate('谷值', xy=(3 * np.pi / 2, -1), xycoords='data',
xytext=(3 * np.pi / 2 - 1, -1.3), textcoords='data',
arrowprops=dict(arrowstyle="->", connectionstyle="arc3"),
fontsize=12, color='green', visible=False)
# 定义更新函数
def update(frame):
phase = frame
y = np.sin(x + phase)
line.set_ydata(y)
# 动态显示注释
if phase >= 0 and phase < np.pi:
peak_annotation.set_visible(True)
trough_annotation.set_visible(False)
elif phase >= np.pi and phase < 2 * np.pi:
peak_annotation.set_visible(False)
trough_annotation.set_visible(True)
return line, peak_annotation, trough_annotation
# 创建动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
interval=50, blit=True, repeat=True)
# 保存动画为 GIF
ani.save('dynamic_annotations.gif', writer='imagemagick')
# 保存动画为 MP4
ani.save('dynamic_annotations.mp4', writer='ffmpeg', fps=30)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
确保 ImageMagick 和 FFmpeg 已安装(参考 6.2.1 动画保存为 GIF 和 6.2.2 动画保存为视频格式)。
运行脚本: 在命令行中运行以下命令:
python demo_dynamic_annotations.py
查看生成的文件:
dynamic_annotations.gif
:适合在网页或文档中嵌入展示。dynamic_annotations.mp4
:适合在视频播放器中播放或嵌入到视频编辑项目中。
代码说明
- 动态注释创建:
- 使用
ax.annotate()
创建两个注释对象,分别用于标注峰值和谷值。 - 初始设置为
visible=False
,在动画中根据相位动态显示。
- 使用
- 更新函数:
- 根据当前相位,决定显示峰值或谷值的注释。
- 使用
peak_annotation.set_visible(True/False)
和trough_annotation.set_visible(True/False)
控制注释的可见性。
- 保存动画: 同时保存为 GIF 和 MP4 格式,便于不同用途的展示。
6.4.3 交互式动画
通过结合 ipywidgets
,可以创建具有交互功能的动画,例如通过滑块控制动画的参数。以下示例展示了如何使用 ipywidgets
创建一个交互式动画,允许用户通过滑块调整正弦波的相位。
代码示例
# demo_interactive_animation.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
import ipywidgets as widgets
from IPython.display import display
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
plt.rcParams['animation.ffmpeg_path'] = r'D:\ruanjian\ffmpeg-7.0.2-essentials_build\bin\ffmpeg.exe'
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('交互式动画示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(phase):
y = np.sin(x + phase)
line.set_ydata(y)
fig.canvas.draw_idle()
# 创建滑块控件
phase_slider = widgets.FloatSlider(value=0, min=0, max=2*np.pi, step=0.1,
description='相位:', continuous_update=True)
# 绑定滑块与更新函数
widgets.interactive(update, phase=phase_slider)
# 显示滑块
display(phase_slider)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
安装
ipywidgets
:pip install ipywidgets
启用 Jupyter 扩展: 对于 Jupyter Notebook:
jupyter nbextension enable --py widgetsnbextension
对于 JupyterLab:
jupyter labextension install @jupyter-widgets/jupyterlab-manager
运行脚本: 在 Jupyter Notebook 中运行以下命令:
%run demo_interactive_animation.py
或者在 JupyterLab 中直接打开并运行脚本。
代码说明
导入
ipywidgets
:import ipywidgets as widgets from IPython.display import display
用于创建和显示交互控件。
创建滑块控件:
phase_slider = widgets.FloatSlider(value=0, min=0, max=2*np.pi, step=0.1, description='相位:', continuous_update=True)
绑定滑块与更新函数:
widgets.interactive(update, phase=phase_slider)
将滑块的值绑定到更新函数,实现实时更新动画。
更新函数:
def update(phase): y = np.sin(x + phase) line.set_ydata(y) fig.canvas.draw_idle()
根据滑块的相位值更新正弦波的数据,并刷新图形。
注意事项
- 环境兼容性:
ipywidgets
更适用于 Jupyter Notebook 和 JupyterLab 环境。- 在标准 Python 脚本或其他 IDE 中,可能无法正常显示交互控件。
- 安装与启用扩展: 确保
ipywidgets
的相关扩展已正确安装并启用,以支持交互控件的显示与使用。
6.5 动画优化与性能提升
在创建复杂动画时,性能可能成为一个挑战。以下是一些优化动画性能的方法,确保动画流畅且资源高效。
6.5.1 使用 blit
参数优化绘图
blit
参数用于优化动画性能,仅更新变化的部分,减少绘图的开销。启用 blit=True
可以显著提升动画的运行效率,特别是在帧数较多或图形复杂时。
代码示例
# demo_optimized_animation.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
plt.rcParams['animation.ffmpeg_path'] = r'D:\ruanjian\ffmpeg-7.0.2-essentials_build\bin\ffmpeg.exe'
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('优化动画示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
phase = frame
y = np.sin(x + phase)
line.set_ydata(y)
return line,
# 创建动画,启用 blit
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
interval=50, blit=True)
# 保存动画为 MP4(可选)
# ani.save('optimized_animation.mp4', writer='ffmpeg', fps=30)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
确保 FFmpeg 已安装(参考 6.2.2 动画保存为视频格式),如果需要保存动画。
运行脚本: 在命令行中运行以下命令:
python demo_optimized_animation.py
代码说明
启用
blit=True
:ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128), interval=50, blit=True)
仅更新变化的绘图对象,减少绘图开销,提高性能。
返回更新的对象:
return line,
更新函数必须返回一个可迭代对象,包含所有需要更新的绘图对象。
注意事项
- 后端兼容性:
blit=True
在某些后端(如TkAgg
)下效果最佳,但在某些复杂场景下可能需要调整。 - 适用性:
blit=True
适用于仅需更新部分绘图对象的简单动画,对于需要频繁添加或移除绘图对象的复杂动画,可能需要禁用blit
。
6.5.2 使用更高效的数据结构
在处理大量数据点或频繁更新的数据时,选择更高效的数据结构和绘图方法可以显著提升动画性能。例如,使用 NumPy 数组进行数据存储和更新,避免在循环中频繁创建新对象。
代码示例
# demo_efficient_animation.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
frames = np.linspace(0, 2*np.pi, 128)
y_frames = np.sin(x[:, np.newaxis] + frames) # 预计算所有帧的 Y 数据
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y_frames[:, 0], label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('优化数据处理示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
y = y_frames[:, frame]
line.set_ydata(y)
return line,
# 创建动画,启用 blit
ani = FuncAnimation(fig, update, frames=range(frames.size),
interval=50, blit=True)
# 保存动画为 MP4(可选)
# ani.save('efficient_animation.mp4', writer='ffmpeg', fps=30)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
确保 FFmpeg 已安装(参考 6.2.2 动画保存为视频格式),如果需要保存动画。
运行脚本: 在命令行中运行以下命令:
python demo_efficient_animation.py
代码说明
预计算 Y 数据:
y_frames = np.sin(x[:, np.newaxis] + frames)
使用 NumPy 的广播机制,预先计算所有帧的 Y 数据,避免在更新函数中进行计算。
高效数据更新:
def update(frame): y = y_frames[:, frame] line.set_ydata(y) return line,
直接从预计算的数组中获取当前帧的 Y 数据,快速更新绘图对象。
动画创建: 使用
FuncAnimation
根据预计算的数据快速生成动画。
注意事项
- 内存消耗: 预计算所有帧的数据可能会增加内存消耗,特别是对于大型数据集。需根据具体情况权衡。
- 适用场景: 适用于帧数固定且数据变化规律已知的场景,不适用于实时数据或复杂数据生成过程。
6.6 动态更新图表的最佳实践
在创建动态更新的图表和动画时,遵循一些最佳实践可以帮助您创建高效、清晰且专业的可视化效果。
6.6.1 避免在循环中频繁创建对象
在动画循环中频繁创建新的绘图对象(如 Line2D
、Text
等)会导致性能下降和内存泄漏。应尽量在循环外创建一次绘图对象,并在循环中更新其数据。
示例
# demo_best_practice.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 创建一次性的绘图对象
line, = ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('最佳实践示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
y = np.sin(x + frame)
line.set_ydata(y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
interval=50, blit=True)
# 保存动画为 MP4(可选)
# ani.save('best_practice_animation.mp4', writer='ffmpeg', fps=30)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
代码说明
创建一次性的绘图对象: 在循环外创建
line
对象,避免在更新函数中反复创建新对象。更新函数仅更新数据:
def update(frame): y = np.sin(x + frame) line.set_ydata(y) return line,
仅更新
line
的 Y 数据,实现高效的动画效果。
6.6.2 优化数据处理与计算
在动画中,数据处理和计算的效率直接影响动画的流畅度。应尽量使用高效的 NumPy 操作,避免在更新函数中进行复杂或耗时的计算。
示例
# demo_optimized_data_processing.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
frames = np.linspace(0, 2*np.pi, 128)
y_frames = np.sin(x[:, np.newaxis] + frames) # 预计算所有帧的 Y 数据
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y_frames[:, 0], label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('优化数据处理示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
y = y_frames[:, frame]
line.set_ydata(y)
return line,
# 创建动画,启用 blit
ani = FuncAnimation(fig, update, frames=range(frames.size),
interval=50, blit=True)
# 保存动画为 MP4(可选)
# ani.save('optimized_data_processing.mp4', writer='ffmpeg', fps=30)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
代码说明
预计算数据: 使用 NumPy 的广播机制,预先计算所有帧的 Y 数据,避免在更新函数中进行计算。
高效数据更新:
def update(frame): y = y_frames[:, frame] line.set_ydata(y) return line,
直接从预计算的数组中获取当前帧的 Y 数据,快速更新绘图对象。
注意事项
- 内存消耗: 预计算所有帧的数据可能会增加内存消耗,特别是对于大型数据集。需根据具体情况权衡。
- 适用场景: 适用于帧数固定且数据变化规律已知的场景,不适用于实时数据或复杂数据生成过程。
6.6.3 使用缓存与优化绘图对象
利用 Matplotlib 的缓存机制和优化绘图对象的属性,可以进一步提升动画性能。例如,使用 Line2D
对象的 set_data
方法替代 set_ydata
,或调整绘图对象的属性以减少渲染开销。
示例
# demo_cache_optimization.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot([], [], label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('优化绘图对象示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 初始化绘图对象
def init():
line.set_data([], [])
return line,
# 定义更新函数
def update(frame):
phase = frame
y = np.sin(x + phase)
line.set_data(x, y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, interval=50, blit=True)
# 保存动画为 MP4(可选)
# ani.save('cache_optimization.mp4', writer='ffmpeg', fps=30)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
代码说明
初始化函数:
def init(): line.set_data([], []) return line,
定义一个初始化函数,用于设置动画开始时的绘图对象状态。
使用
set_data
方法:line.set_data(x, y)
使用
set_data
方法同时更新 X 和 Y 数据,提供更高效的更新方式。动画创建: 使用
FuncAnimation
并指定init_func
,确保动画开始时绘图对象处于正确状态。
注意事项
- 动画开始状态: 使用
init_func
可以确保动画开始时绘图对象的状态一致,避免不必要的渲染开销。 - 方法选择:
set_data
方法比单独的set_ydata
更高效,尤其是在同时更新 X 和 Y 数据时。
6.7 动画中的交互元素
在动画中添加交互元素(如按钮、滑块、文本输入等)可以增强用户的控制和数据探索能力。以下示例展示了如何在动画中添加按钮,允许用户启动和停止动画。
代码示例
# demo_interactive_buttons.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
import ipywidgets as widgets
from IPython.display import display
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
y = np.sin(x)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始折线图
line, = ax.plot(x, y, label='正弦波', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('交互式按钮控制动画示例', fontsize=16, fontweight='bold')
ax.set_xlabel('角度 $x$ (弧度)', fontsize=14)
ax.set_ylabel('函数值 $y$', fontsize=14)
# 添加图例
ax.legend(fontsize=12)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
phase = frame
y = np.sin(x + phase)
line.set_ydata(y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
interval=50, blit=True, repeat=True)
# 创建控制按钮
play_button = widgets.Button(description="播放", button_style='success')
pause_button = widgets.Button(description="暂停", button_style='warning')
# 定义按钮回调函数
def on_play_clicked(b):
ani.event_source.start()
def on_pause_clicked(b):
ani.event_source.stop()
# 绑定按钮与回调函数
play_button.on_click(on_play_clicked)
pause_button.on_click(on_pause_clicked)
# 显示按钮
display(widgets.HBox([play_button, pause_button]))
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
安装
ipywidgets
(参考 6.4.3 交互式动画)。启用 Jupyter 扩展(参考 6.4.3 交互式动画)。
运行脚本: 在 Jupyter Notebook 中运行以下命令:
%run demo_interactive_buttons.py
或者在 JupyterLab 中直接打开并运行脚本。
代码说明
创建控制按钮:
play_button = widgets.Button(description="播放", button_style='success') pause_button = widgets.Button(description="暂停", button_style='warning')
创建“播放”和“暂停”按钮,设置按钮样式以增强可视化效果。
定义按钮回调函数:
def on_play_clicked(b): ani.event_source.start() def on_pause_clicked(b): ani.event_source.stop()
定义按钮点击时的行为,控制动画的启动和停止。
绑定按钮与回调函数:
play_button.on_click(on_play_clicked) pause_button.on_click(on_pause_clicked)
显示按钮:
display(widgets.HBox([play_button, pause_button]))
使用
widgets.HBox
将按钮水平排列,并在 Notebook 中显示。
注意事项
- 环境兼容性:
ipywidgets
更适用于 Jupyter Notebook 和 JupyterLab 环境。- 在标准 Python 脚本或其他 IDE 中,可能无法正常显示交互控件。
- 安装与启用扩展: 确保
ipywidgets
的相关扩展已正确安装并启用,以支持交互控件的显示与使用。
6.8 动画调试与错误排查
在创建动画过程中,可能会遇到各种问题和错误。以下是一些常见问题的解决方法和调试技巧,帮助您快速定位和解决动画相关的问题。
6.8.1 动画不显示或显示不完整
可能原因:
- 缺少必要的库或编写器:
- 保存动画为 GIF 或 MP4 时,可能缺少 ImageMagick 或 FFmpeg。
- 后端配置不正确:
- 在 Jupyter Notebook 中,使用了不兼容的 Matplotlib 后端。
- 动画对象未正确返回:
- 更新函数未返回所有需要更新的绘图对象。
解决方法:
安装必要的库
:
- 确保已安装 ImageMagick 和 FFmpeg,并将其
bin
目录添加到系统的PATH
中。
- 确保已安装 ImageMagick 和 FFmpeg,并将其
检查后端配置
:
- 在脚本开头设置正确的后端(如
TkAgg
)。
- 在脚本开头设置正确的后端(如
确保更新函数正确返回对象
:
- 更新函数应返回一个可迭代对象,包含所有需要更新的绘图对象。
示例:
# 定义更新函数,确保返回所有更新的对象
def update(frame):
phase = frame
y = np.sin(x + phase)
line.set_ydata(y)
return line, # 返回一个元组
6.8.2 动画保存失败或生成错误
可能原因:
- 编写器未安装或未在
PATH
中:- ImageMagick 或 FFmpeg 未安装,或其
bin
目录未添加到PATH
中。
- ImageMagick 或 FFmpeg 未安装,或其
- 文件权限问题:
- 没有权限在指定目录中创建或写入文件。
- 参数配置错误:
- 保存函数的参数配置不正确,如错误的编写器名称或文件路径。
解决方法:
安装并配置编写器
:
- 安装 ImageMagick 和 FFmpeg,并确保其
bin
目录在PATH
中。 - 通过命令提示符运行
magick -version
和ffmpeg -version
验证安装是否成功。
- 安装 ImageMagick 和 FFmpeg,并确保其
检查文件权限
:
- 确保有权限在目标目录中创建和写入文件。
正确配置保存函数
:
- 使用正确的编写器名称和有效的文件路径。
示例:
# 保存动画为 MP4,指定正确的编写器
ani.save('animation.mp4', writer='ffmpeg', fps=30)
6.8.3 动画运行缓慢或卡顿
可能原因:
- 绘图对象过多或过于复杂:
- 在一个图形中包含过多的绘图对象,导致渲染开销大。
- 更新函数中存在耗时操作:
- 在更新函数中进行复杂的计算或数据处理。
- 使用了不高效的绘图方法:
- 使用了不必要的绘图方法或属性更新方式。
解决方法:
简化绘图对象
:
- 减少图形中的绘图对象数量,简化图表结构。
优化更新函数
:
- 将耗时的计算移出更新函数,预先计算或使用高效的算法。
使用高效的绘图方法
:
- 使用
set_ydata
或set_data
方法更新数据,而不是重新绘制对象。
- 使用
示例:
# 优化更新函数,避免复杂计算
def update(frame):
y = np.sin(x + frame)
line.set_ydata(y)
return line,
6.9 动画示例与应用案例
为了更好地理解动画在实际数据可视化中的应用,以下提供一些具体的应用案例和示例,展示动画在不同领域的数据展示中的优势。
6.9.1 科学数据可视化
在科学研究中,动画常用于展示实验数据、模拟结果和理论模型的动态变化。例如,展示波动现象、电磁场变化或天体运动。
示例:展示波动现象
# demo_wave_animation.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成数据
x = np.linspace(0, 4 * np.pi, 400)
frames = 200 # 总帧数
y_frames = np.sin(x - 0.05 * np.arange(frames)[:, np.newaxis])
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始波形
line, = ax.plot(x, y_frames[0], label='波形', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('波动现象动画', fontsize=16, fontweight='bold')
ax.set_xlabel('位置 $x$', fontsize=14)
ax.set_ylabel('振幅 $A$', fontsize=14)
# 添加图例和网格线
ax.legend(fontsize=12)
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 4 * np.pi)
ax.set_ylim(-1.5, 1.5)
# 定义更新函数
def update(frame):
y = y_frames[frame]
line.set_ydata(y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=frames, interval=50, blit=True)
# 保存动画为 GIF(可选)
# ani.save('wave_animation.gif', writer='imagemagick')
# 保存动画为 MP4(可选)
# ani.save('wave_animation.mp4', writer='ffmpeg', fps=20)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
效果说明
- 该动画展示了一个沿着 X 轴传播的正弦波,模拟波动现象的动态变化。
6.9.2 财务数据分析
在财务分析中,动画可用于展示股票价格的动态变化、市场趋势和投资组合的表现。
示例:动态展示股票价格
# demo_stock_animation.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 生成模拟股票价格数据
np.random.seed(0)
days = np.linspace(0, 100, 100)
price = 50 + np.cumsum(np.random.randn(100)) # 随机游走
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始价格线
line, = ax.plot([], [], label='股票价格', color='green', linewidth=2)
# 添加标题和标签
ax.set_title('股票价格动态变化', fontsize=16, fontweight='bold')
ax.set_xlabel('天数', fontsize=14)
ax.set_ylabel('价格 ($)', fontsize=14)
# 添加图例和网格线
ax.legend(fontsize=12)
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 100)
ax.set_ylim(min(price) - 5, max(price) + 5)
# 定义初始化函数
def init():
line.set_data([], [])
return line,
# 定义更新函数
def update(frame):
x = days[:frame]
y = price[:frame]
line.set_data(x, y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=len(days),
init_func=init, interval=100, blit=True)
# 保存动画为 MP4(可选)
# ani.save('stock_price_animation.mp4', writer='ffmpeg', fps=10)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
效果说明
- 该动画模拟了股票价格随时间的动态变化,展示了价格的波动趋势。
6.9.3 工程与设计展示
在工程与设计领域,动画可用于展示设计方案的演变、结构的应力分布或机械部件的运动。
示例:展示机械臂的运动
# demo_robot_arm_animation.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 定义机械臂参数
length1 = 2
length2 = 1.5
frames = 200 # 总帧数
angles1 = np.linspace(0, 2 * np.pi, frames)
angles2 = np.linspace(0, 4 * np.pi, frames)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_xlim(-4, 4)
ax.set_ylim(-4, 4)
ax.set_aspect('equal')
ax.grid(True, linestyle='--', linewidth=0.5)
# 初始化机械臂线条
line1, = ax.plot([], [], lw=4, color='blue')
line2, = ax.plot([], [], lw=4, color='red')
# 添加标题
ax.set_title('机械臂运动动画', fontsize=16, fontweight='bold')
# 定义初始化函数
def init():
line1.set_data([], [])
line2.set_data([], [])
return line1, line2
# 定义更新函数
def update(frame):
theta1 = angles1[frame]
theta2 = angles2[frame]
# 计算关节位置
x1 = length1 * np.cos(theta1)
y1 = length1 * np.sin(theta1)
x2 = x1 + length2 * np.cos(theta1 + theta2)
y2 = y1 + length2 * np.sin(theta1 + theta2)
# 更新线条数据
line1.set_data([0, x1], [0, y1])
line2.set_data([x1, x2], [y1, y2])
return line1, line2
# 创建动画
ani = FuncAnimation(fig, update, frames=frames,
init_func=init, interval=50, blit=True)
# 保存动画为 GIF
ani.save('robot_arm_animation.gif', writer='imagemagick')
# 保存动画为 MP4
ani.save('robot_arm_animation.mp4', writer='ffmpeg', fps=30)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
效果说明
- 该动画展示了一个机械臂的运动过程,模拟了机械关节的旋转和机械臂末端的移动。
6.10 总结
动画与动态图形在数据可视化中扮演着重要角色,能够有效地展示数据的动态变化和复杂过程。通过 Matplotlib 提供的多种工具和方法,用户可以创建从简单到复杂的动画效果,并将其保存为多种格式以满足不同的展示需求。
关键点总结:
- 创建动态图形:
- 使用循环和
plt.ion()
实现简单的动态折线图和散点图。 - 使用
FuncAnimation
实现更高效、复杂的动画效果。
- 使用循环和
- 动画保存与导出:
- 使用 ImageMagick 和 FFmpeg 保存动画为 GIF 和 MP4 格式。
- 确保相关编写器已正确安装并配置在系统
PATH
中。
- 优化动画性能:
- 启用
blit=True
优化绘图性能。 - 使用高效的数据结构和预计算方法减少计算开销。
- 启用
- 添加交互元素:
- 结合
ipywidgets
添加按钮、滑块等控件,增强动画的交互性和用户控制。
- 结合
- 动画调试与错误排查:
- 确保编写器安装正确,后端配置适当。
- 避免在循环中频繁创建绘图对象,优化更新函数。
7. 实践与项目
7.1 数据可视化项目
数据可视化项目是将理论知识应用于实际数据的绝佳途径。通过项目,您可以深入挖掘数据中的模式、趋势和关系,并有效地向他人传达这些信息。
7.1.1 使用 Matplotlib 进行数据可视化项目
本节将通过一个完整的项目示例,展示如何使用 Matplotlib 进行数据可视化。我们将以动态展示股票价格变化为例,演示如何创建、更新和保存动画。
项目示例:动态展示股票价格
假设我们拥有一组模拟的股票价格数据,旨在动态展示其随时间的变化趋势。以下是实现这一目标的步骤和代码示例。
代码示例
# demo_save_mp4.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation, FFMpegWriter
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体为“SimHei”
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
plt.rcParams['text.usetex'] = False # 禁用 LaTeX 渲染
def main():
# 生成模拟股票价格数据
np.random.seed(0)
days = np.linspace(0, 100, 100) # 100天
price = 50 + np.cumsum(np.random.randn(100)) # 随机游走生成价格
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制初始价格线
line, = ax.plot([], [], label='股票价格', color='green', linewidth=2)
# 添加标题和标签
ax.set_title('股票价格动态变化', fontsize=16, fontweight='bold')
ax.set_xlabel('天数', fontsize=14)
ax.set_ylabel('价格 ($)', fontsize=14)
# 添加图例和网格线
ax.legend(fontsize=12)
ax.grid(True, linestyle='--', linewidth=0.5)
# 设置坐标轴范围
ax.set_xlim(0, 100)
ax.set_ylim(min(price) - 5, max(price) + 5)
# 定义初始化函数
def init():
line.set_data([], [])
return line,
# 定义更新函数
def update(frame):
x = days[:frame]
y = price[:frame]
line.set_data(x, y)
return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=len(days),
init_func=init, interval=100, blit=True)
# 指定 FFmpeg 的路径(根据您的安装路径修改)
# 如果 FFmpeg 已添加到系统 PATH 中,可以省略此步骤
plt.rcParams['animation.ffmpeg_path'] = r'D:\ruanjian\ffmpeg-7.0.2-essentials_build\bin\ffmpeg.exe' # 示例路径
# 创建 FFMpegWriter 实例
writer = FFMpegWriter(fps=10, metadata=dict(artist='Me'), bitrate=1800)
# 保存动画为 MP4
ani.save('stock_price_animation.mp4', writer=writer)
# 显示图形(可选)
plt.show()
if __name__ == "__main__":
main()
运行说明
确认 FFmpeg 的路径
根据您的系统配置,确认
ffmpeg.exe
的路径。例如:D:\ruanjian\ffmpeg-7.0.2-essentials_build\bin\ffmpeg.exe
确保路径正确,并且
ffmpeg.exe
文件存在。运行脚本
在命令提示符或终端中导航到脚本所在的目录。
运行以下命令:
python demo_save_mp4.py
查看生成的 MP4 文件
脚本运行后,将在当前工作目录生成
stock_price_animation.mp4
文件。您可以使用支持 MP4 播放的媒体播放器(如 VLC、Windows Media Player)打开并查看动画效果。
代码说明
后端设置
import matplotlib matplotlib.use('TkAgg') # 设置后端为 TkAgg
确保 Matplotlib 使用
TkAgg
后端来渲染图形,适用于大多数标准 Python 脚本和 IDE(如 VS Code、PyCharm 等)。中文字体和负号处理
plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False plt.rcParams['text.usetex'] = False
设置中文字体为“SimHei”,解决中文字符显示问题,并禁用 LaTeX 渲染以避免相关错误。
动画创建与保存
- 使用
FuncAnimation
创建动画,通过update
函数逐帧更新股票价格线。 - 使用
FFMpegWriter
将动画保存为 MP4 格式。
- 使用
优化
- 启用
blit=True
参数,仅更新变化的部分,提高动画性能。
- 启用
注意事项
- FFmpeg 安装与配置
- 确保 FFmpeg 已正确安装,并且其
bin
目录已添加到系统的PATH
中。 - 通过在命令提示符中运行
ffmpeg -version
来验证 FFmpeg 是否安装正确。
- 确保 FFmpeg 已正确安装,并且其
- 文件权限
- 确保您有权限在目标目录中创建和写入文件。
- 编码问题
- 如果在保存过程中遇到编码错误,确保文件路径和名称不包含特殊字符,或使用原始字符串(在路径字符串前加
r
)避免转义字符的问题。
- 如果在保存过程中遇到编码错误,确保文件路径和名称不包含特殊字符,或使用原始字符串(在路径字符串前加
7.1.2 从 Pandas 读取数据并绘制图表
Pandas 是一个功能强大的数据处理库,与 Matplotlib 结合使用,可以极大地简化数据读取、处理和可视化的过程。在 Pandas 的数据框(DataFrame)对象上直接调用绘图方法,可以快速生成各种类型的图表。
项目示例:可视化气温变化数据
假设我们有一个包含每日气温变化的数据集,存储在 temperature_data.csv
文件中。我们将使用 Pandas 读取该数据,并使用 Matplotlib 绘制气温随时间的变化趋势。
示例 CSV 文件内容 (temperature_data.csv
)
日期,最高气温,最低气温
2024-01-01,10,2
2024-01-02,12,3
2024-01-03,11,4
2024-01-04,13,5
2024-01-05,14,6
...
代码示例
# demo_pandas_matplotlib.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 从 CSV 文件读取数据
data = pd.read_csv('temperature_data.csv', parse_dates=['日期'])
# 检查数据
print(data.head())
# 设置日期为索引
data.set_index('日期', inplace=True)
# 创建图形和子图
fig, ax = plt.subplots(figsize=(14, 7))
# 绘制最高气温和最低气温
ax.plot(data.index, data['最高气温'], label='最高气温', color='red', linewidth=2)
ax.plot(data.index, data['最低气温'], label='最低气温', color='blue', linewidth=2)
# 添加标题和标签
ax.set_title('每日气温变化趋势', fontsize=18, fontweight='bold')
ax.set_xlabel('日期', fontsize=14)
ax.set_ylabel('气温 (°C)', fontsize=14)
# 格式化日期显示
fig.autofmt_xdate()
# 添加图例和网格线
ax.legend(fontsize=12)
ax.grid(True, linestyle='--', linewidth=0.5)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
准备数据
- 创建一个名为
temperature_data.csv
的 CSV 文件,并填入示例数据或实际气温数据。
- 创建一个名为
运行脚本
在命令提示符或终端中导航到脚本所在的目录。
运行以下命令:
python demo_pandas_matplotlib.py
查看图表
- 脚本将生成并显示一个包含最高气温和最低气温变化趋势的折线图。
代码说明
数据读取与处理
data = pd.read_csv('temperature_data.csv', parse_dates=['日期']) data.set_index('日期', inplace=True)
使用 Pandas 读取 CSV 文件,并将日期列解析为日期类型。然后,将日期设置为数据框的索引,便于绘图。
绘图
ax.plot(data.index, data['最高气温'], label='最高气温', color='red', linewidth=2) ax.plot(data.index, data['最低气温'], label='最低气温', color='blue', linewidth=2)
使用 Matplotlib 绘制最高气温和最低气温的折线图,分别使用不同的颜色和标签。
图表美化
- 添加标题、轴标签。
- 使用
fig.autofmt_xdate()
自动格式化日期显示,避免日期标签重叠。 - 添加图例和网格线,提高图表的可读性。
注意事项
- 数据格式
- 确保 CSV 文件的格式正确,列名与代码中的列名一致。
- 日期列应为可解析的日期格式,以便 Pandas 正确读取。
- 缺失值处理
- 在读取和处理数据时,注意处理缺失值(如使用
dropna()
或填充缺失值)。
- 在读取和处理数据时,注意处理缺失值(如使用
- 日期范围
- 如果数据覆盖较长时间段,考虑调整图表的轴范围或使用分段绘图,以提高可读性。
7.1.3 将多个图表结合到一个项目中
在实际项目中,通常需要在一个图形中展示多个图表,以便更全面地分析和展示数据。Matplotlib 提供了多种方法来实现这一目标,包括使用子图(subplots)、网格布局(gridspec)等。
项目示例:气温与降水量综合可视化
假设我们有一个数据集,包含每日的气温和降水量数据。我们希望在一个图形中同时展示气温变化和降水量变化,以便更好地理解两者之间的关系。
示例 CSV 文件内容 (weather_data.csv
)
日期,最高气温,最低气温,降水量(mm)
2024-01-01,10,2,5
2024-01-02,12,3,0
2024-01-03,11,4,10
2024-01-04,13,5,0
2024-01-05,14,6,15
...
代码示例
# demo_combined_charts.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 从 CSV 文件读取数据
data = pd.read_csv('weather_data.csv', parse_dates=['日期'])
# 检查数据
print(data.head())
# 设置日期为索引
data.set_index('日期', inplace=True)
# 创建图形和子图(两个子图,垂直排列)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 10), sharex=True)
# 绘制最高气温和最低气温
ax1.plot(data.index, data['最高气温'], label='最高气温', color='red', linewidth=2)
ax1.plot(data.index, data['最低气温'], label='最低气温', color='blue', linewidth=2)
# 添加标题和标签
ax1.set_title('每日气温变化趋势', fontsize=16, fontweight='bold')
ax1.set_ylabel('气温 (°C)', fontsize=14)
# 添加图例和网格线
ax1.legend(fontsize=12)
ax1.grid(True, linestyle='--', linewidth=0.5)
# 绘制降水量
ax2.bar(data.index, data['降水量(mm)'], label='降水量', color='skyblue', width=0.8)
# 添加标题和标签
ax2.set_title('每日降水量', fontsize=16, fontweight='bold')
ax2.set_xlabel('日期', fontsize=14)
ax2.set_ylabel('降水量 (mm)', fontsize=14)
# 添加图例和网格线
ax2.legend(fontsize=12)
ax2.grid(True, linestyle='--', linewidth=0.5)
# 格式化日期显示
fig.autofmt_xdate()
# 设置坐标轴范围(可根据需要调整)
ax1.set_ylim(data['最低气温'].min() - 5, data['最高气温'].max() + 5)
ax2.set_ylim(0, data['降水量(mm)'].max() + 10)
# 调整子图间距
plt.tight_layout()
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
准备数据
- 创建一个名为
weather_data.csv
的 CSV 文件,并填入示例数据或实际气温与降水量数据。
- 创建一个名为
运行脚本
在命令提示符或终端中导航到脚本所在的目录。
运行以下命令:
python demo_combined_charts.py
查看图表
- 脚本将生成并显示一个包含两个子图的图形:上方为气温变化趋势,下面为降水量变化。
代码说明
创建多个子图
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 10), sharex=True)
使用
plt.subplots
创建两个垂直排列的子图,并共享 X 轴。绘制不同类型的图表
- 上方子图使用折线图展示最高气温和最低气温。
- 下方子图使用柱状图展示每日降水量。
图表美化
- 添加标题、轴标签。
- 使用
fig.autofmt_xdate()
自动格式化日期显示,避免日期标签重叠。 - 添加图例和网格线,提高图表的可读性。
注意事项
- 子图布局
plt.subplots
的第一个参数表示子图的行数,第二个参数表示子图的列数。例如,plt.subplots(2, 1)
表示创建两个垂直排列的子图。
- 共享轴
- 使用
sharex=True
参数可以让多个子图共享同一个 X 轴,避免重复显示 X 轴标签。
- 使用
- 图表类型选择
- 根据数据的特点选择合适的图表类型。例如,气温变化适合使用折线图,而降水量适合使用柱状图。
- 颜色和样式
- 使用不同颜色和线条样式区分不同的数据系列,增强图表的可读性。
7.2 Matplotlib 与其他库结合
Matplotlib 可以与多种 Python 数据科学库结合使用,以实现更强大的数据处理和可视化功能。以下是与 Pandas、Seaborn 和 Plotly 的结合使用示例。
7.2.1 与 Pandas 结合绘制图形
Pandas 与 Matplotlib 的紧密集成使得数据读取、处理和可视化过程更加简洁高效。在 Pandas 的数据框(DataFrame)对象上直接调用绘图方法,可以快速生成各种类型的图表。
项目示例:销售数据分析
假设我们有一份包含产品销售数据的 CSV 文件,我们希望使用 Pandas 读取数据,并使用 Matplotlib 绘制销售趋势图。
示例 CSV 文件内容 (sales_data.csv
)
日期,产品A,产品B,产品C
2024-01-01,100,150,200
2024-01-02,110,160,210
2024-01-03,120,170,220
2024-01-04,130,180,230
2024-01-05,140,190,240
...
代码示例
# demo_pandas_matplotlib_combined.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import pandas as pd
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 从 CSV 文件读取数据
data = pd.read_csv('sales_data.csv', parse_dates=['日期'])
data.set_index('日期', inplace=True)
# 检查数据
print(data.head())
# 使用 Pandas 的绘图方法绘制销售趋势
ax = data.plot(figsize=(14, 7), linewidth=2)
# 添加标题和标签
ax.set_title('产品销售趋势', fontsize=18, fontweight='bold')
ax.set_xlabel('日期', fontsize=14)
ax.set_ylabel('销售量', fontsize=14)
# 格式化日期显示
plt.gcf().autofmt_xdate()
# 添加图例和网格线
ax.legend(fontsize=12)
ax.grid(True, linestyle='--', linewidth=0.5)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
准备数据
- 创建一个名为
sales_data.csv
的 CSV 文件,并填入示例数据或实际销售数据。
- 创建一个名为
运行脚本
在命令提示符或终端中导航到脚本所在的目录。
运行以下命令:
python demo_pandas_matplotlib_combined.py
查看图表
- 脚本将生成并显示一个包含产品A、产品B和产品C销售趋势的折线图。
代码说明
数据读取与处理
data = pd.read_csv('sales_data.csv', parse_dates=['日期']) data.set_index('日期', inplace=True)
使用 Pandas 读取 CSV 文件,并将日期列解析为日期类型。然后,将日期设置为数据框的索引,便于绘图。
使用 Pandas 的绘图方法
ax = data.plot(figsize=(14, 7), linewidth=2)
使用 Pandas 的
plot
方法直接绘制折线图。此方法简化了与 Matplotlib 的交互,自动处理图例、颜色等细节。图表美化
- 添加标题、轴标签。
- 使用
plt.gcf().autofmt_xdate()
自动格式化日期显示,避免日期标签重叠。 - 添加图例和网格线,提高图表的可读性。
注意事项
- 数据索引
- 将日期设置为数据框的索引,可以使绘图过程更加便捷,并自动处理日期格式。
- 图表类型选择
- Pandas 的
plot
方法支持多种图表类型,如折线图、柱状图、散点图等。根据数据特点选择合适的图表类型。
- Pandas 的
- 样式定制
- 可以通过传递参数(如
linewidth
、color
等)来定制图表的样式,提升视觉效果。
- 可以通过传递参数(如
7.2.2 与 Seaborn 结合进行统计图形绘制
Seaborn 是一个基于 Matplotlib 的高级数据可视化库,提供了更简洁的接口和更美观的默认样式,特别适用于统计图形的绘制。与 Matplotlib 结合使用,Seaborn 可以显著提升数据可视化的效率和效果。
项目示例:绘制箱线图和散点图
假设我们有一份包含学生成绩和学习时间的数据集,我们希望使用 Seaborn 绘制箱线图和散点图,以分析成绩与学习时间之间的关系。
示例 CSV 文件内容 (student_scores.csv
)
学生,数学,语文,英语,学习时间(小时)
张三,85,78,90,5
李四,92,88,95,7
王五,75,70,80,3
赵六,88,82,85,6
孙七,90,85,92,8
...
代码示例
# demo_seaborn_combined.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 从 CSV 文件读取数据
data = pd.read_csv('student_scores.csv')
print(data.head())
# 设置图形风格
sns.set(style="whitegrid")
# 创建图形和子图(两个子图,水平排列)
fig, axes = plt.subplots(1, 2, figsize=(16, 8))
# 绘制箱线图
melted_data = pd.melt(data, id_vars=['学生', '学习时间(小时)'],
value_vars=['数学', '语文', '英语'],
var_name='科目', value_name='成绩')
sns.boxplot(x='科目', y='成绩', data=melted_data, ax=axes[0], palette="Set3")
axes[0].set_title('各科成绩分布', fontsize=16, fontweight='bold')
axes[0].set_xlabel('科目', fontsize=14)
axes[0].set_ylabel('成绩', fontsize=14)
# 绘制散点图
sns.scatterplot(x='学习时间(小时)', y='数学', data=data, ax=axes[1], color='blue', s=100, label='数学')
sns.scatterplot(x='学习时间(小时)', y='语文', data=data, ax=axes[1], color='green', s=100, label='语文')
sns.scatterplot(x='学习时间(小时)', y='英语', data=data, ax=axes[1], color='red', s=100, label='英语')
axes[1].set_title('学习时间与成绩关系', fontsize=16, fontweight='bold')
axes[1].set_xlabel('学习时间 (小时)', fontsize=14)
axes[1].set_ylabel('成绩', fontsize=14)
axes[1].legend(title='科目')
# 调整布局
plt.tight_layout()
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
准备数据
- 创建一个名为
student_scores.csv
的 CSV 文件,并填入示例数据或实际学生成绩和学习时间数据。
- 创建一个名为
运行脚本
在命令提示符或终端中导航到脚本所在的目录。
运行以下命令:
python demo_seaborn_combined.py
查看图表
- 脚本将生成并显示一个包含两个子图的图形:左侧为各科成绩的箱线图,右侧为学习时间与各科成绩的散点图。
代码说明
数据处理
melted_data = pd.melt(data, id_vars=['学生', '学习时间(小时)'], value_vars=['数学', '语文', '英语'], var_name='科目', value_name='成绩')
使用 Pandas 的
melt
函数将数据从宽格式转换为长格式,便于 Seaborn 绘制箱线图。绘制箱线图
sns.boxplot(x='科目', y='成绩', data=melted_data, ax=axes[0], palette="Set3")
使用 Seaborn 的
boxplot
函数绘制各科成绩分布的箱线图。绘制散点图
sns.scatterplot(x='学习时间(小时)', y='数学', data=data, ax=axes[1], color='blue', s=100, label='数学') sns.scatterplot(x='学习时间(小时)', y='语文', data=data, ax=axes[1], color='green', s=100, label='语文') sns.scatterplot(x='学习时间(小时)', y='英语', data=data, ax=axes[1], color='red', s=100, label='英语')
使用 Seaborn 的
scatterplot
函数绘制学习时间与各科成绩的关系图,分别使用不同颜色区分科目。图表美化
- 添加标题、轴标签。
- 使用不同颜色区分不同的数据系列,添加图例。
- 使用
plt.tight_layout()
自动调整子图间距,确保布局美观。
注意事项
- 数据格式
- 确保 CSV 文件的格式正确,列名与代码中的列名一致。
- 颜色选择
- 使用色板(如
palette="Set3"
)增强图表的美观性和可读性。
- 使用色板(如
- 图例管理
- 确保图例准确反映数据系列的信息,避免混淆。
7.2.3 与 Plotly 结合进行交互式图形展示
Plotly 是一个用于创建交互式图形的库,支持丰富的图表类型和交互功能。虽然 Matplotlib 主要用于静态图表,但通过与 Plotly 的结合使用,可以实现更具交互性的可视化效果。
项目示例:交互式散点图
假设我们有一份包含城市人口和面积的数据集,我们希望创建一个交互式散点图,允许用户通过悬停查看具体数据点的信息。
示例 CSV 文件内容 (city_data.csv
)
城市,人口(万人),面积(平方公里),省份
北京,2154,16410,北京
上海,2424,6340,上海
广州,1400,7434,广东
深圳,1300,1996,广东
天津,1567,11920,天津
...
代码示例
# demo_plotly_interactive.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import pandas as pd
import matplotlib.pyplot as plt
import plotly.express as px
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def main():
# 从 CSV 文件读取数据
data = pd.read_csv('city_data.csv')
print(data.head())
# 使用 Plotly 创建交互式散点图
fig = px.scatter(data, x='面积(平方公里)', y='人口(万人)',
size='人口(万人)', color='省份',
hover_name='城市',
title='城市人口与面积关系',
labels={'面积(平方公里)': '面积 (平方公里)', '人口(万人)': '人口 (万人)'},
template='plotly_dark')
# 显示交互式图形
fig.show()
# 如果需要将 Plotly 图表嵌入 Matplotlib 图形中,可以使用 plotly 的 Matplotlib 转换工具
# 但通常推荐直接使用 Plotly 进行交互式图形展示
# 下面是一个简单的 Matplotlib 图表示例
fig2, ax = plt.subplots(figsize=(10, 6))
scatter = ax.scatter(data['面积(平方公里)'], data['人口(万人)'],
s=data['人口(万人)']*10, c=pd.factorize(data['省份'])[0],
cmap='viridis', alpha=0.6, edgecolors='w', linewidth=0.5)
# 添加标题和标签
ax.set_title('城市人口与面积关系 (Matplotlib)', fontsize=16, fontweight='bold')
ax.set_xlabel('面积 (平方公里)', fontsize=14)
ax.set_ylabel('人口 (万人)', fontsize=14)
# 添加图例
legend1 = ax.legend(*scatter.legend_elements(),
title="省份", loc="upper right", fontsize=12)
ax.add_artist(legend1)
# 添加注释
for i, row in data.iterrows():
ax.annotate(row['城市'], (row['面积(平方公里)'], row['人口(万人)']),
textcoords="offset points", xytext=(0,10), ha='center', fontsize=9)
# 添加网格线
ax.grid(True, linestyle='--', linewidth=0.5)
# 显示图形
plt.show()
if __name__ == "__main__":
main()
运行说明
安装 Plotly
如果尚未安装 Plotly,可以使用以下命令安装:
pip install plotly
准备数据
- 创建一个名为
city_data.csv
的 CSV 文件,并填入示例数据或实际城市人口与面积数据。
- 创建一个名为
运行脚本
在命令提示符或终端中导航到脚本所在的目录。
运行以下命令:
python demo_plotly_interactive.py
查看图表
- 脚本将生成并显示一个交互式的 Plotly 散点图,您可以通过悬停查看具体城市的信息。同时,还会生成一个静态的 Matplotlib 散点图,展示相同的数据。
代码说明
使用 Plotly 创建交互式散点图
fig = px.scatter(data, x='面积(平方公里)', y='人口(万人)', size='人口(万人)', color='省份', hover_name='城市', title='城市人口与面积关系', labels={'面积(平方公里)': '面积 (平方公里)', '人口(万人)': '人口 (万人)'}, template='plotly_dark') fig.show()
使用
plotly.express.scatter
函数创建交互式散点图,参数说明:x
和y
:指定坐标轴数据。size
:根据人口数量调整点的大小。color
:根据省份区分点的颜色。hover_name
:悬停时显示的城市名称。title
和labels
:设置图表标题和轴标签。template
:设置图表主题样式。
结合 Matplotlib 绘制静态图表
fig2, ax = plt.subplots(figsize=(10, 6)) scatter = ax.scatter(data['面积(平方公里)'], data['人口(万人)'], s=data['人口(万人)']*10, c=pd.factorize(data['省份'])[0], cmap='viridis', alpha=0.6, edgecolors='w', linewidth=0.5)
使用 Matplotlib 绘制静态散点图,结合 Pandas 和 Matplotlib 的功能,实现数据的可视化。
图表美化
- 添加标题、轴标签。
- 使用不同颜色区分省份,添加图例。
- 添加注释标注每个数据点对应的城市名称。
- 添加网格线,提高图表的可读性。
注意事项
- 交互式图表环境
- Plotly 的交互式图表更适合在浏览器或支持 JavaScript 的环境中查看,如 Jupyter Notebook。
- 图表嵌入
- 虽然可以将 Plotly 图表嵌入到 Matplotlib 图形中,但通常推荐直接使用 Plotly 进行交互式图表的展示,以充分利用其交互功能。
- 性能考虑
- 对于大型数据集,交互式图表可能会影响性能。可以考虑数据抽样或优化图表配置,以提升响应速度。
7.3 综合项目案例
为了将前几章中学到的知识整合起来,我们将通过一个综合项目案例,展示如何使用 Matplotlib 及其与其他库的结合,完成一个完整的数据可视化任务。
7.3.1 项目背景
假设我们是一家市场分析公司,收集了不同地区的销售数据和客户满意度调查结果。我们的目标是分析销售额与客户满意度之间的关系,并向管理层提供可视化报告。
7.3.2 数据描述
我们的数据集包含以下字段:
- 地区:销售区域名称。
- 销售额:每个区域的月度销售额(万元)。
- 客户满意度:通过调查得出的客户满意度评分(1-10分)。
- 广告投入:每个区域的广告投入(万元)。
- 销售人员:每个区域的销售人员数量。
示例 CSV 文件内容 (sales_data1.csv
)
地区,销售额,客户满意度,广告投入,销售人员
北区,500,8,50,10
南区,450,7,45,9
东区,600,9,60,12
西区,400,6,40,8
中区,550,8,55,11
...
7.3.3 项目实施
我们将通过以下步骤完成项目:
- 数据读取与处理:使用 Pandas 读取和处理数据。
- 数据可视化:使用 Matplotlib 和 Seaborn 绘制各种图表。
- 交互式分析:使用 Plotly 创建交互式图表。
- 动画展示:创建动态销售趋势动画。
- 报告生成:整合所有图表,生成可视化报告。
步骤1:数据读取与处理
# project_sales_analysis.py
import matplotlib
# 设置后端为 TkAgg,确保在导入 pyplot 之前设置
matplotlib.use('TkAgg')
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
from matplotlib.animation import FuncAnimation, FFMpegWriter
import numpy as np
# 全局设置中文字体和负号显示,禁用 LaTeX 支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['text.usetex'] = False
def load_and_clean_data(filepath):
# 从 CSV 文件读取数据
data = pd.read_csv(filepath)
print("原始数据:")
print(data.head())
# 检查缺失值
print("\n缺失值统计:")
print(data.isnull().sum())
# 填充或删除缺失值(根据情况选择)
data.dropna(inplace=True)
# 确保数据类型正确
data['销售额'] = data['销售额'].astype(float)
data['客户满意度'] = data['客户满意度'].astype(float)
data['广告投入'] = data['广告投入'].astype(float)
data['销售人员'] = data['销售人员'].astype(int)
print("\n清洗后的数据:")
print(data.head())
return data
def plot_sales_vs_satisfaction(data):
plt.figure(figsize=(10, 6))
sns.scatterplot(x='销售额', y='客户满意度', data=data, hue='地区', s=100, palette='Set2')
plt.title('销售额与客户满意度关系', fontsize=16, fontweight='bold')
plt.xlabel('销售额 (万元)', fontsize=14)
plt.ylabel('客户满意度 (1-10)', fontsize=14)
plt.legend(title='地区')
plt.grid(True, linestyle='--', linewidth=0.5)
plt.show()
def plot_advertising_effect(data):
plt.figure(figsize=(10, 6))
sns.regplot(x='广告投入', y='销售额', data=data, scatter_kws={'s':100}, line_kws={'color':'red'})
plt.title('广告投入与销售额关系', fontsize=16, fontweight='bold')
plt.xlabel('广告投入 (万元)', fontsize=14)
plt.ylabel('销售额 (万元)', fontsize=14)
plt.grid(True, linestyle='--', linewidth=0.5)
plt.show()
def plot_sales_personnel(data):
plt.figure(figsize=(10, 6))
sns.barplot(x='地区', y='销售人员', data=data, palette='Pastel1')
plt.title('各地区销售人员数量', fontsize=16, fontweight='bold')
plt.xlabel('地区', fontsize=14)
plt.ylabel('销售人员数量', fontsize=14)
plt.grid(axis='y', linestyle='--', linewidth=0.5)
plt.show()
def plot_interactive_sales(data):
fig = px.scatter(data, x='广告投入', y='销售额',
size='销售人员', color='地区',
hover_name='地区',
title='广告投入与销售额关系 (交互式)',
labels={'广告投入': '广告投入 (万元)', '销售额': '销售额 (万元)'},
template='plotly_dark')
fig.show()
def create_sales_animation(data):
# 排序数据以确保动画连贯
data_sorted = data.sort_values('广告投入')
x = data_sorted['广告投入'].values
y = data_sorted['销售额'].values
regions = data_sorted['地区'].values
# 创建图形和子图
fig, ax = plt.subplots(figsize=(12, 6))
# 初始化散点图
scatter = ax.scatter([], [], s=[], c=[], cmap='viridis', alpha=0.6, edgecolors='w', linewidth=0.5)
# 添加标题和标签
ax.set_title('广告投入与销售额动态关系', fontsize=16, fontweight='bold')
ax.set_xlabel('广告投入 (万元)', fontsize=14)
ax.set_ylabel('销售额 (万元)', fontsize=14)
# 设置坐标轴范围
ax.set_xlim(min(x) - 10, max(x) + 10)
ax.set_ylim(min(y) - 50, max(y) + 50)
# 添加图例
unique_regions = list(set(regions))
colors = plt.cm.get_cmap('viridis', len(unique_regions))
for idx, region in enumerate(unique_regions):
ax.scatter([], [], c=[colors(idx)], label=region)
ax.legend(title='地区', fontsize=12)
# 定义初始化函数
def init():
scatter.set_offsets([])
scatter.set_sizes([])
scatter.set_array([])
return scatter,
# 定义更新函数
def update(frame):
current_x = x[:frame]
current_y = y[:frame]
current_regions = regions[:frame]
scatter.set_offsets(np.c_[current_x, current_y])
scatter.set_sizes([s * 10 for s in frame * 0.1])
scatter.set_array(pd.factorize(current_regions)[0])
return scatter,
# 创建动画
ani = FuncAnimation(fig, update, frames=len(x), init_func=init,
interval=100, blit=True, repeat=False)
# 指定 FFmpeg 的路径(根据实际情况修改)
# plt.rcParams['animation.ffmpeg_path'] = r'C:\ffmpeg\bin\ffmpeg.exe' # 可选
# 创建 FFMpegWriter 实例
writer = FFMpegWriter(fps=10, metadata=dict(artist='Me'), bitrate=1800)
# 保存动画为 MP4
ani.save('advertising_sales_animation.mp4', writer=writer)
# 显示图形
plt.show()
def main():
# 数据文件路径
filepath = 'sales_data1.csv'
# 加载并清洗数据
data = load_and_clean_data(filepath)
# 绘制销售额与客户满意度关系图
plot_sales_vs_satisfaction(data)
# 绘制广告投入与销售额关系图
plot_advertising_effect(data)
# 绘制各地区销售人员数量图
plot_sales_personnel(data)
# 创建并显示交互式散点图
plot_interactive_sales(data)
# 创建并保存销售动画
create_sales_animation(data)
if __name__ == "__main__":
main()
运行说明
准备数据
- 创建一个名为
sales_data.csv
的 CSV 文件,并填入示例数据或实际销售数据。
- 创建一个名为
安装必要的库
确保已安装 Pandas、Seaborn 和 Plotly:
pip install pandas seaborn plotly
运行脚本
在命令提示符或终端中导航到脚本所在的目录。
运行以下命令:
python project_sales_analysis.py
查看结果
- 脚本将依次生成并显示多个图表,包括静态图表、交互式图表和动画。动画将被保存为
advertising_sales_animation.mp4
文件。
- 脚本将依次生成并显示多个图表,包括静态图表、交互式图表和动画。动画将被保存为
代码说明
- 数据读取与清洗
- 使用 Pandas 读取 CSV 文件,检查并处理缺失值,确保数据类型正确。
- 绘制静态图表
- 销售额与客户满意度关系图:使用 Seaborn 的
scatterplot
绘制散点图,展示销售额与客户满意度的关系。 - 广告投入与销售额关系图:使用 Seaborn 的
regplot
绘制回归散点图,分析广告投入对销售额的影响。 - 各地区销售人员数量图:使用 Seaborn 的
barplot
绘制柱状图,比较不同地区的销售人员数量。
- 销售额与客户满意度关系图:使用 Seaborn 的
- 交互式图表
- 使用 Plotly 创建交互式散点图,允许用户通过悬停查看具体地区的信息。
- 动画展示
- 使用 Matplotlib 的
FuncAnimation
创建广告投入与销售额关系的动态散点图动画,并将其保存为 MP4 文件。
- 使用 Matplotlib 的
- 图表美化
- 为每个图表添加标题、轴标签、图例和网格线,提升图表的可读性和专业性。
- 使用不同的颜色和样式区分不同的数据系列。
注意事项
- 文件路径
- 确保脚本中的文件路径与实际文件位置一致,避免文件未找到错误。
- FFmpeg 配置
- 确保 FFmpeg 已正确安装并添加到系统
PATH
中,以便 Matplotlib 能够找到ffmpeg
编写器进行动画保存。
- 确保 FFmpeg 已正确安装并添加到系统
- 数据一致性
- 确保数据集中各列的数据类型一致,避免类型转换错误。
- 图表布局
- 使用
plt.tight_layout()
自动调整图表布局,避免子图或图例重叠。
- 使用
7.4 高级项目与挑战
在完成基本项目后,您可以挑战更高级的项目,以进一步提升数据可视化技能。以下是一些高级项目建议:
7.4.1 动态仪表盘创建
创建一个动态仪表盘,实时展示关键业务指标,如销售额、市场份额、客户满意度等。可以结合使用 Matplotlib、Seaborn 和 Plotly 的交互功能,提供实时数据更新和交互式分析。
7.4.2 地理空间数据可视化
使用地理空间数据,绘制城市分布图、热力图、地理标记等。可以结合使用 geopandas
和 folium
等库,增强地理数据的可视化效果。
7.4.3 时间序列预测与可视化
结合使用时间序列分析工具(如 statsmodels
、prophet
),对销售额、气温等数据进行预测,并将预测结果与实际数据进行可视化对比。
7.4.4 多维数据可视化
探索和展示多维数据的关系,使用散点矩阵(pairplot)、热力图(heatmap)、3D 图表等,揭示数据中的潜在模式和关联。
7.5 项目展示与分享
完成项目后,您可能希望将其展示和分享给他人。以下是一些推荐的方法:
7.5.1 使用 Jupyter Notebook 展示项目
Jupyter Notebook 是一个交互式的编程环境,适合展示数据分析和可视化项目。通过结合 Markdown 和代码单元,您可以创建结构化的项目报告,包含代码、输出和解释。
示例
# 销售数据分析与可视化报告
## 项目背景
...
## 数据读取与清洗
```python
# 代码单元
import pandas as pd
data = pd.read_csv('sales_data.csv', parse_dates=['日期'])
data.dropna(inplace=True)
data.set_index('日期', inplace=True)
data.head()
```
7.5.2 创建可视化仪表盘
使用 Dash 或 Streamlit 等库,创建一个交互式的可视化仪表盘,展示项目中的关键图表和分析结果。这样,用户可以通过浏览器实时探索数据。
示例
# demo_dash_dashboard.py
import dash
from dash import dcc, html
import plotly.express as px
import pandas as pd
# 初始化 Dash 应用
app = dash.Dash(__name__)
# 读取数据
data = pd.read_csv('sales_data.csv')
# 创建 Plotly 图表
fig = px.scatter(data, x='广告投入', y='销售额',
size='销售人员', color='地区',
hover_name='地区',
title='广告投入与销售额关系',
labels={'广告投入': '广告投入 (万元)', '销售额': '销售额 (万元)'},
template='plotly_dark')
# 定义应用布局
app.layout = html.Div(children=[
html.H1(children='销售数据可视化仪表盘', style={'textAlign': 'center'}),
dcc.Graph(
id='sales-scatter',
figure=fig
)
])
# 运行应用
if __name__ == '__main__':
app.run_server(debug=True)
运行说明
安装 Dash
使用以下命令安装 Dash:
pip install dash
运行脚本
在命令提示符或终端中导航到脚本所在的目录。
运行以下命令:
python demo_dash_dashboard.py
查看仪表盘
- 打开浏览器,访问提示的本地地址(如
http://127.0.0.1:8050/
),查看交互式仪表盘。
- 打开浏览器,访问提示的本地地址(如
注意事项
- 应用布局
- 使用 Dash 的 HTML 组件和 Graph 组件,灵活设计应用布局。
- 交互功能
- 可以添加更多的交互组件,如下拉菜单、滑块等,增强仪表盘的功能。
7.5.3 生成并分享报告
将项目报告导出为 PDF、HTML 或其他格式,通过邮件、云存储或社交媒体分享给他人。
示例:使用 Jupyter Notebook 导出 PDF
- 安装 LaTeX
- 若要从 Jupyter Notebook 导出 PDF,需要安装 LaTeX 发行版(如 MiKTeX 或 TeX Live)。
- 在 Jupyter Notebook 中导出
- 打开项目的 Jupyter Notebook 文件。
- 点击菜单栏的
File
->Download as
->PDF via LaTeX (.pdf)
。
示例:使用 nbconvert 导出 HTML
jupyter nbconvert --to html project_sales_analysis.ipynb
生成的 HTML 文件可以在浏览器中查看,并通过网络分享。