【数据分析】03 - Matplotlib
【数据分析】03 - Matplotlib
文章目录
- 【数据分析】03 - Matplotlib
- 一:基础入门
- 1:Matplotlib简介
- 1.1:什么是Matplotlib
- 1.2:Matplotlib架构
- 2:基本的绘图流程
- 3:图形基本元素
- 3.1:图形容器Figure
- 3.2:坐标轴系统 - axes
- 3.3:坐标轴 - axis
- 3.4:其他常用的基本元素
- 二:核心绘图功能
- 1:基本图表类型
- 1.1:折线图plot
- 1.2:散点图scatter
- 1.3:柱状图bar/barh
- 1.4:直方图hist
- 1.5:饼图pie
- 1.6:箱线图boxplot
- 2:多子图绘制
- 2.1:GridSpec 高级布局
- 2.2:嵌套子图
- 3:图形样式设置
- 3.1:颜色设置
- 3.2:线型设置
- 3.3:标记设置
- 3.4:透明度设置
- 3.5:图形尺寸设置
- 三:高级绘图功能
- 1:高级图标类型
- 1.1:面积图stackplot
- 1.2:等高线图contour/contourf
- 1.3:3D 绘图mplot3d
- 1.4:极坐标图polar
- 1.5:热力图imshow/pcolor
- 2:动画和交互
- 2.1:基本动画
- 2.2:交互式绘图
- 2.3:事件处理
一:基础入门
1:Matplotlib简介
1.1:什么是Matplotlib
Matplotlib 是 Python 中最著名的 2D 绘图库,它提供了一个面向对象的 API 和一系列函数,用于将数据可视化。
最初由 John D. Hunter 于 2003 年创建,现已成为 Python 科学计算生态系统中最核心的可视化工具之一。
主要特点:
- 跨平台性:可在 Windows、Linux 和 macOS 上运行
- 多种输出格式:支持 PNG、PDF、SVG、EPS 等多种格式
- 高度可定制:几乎可以控制图形的每个元素
- 丰富的图表类型:支持线图、散点图、条形图、直方图、饼图等
- 与科学计算库集成:与 NumPy、Pandas、SciPy 等无缝协作
- 交互式功能:支持缩放、平移和更新图形
1.2:Matplotlib架构
Matplotlib 采用三层架构设计,各层职责分明:
Backend 层(后端层) -> 处理与具体显示/输出设备的交互 -> 将 Artist 层生成的图形渲染到屏幕或文件中
主要后端类型如下:
- Agg:用于生成 PNG 等静态图像文件(无显示功能)
- TkAgg:基于 Tkinter 的交互式后端
- QtAgg:基于 Qt 的交互式后端
- GTK:基于 GTK 的交互式后端
- WX:基于 WXWidgets 的交互式后端
- MacOSX:macOS 原生后端
- WebAgg:基于 Web 的后端(可在浏览器中显示)
Artist 层(艺术家层)-> 处理所有高级绘图元素(如线条、文本、图像等)
面向对象接口,提供对图形元素的精细控制
FigureCanvas
:表示绘图区域Renderer
:知道如何在绘图区域上绘图Artist
:所有可见元素的基类Figure
:顶级容器,包含所有绘图元素Axes
:实际的绘图区域,包含坐标轴、标签等Axis
:坐标轴,处理刻度、标签等Line2D
、Text
、Patch
等具体图形元素
Scripting 层(脚本层)-> 提供类似 MATLAB 的简单接口,便于快速绘图
- 状态机接口,保持当前图形和坐标轴的状态
- 适合交互式使用和简单脚本
- 底层仍然使用 Artist 层
主要模块:
pyplot
模块:提供类似 MATLAB 的绘图命令pylab
模块(不推荐使用):将 pyplot 和 numpy 合并到同一命名空间
2:基本的绘图流程
- 创建图形 (plt.figure())
- 创建子图 (plt.subplot()/add_subplot())
- 绘制简单图形 (plt.plot())
- 显示图形 (plt.show())
3:图形基本元素
3.1:图形容器Figure
顶级容器,相当于画布
创建一个新的图形窗口或画布
参数 | 说明 |
---|---|
figsize | (宽度, 高度) 英寸为单位 |
dpi | 每英寸点数(分辨率) |
facecolor | 背景颜色 |
edgecolor | 边框颜色 |
fig = plt.figure(figsize=(8, 6), dpi=100, facecolor='lightgray')
-
可以包含一个或多个 Axes(子图)
-
控制图形大小、DPI、背景色等全局属性
-
常用方法:
fig = plt.figure(figsize=(8,6), dpi=100, facecolor='white') fig.suptitle('Figure Title') # 图形总标题
3.2:坐标轴系统 - axes
实际的绘图区域(子图)
-
每个 Axes 包含 x 轴和 y 轴
-
真正的绘图函数(如 plot())都是在 Axes 上调用的
-
创建方法:
ax = fig.add_subplot(111) # 1行1列第1个子图 # 或 fig, ax = plt.subplots() # 更现代的创建方式
创建子图 - plt.subplot() || fig.add_subplot || plt.subplots
方式一:plt.subplot(nrows, ncols, index)
plt.subplot(2, 2, 1) # 创建2行2列的第1个子图, 就是创建nrows * ncols个子图,然后index是显示第几个
方式二:fig.add_subplot(nrows, ncols, index)
fig = plt.figure(figsize=(8, 6), dpi=100, facecolor='lightgray')
ax = fig.add_subplot(2, 2, 3) # 在已创建的图形上添加子图
方式三:plt.subplots(nrows, nrols)
fig, ax = plt.subplots(nrows=2, ncols=2) # 一次性创建多个子图
3.3:坐标轴 - axis
创建画布 -> 创建子图(坐标轴系统) -> 在子图中绘制坐标轴
实际的坐标轴对象:
-
控制刻度、刻度标签、网格线等
-
包含 XAxis 和 YAxis 两个对象
-
常用定制方法:
ax.xaxis.set_ticks([0, 1, 2]) # 设置x轴刻度 ax.yaxis.set_tick_params(rotation=45) # 旋转y轴标签
3.4:其他常用的基本元素
标题和标签
ax.set_title('Subplot Title') # 子图标题
ax.set_xlabel('X Axis Label') # x轴标签
ax.set_ylabel('Y Axis Label') # y轴标签
图例 (Legend)
lines = ax.plot(x, y1, x, y2)
ax.legend(lines, ['Line 1', 'Line 2'], loc='upper right')
网格线 (Grid)
ax.grid(True, linestyle='--', alpha=0.5) # 显示虚线网格
刻度 (Ticks)
ax.set_xticks([0, 1, 2, 3]) # 设置x轴刻度位置
ax.set_xticklabels(['A', 'B', 'C', 'D']) # 设置刻度标签
注释 (Annotation)
ax.annotate('Important Point', xy=(2,1), xytext=(3,1.5),arrowprops=dict(facecolor='black'))
图形元素 (Shapes)
# 矩形
rect = plt.Rectangle((0.5,0.5), 0.2, 0.4, color='green')
ax.add_patch(rect)# 圆形
circle = plt.Circle((0.5,0.5), 0.1, color='red')
ax.add_patch(circle)
图形保存
plt.savefig('output.png', dpi=300, bbox_inches='tight')
二:核心绘图功能
1:基本图表类型
图表类型 | 适用场景 | 不适用场景 |
---|---|---|
折线图 | 趋势分析、时间序列 | 非连续数据 |
散点图 | 相关性分析、分布观察 | 大数据集(需采样) |
柱状图 | 类别比较、离散数据 | 连续数据分布 |
直方图 | 数据分布、概率密度 | 类别数据 |
饼图 | 比例展示、组成分析 | 多类别(>6)、精确比较 |
箱线图 | 统计分布、异常值检测 | 展示具体数据点 |
1.1:折线图plot
显示数据随时间或有序类别的变化趋势
plt.plot(x, y, fmt, **kwargs)
plt.plot()是matplotlib中最基础且最常用的函数之一,用于绘制二维图形
x, y参数
必须参数,数据点的 x 坐标和 y 坐标
- 可以是列表、元组或 numpy 数组
- 如果只提供 y 值,x 值会自动生成为 [0, 1, 2, …, len(y)-1]
fmt
格式字符串由颜色、标记和线型三部分组成,格式为:[marker][line][color]
,顺序任意。
颜色 (color):
'b'
: 蓝色'g'
: 绿色'r'
: 红色'c'
: 青色'm'
: 洋红'y'
: 黄色'k'
: 黑色'w'
: 白色
标记 (marker):
'.'
: 点','
: 像素'o'
: 圆圈'v'
: 下三角'^'
: 上三角'<'
: 左三角'>'
: 右三角's'
: 正方形'p'
: 五边形'*'
: 星形'h'
: 六边形1'H'
: 六边形2'+'
: 加号'x'
: x符号'D'
: 菱形'd'
: 小菱形'|'
: 垂直线'_'
: 水平线
线型 (linestyle):
'-'
: 实线'--'
: 虚线'-.'
: 点划线':'
: 点线'None'
或' '
: 无线
常用关键字参数
color
或c
: 线条颜色 (可以接受十六进制颜色码如'#FF0000'
)linestyle
或ls
: 线型linewidth
或lw
: 线宽 (浮点数)marker
: 标记样式markersize
或ms
: 标记大小markerfacecolor
或mfc
: 标记填充色markeredgecolor
或mec
: 标记边缘色markeredgewidth
或mew
: 标记边缘宽度label
: 图例标签alpha
: 透明度 (0-1)zorder
: 绘图顺序 (数值大的显示在上层)
import matplotlib.pyplot as plt
import numpy as npx = np.linspace(0, 10, 100)
y = np.sin(x)plt.plot(x, y) # 最简单的折线图
plt.show()plt.plot(x, y, 'ro--') # 红色圆圈标记,虚线
plt.plot(x, y, 'g^:', linewidth=2, markersize=8) # 绿色上三角标记,点线plt.plot(x, y, color='blue', linestyle='-', linewidth=2, marker='o', markersize=6, markerfacecolor='red', label='sin(x)')y2 = np.cos(x)
plt.plot(x, y, 'b-', label='sin(x)')
plt.plot(x, y2, 'r--', label='cos(x)')
plt.legend()# 设置数据点之间的插值方式
plt.plot(x, y, drawstyle='steps-post') # 阶梯图# 使用不同的缩放
plt.plot(x, y, '-', x, y*2, '--') # 同时绘制两条线line, = plt.plot(x, y, 'b-')
line.set_linestyle(':') # 之后将线改为点线
line.set_color('r') # 改为红色
1.2:散点图scatter
展示两个变量之间的关系,发现数据分布、聚类或异常值
plt.scatter(x, y, s=None, c=None, marker=None, **kwargs)
x
,y
: 数据点坐标s
: 点的大小(标量或与x,y同长度的数组)c
: 点颜色(颜色字符串或颜色序列)marker
: 点形状,如'o'
,'s'
,'^'
等
import matplotlib.pyplot as plt
import numpy as npplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False# 随机生成数据 - 50个点
x = np.random.rand(50)
y = np.random.rand(50)
# 随机生成颜色和尺寸
colors = np.random.rand(50)
sizes = 1000 * np.random.rand(50)# alpha参数控制透明度
plt.scatter(x, y, c=colors, s=sizes, alpha=0.5)
plt.colorbar() # 显示颜色条
plt.title('散点图示例')
plt.show()
1.3:柱状图bar/barh
特征 | 垂直柱状图 | 水平柱状图 | 直方图 |
---|---|---|---|
坐标方向 | 垂直 | 水平 | 垂直 |
适用场景 | 类别比较 | 长标签/排名 | 数据分布 |
X轴 | 类别标签 | 数值 | 数值区间 |
Y轴 | 数值 | 类别标签 | 频数/频率 |
垂直柱状图最适合比较少量类别间的数值差异,当类别标签较长或类别较多时,建议改用水平柱状图
垂直柱状图 - bar
比较不同类别的离散数据
# x -> 柱子的x坐标(类别位置)-> 可以是标量序列(如列表、数组)或类别标签
# height -> 柱子的高度(数值)
# width -> 柱子宽度(默认0.8), 范围在0-1之间,大于1会导致柱子重叠
# bottom -> 柱子底部基准(用于堆叠柱状图)
# align -> 柱子对齐方式 -> 'center':以x坐标为中心(默认)-> 'edge':以x坐标为左边缘
# color/facecolor:柱子填充色 -> 可接受颜色名称、十六进制或RGB值
# edgecolor:边框颜色
# linewidth/lw:边框宽度
# alpha:透明度(0-1)
# label:图例标签
plt.bar(x, height, width=0.8, bottom=None, **kwargs)# ============== 示例 ======================
import matplotlib.pyplot as plt
import numpy as np# 定义横纵坐标的内容
categories = ['Apple', 'Banana', 'Orange', 'Grape']
values = [23, 45, 56, 12]# 柱子的颜色是skyblue, 边框颜色是black
plt.bar(categories, values, color='skyblue', edgecolor='black')
# 标题,x标签,y标签
plt.title('Fruit Sales')
plt.xlabel('Fruit Type')
plt.ylabel('Sales Quantity')
# grid样式
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.show()
如果是多组柱状图
import matplotlib.pyplot as plt
import numpy as npplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falsecategories = ['Apple', 'Banana', 'Orange', 'Grape']
values = [23, 45, 56, 12]n = len(categories)
width = 0.35 # 柱子宽度# 第一组数据
plt.bar(np.arange(n) - width/2, values, width, label='2022')
# 第二组数据
plt.bar(np.arange(n) + width/2, [x*1.2 for x in values], width, label='2023')plt.xticks(np.arange(n), categories) # 设置x轴标签
plt.legend()
plt.show()
如果是堆叠柱状图
import matplotlib.pyplot as plt
import numpy as npplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falsecategories = ['Apple', 'Banana', 'Orange', 'Grape']
values = [23, 45, 56, 12]bottom_values = [20, 30, 40, 10]
top_values = [15, 20, 25, 8]plt.bar(categories, bottom_values, label='Base')
plt.bar(categories, top_values, bottom=bottom_values, label='Bonus')
plt.legend()
plt.show()
水平柱状图 (barh)
# y:柱子的y坐标(类别位置) -> 可以是标量序列或类别标签
# width:柱子的宽度(数值)
# height:柱子高度(默认0.8)-> 相当于垂直柱状图中的width参数
# left:柱子左边缘基准(用于堆叠柱状图)
# align:柱子对齐方式 -> 'center':以y坐标为中心(默认) -> 'edge':以y坐标为下边缘
# color/facecolor:柱子填充色 -> 可接受颜色名称、十六进制或RGB值
# edgecolor:边框颜色
# linewidth/lw:边框宽度
# alpha:透明度(0-1)
# label:图例标签
plt.barh(y, width, height=0.8, left=None, *, align='center', **kwargs)# ========== 举一个例子 =================
import matplotlib.pyplot as plt
import numpy as npplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falseimport matplotlib.pyplot as plt# 定义y -> 类别
categories = ['金融服务', '医疗健康', '教育培训', '电子商务']
# 定义x -> 数值
values = [120, 85, 65, 110]plt.barh(categories, values, color='lightgreen', edgecolor='darkgreen')
plt.title('行业投资金额(百万美元)')
plt.xlabel('投资金额')
plt.ylabel('行业类别')
plt.grid(axis='x', linestyle='--', alpha=0.6)
plt.tight_layout()
plt.show()
同理,多组的水平柱状图如下
import matplotlib.pyplot as plt
import numpy as npplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falsecategories = ['金融服务', '医疗健康', '教育培训', '电子商务']
values = [120, 85, 65, 110]n = len(categories)
height = 0.35 # 柱子高度# 第一组数据(左侧)
plt.barh(np.arange(n) - height/2, values, height, label='2022')
# 第二组数据(右侧)
plt.barh(np.arange(n) + height/2, [x*1.3 for x in values], height, label='2023')plt.yticks(np.arange(n), categories)
plt.legend()
plt.tight_layout()
plt.show()
1.4:直方图hist
基础直方图
import matplotlib.pyplot as plt
import numpy as npplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False# 生成随机数据 - 1000个数据
data = np.random.normal(0, 1, 1000) # 均值为0,标准差为1的正态分布# 绘制基础直方图
# 创建一个figure对象,并设置大小为8 x 6
plt.figure(figsize=(8, 6))
# 创建直方图,bins表示直方图的柱数,color表示柱的颜色,edgecolor表示柱的边框颜色
plt.hist(data, bins=30, color='steelblue', edgecolor='white')# 添加标题和标签
plt.title('基础直方图示例', fontsize=14)
plt.xlabel('数值范围', fontsize=12)
plt.ylabel('频数', fontsize=12)# 添加网格线
plt.grid(axis='y', alpha=0.3)plt.show()
可以自定义一些直方图的参数
import matplotlib.pyplot as plt
import numpy as npplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False# 生成随机数据 - 1000个数据
data = np.random.normal(0, 1, 1000) # 均值为0,标准差为1的正态分布plt.figure(figsize=(8, 6))# 更多自定义参数
plt.hist(data,bins=50, # 柱子数量range=(-3, 3), # 数值范围density=True, # 显示密度而非频数color='#FF6B6B', # 柱子颜色edgecolor='#4D96FF', # 边缘颜色linewidth=1.2, # 边缘线宽alpha=0.7, # 透明度histtype='stepfilled', # 直方图类型label='正态分布') # 图例标签plt.title('自定义参数直方图', fontsize=14)
plt.xlabel('数值', fontsize=12)
plt.ylabel('概率密度', fontsize=12)
plt.legend(fontsize=10)
plt.grid(axis='y', linestyle='--', alpha=0.5)plt.show()
可以多组直方图进行比较
import matplotlib.pyplot as plt
import numpy as npplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False# 生成多组数据
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(2, 1.5, 800)
data3 = np.random.normal(-2, 0.8, 1200)plt.figure(figsize=(10, 6))# 绘制多组直方图
plt.hist(data1, bins=30, alpha=0.5, label='组1: μ=0, σ=1')
plt.hist(data2, bins=30, alpha=0.5, label='组2: μ=2, σ=1.5')
plt.hist(data3, bins=30, alpha=0.5, label='组3: μ=-2, σ=0.8')plt.title('多组数据直方图比较', fontsize=14)
plt.xlabel('数值', fontsize=12)
plt.ylabel('频数', fontsize=12)
plt.legend(fontsize=10)
plt.grid(axis='y', alpha=0.3)plt.show()
还可以直方图配合密度曲线
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
import seaborn as snsplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falseplt.figure(figsize=(10, 6))data = np.random.normal(loc=0, scale=1, size=1000)# 绘制直方图
plt.hist(data, bins=30, density=True,color='lightgreen',edgecolor='black',alpha=0.7,label='直方图')# 添加核密度估计曲线
sns.kdeplot(data, color='red', linewidth=2, label='密度曲线')# 添加理论正态分布曲线
xmin, xmax = plt.xlim()
x = np.linspace(xmin, xmax, 100)
p = norm.pdf(x, np.mean(data), np.std(data))
plt.plot(x, p, 'k--', linewidth=1.5, label='理论正态分布')plt.title('直方图与密度曲线', fontsize=14)
plt.xlabel('数值', fontsize=12)
plt.ylabel('密度', fontsize=12)
plt.legend(fontsize=10)plt.show()
1.5:饼图pie
基础饼图
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
import seaborn as snsplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False# 数据准备
labels = ['A', 'B', 'C', 'D']
sizes = [15, 30, 45, 10] # 各部分大小
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99'] # 颜色# 绘制饼图
plt.figure(figsize=(8, 6))
plt.pie(sizes,labels=labels,colors=colors,autopct='%1.1f%%', # 显示百分比格式startangle=90) # 起始角度# 添加标题
plt.title('基础饼图示例', fontsize=14)# 显示为圆形(防止压缩变形)
plt.axis('equal')
plt.show()
可以通过属性,添加突出和阴影效果
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
import seaborn as snsplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False# 数据准备
labels = ['A', 'B', 'C', 'D']
sizes = [15, 30, 45, 10] # 各部分大小
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99'] # 颜色# 突出显示某一块(这里突出第2块)
explode = (0, 0.1, 0, 0)plt.figure(figsize=(8, 6))
plt.pie(sizes,explode=explode, # 突出显示labels=labels,colors=colors,autopct='%1.1f%%',shadow=True, # 阴影效果startangle=90)plt.title('带阴影和突出显示的饼图', fontsize=14)
plt.axis('equal')
plt.show()
如果是环形图,其实就是在饼图的基础上上面在画一个圆
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
import seaborn as snsplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False# 数据准备
labels = ['A', 'B', 'C', 'D']
sizes = [15, 30, 45, 10] # 各部分大小
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99'] # 颜色# 突出显示某一块(这里突出第2块)
explode = (0, 0.1, 0, 0)plt.figure(figsize=(8, 6))# 先画饼图
pie = plt.pie(sizes,labels=labels,colors=colors,autopct='%1.1f%%',startangle=90)# 添加一个白色圆形在中心
centre_circle = plt.Circle((0, 0), 0.7, color='white')
fig = plt.gcf()
fig.gca().add_artist(centre_circle)plt.title('环形图(甜甜圈图)示例', fontsize=14)
plt.axis('equal')
plt.show()
1.6:箱线图boxplot
箱线图(又称盒须图)是展示数据分布特征的重要工具,可以直观显示数据的中位数、四分位数、异常值等统计信息
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
import seaborn as snsplt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False# 生成随机数据
np.random.seed(42)
data = np.random.normal(loc=0, scale=1, size=100)# 绘制基础箱线图
plt.figure(figsize=(8, 6))
plt.boxplot(data, patch_artist=True) # patch_artist=True允许填充颜色# 添加标题和标签
plt.title('基础箱线图', fontsize=14)
plt.ylabel('数值', fontsize=12)
plt.xticks([1], ['数据集']) # 设置x轴标签plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.show()
当然还可以自定义样式
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
import seaborn as sns# 设置中文字体,确保图表中的中文能够正常显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统使用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False# 创建一个新的图像,指定大小
plt.figure(figsize=(10, 6))# 生成三组正态分布的随机数据,用于绘制箱线图
np.random.seed(42)
data1 = np.random.normal(0, 1, 100)
data2 = np.random.normal(2, 1.5, 100)
data3 = np.random.normal(-1, 0.8, 100)
all_data = [data1, data2, data3]# 定义箱线图中箱子的颜色
colors = ['#FF9F43', '#48CFAD', '#4FC1E9']# 绘制自定义样式的箱线图
box = plt.boxplot(all_data,patch_artist=True, # 允许自定义填充颜色labels=['组1', '组2', '组3'], # 设置每个数据组的标签widths=0.6, # 箱体宽度showmeans=True, # 显示均值meanline=True, # 均值显示为线showfliers=True, # 显示异常值flierprops=dict( # 异常点样式marker='o',markerfacecolor='red',markersize=8,markeredgecolor='none'),medianprops=dict( # 中位数线样式color='white',linewidth=2),meanprops=dict( # 均值线样式color='yellow',linewidth=2),whiskerprops=dict( # 须线样式color='gray',linewidth=1.5),capprops=dict( # 箱体顶端线样式color='gray',linewidth=1.5))# 为每个箱子设置颜色和透明度
for patch, color in zip(box['boxes'], colors):patch.set_facecolor(color)patch.set_alpha(0.8) # 设置透明度# 添加图表标题和y轴标签
plt.title('自定义样式的箱线图', fontsize=14)
plt.ylabel('数值分布', fontsize=12)# 添加网格,便于观察数据分布
plt.grid(axis='y', linestyle='--', alpha=0.5)# 显示图表
plt.show()
2:多子图绘制
前面已经介绍过了 subplot 函数和 subplots 函数,下面看看还有那些绘制子图的知识点
2.1:GridSpec 高级布局
GridSpec是Matplotlib中用于创建复杂子图布局的强大工具,它比简单的subplot()
或subplots()
函数提供了更精细的控制。
GridSpec不是直接创建子图的函数,而是一个指定网格布局的类,然后你可以在这个网格的特定位置创建子图。
- 创建GridSpec对象,指定网格的行数和列数
- 使用
subplot()
函数并传入GridSpec的切片来创建子图
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpecfig = plt.figure(figsize=(10, 6))# 创建2行3列的网格
gs = GridSpec(2, 3, figure=fig)# 在网格的不同位置创建子图
ax1 = fig.add_subplot(gs[0, 0]) # 第一行第一列
ax2 = fig.add_subplot(gs[0, 1:]) # 第一行第二和第三列
ax3 = fig.add_subplot(gs[1, :2]) # 第二行第一和第二列
ax4 = fig.add_subplot(gs[1, 2]) # 第二行第三列# 添加一些示例内容
ax1.plot([1, 2, 3], [1, 2, 3])
ax2.bar(['A', 'B', 'C'], [3, 7, 2])
ax3.scatter([1, 2, 3], [3, 2, 1])
ax4.pie([15, 30, 45, 10], labels=['A', 'B', 'C', 'D'])plt.tight_layout()
plt.show()
高级设置 - 调整子图间距
gs = GridSpec(2, 2, figure=fig, width_ratios=[1, 2], # 列宽度比例height_ratios=[2, 1], # 行高度比例wspace=0.4, # 列间距hspace=0.3) # 行间距
高级设置 - 跨越多行/列的子图
gs = GridSpec(3, 3, figure=fig)# 创建跨越多行/列的子图
ax1 = fig.add_subplot(gs[:2, :]) # 占据前两行所有列
ax2 = fig.add_subplot(gs[2, :2]) # 占据第三行前两列
ax3 = fig.add_subplot(gs[2, 2]) # 占据第三行第三列
再举一个复杂的例子
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy as npdef grid_spec_test():# 创建一个Figure对象, 并设置大小为10x8fig = plt.figure(figsize=(10, 8))# 创建一个GridSpec对象, 宽高比为1:1, 4 * 4gs = GridSpec(4, 4, figure=fig)# 主图占据前3行和前3列ax_main = fig.add_subplot(gs[:3, :3])# 右侧颜色条占据前3行第4列ax_color = fig.add_subplot(gs[:3, 3])# 底部直方图占据第4行前3列ax_hist = fig.add_subplot(gs[3, :3])# 生成一些数据x = np.random.randn(1000)y = np.random.randn(1000)# 在主图中绘制散点图sc = ax_main.scatter(x, y, c=np.sqrt(x ** 2 + y ** 2), alpha=0.6)# 添加颜色条plt.colorbar(sc, cax=ax_color)# 在底部绘制直方图ax_hist.hist(x, bins=30, alpha=0.7)plt.tight_layout()plt.show()if __name__ == '__main__':grid_spec_test()
2.2:嵌套子图
嵌套子图是Matplotlib中创建复杂布局的高级技术,它允许你在一个主图中嵌入多个子图,或者在一个子图中再创建子图
基本创建方式
# 使用`add_axes()`手动定位
import matplotlib.pyplot as pltfig = plt.figure(figsize=(10, 8))# 主图
main_ax = fig.add_subplot(111)
main_ax.plot([1, 2, 3], [1, 2, 3], 'r-')# 在(0.2, 0.6)位置创建嵌套子图,宽度和高度为0.2
inset_ax = fig.add_axes([0.2, 0.6, 0.2, 0.2]) # [left, bottom, width, height]
inset_ax.plot([1, 2, 3], [3, 2, 1], 'b--')
inset_ax.set_title('嵌套子图')plt.show()# 使用inset_axes()方法
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axesfig, ax = plt.subplots(figsize=(8, 6))
ax.plot([1, 2, 3], [1, 2, 3])# 在主图中创建嵌套子图
inset_ax = inset_axes(ax, width="30%", # 宽度为主图的30%height="20%", # 高度为主图的20%loc='upper right') # 位置在右上角inset_ax.plot([1, 2, 3], [3, 2, 1], 'g-')
inset_ax.set_title('使用inset_axes创建')
高级嵌套技术
# 多级嵌套子图
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(12, 8))# 一级主图
main_ax = fig.add_subplot(111)
main_ax.plot([0, 1, 2], [0, 1, 0], 'k-')# 二级嵌套子图
inset1 = fig.add_axes([0.2, 0.6, 0.3, 0.3])
inset1.plot([1, 2, 3], [1, 3, 1], 'b-')# 三级嵌套子图(在二级子图中再嵌套)
inset2 = inset1.inset_axes([0.5, 0.5, 0.4, 0.4])
inset2.plot([1, 2], [2, 1], 'r--')
inset2.set_title('三级嵌套')plt.show()# 使用GridSpec实现嵌套布局
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpecfig = plt.figure(figsize=(10, 8))# 外层GridSpec:1行2列
outer_gs = GridSpec(1, 2, figure=fig, width_ratios=[3, 1])# 内层GridSpec:2行1列(用于左侧主区域)
inner_gs = GridSpec(2, 1, figure=fig, left=0.05, right=0.65, # 定位hspace=0.3) # 行间距# 创建子图
main_ax1 = fig.add_subplot(inner_gs[0])
main_ax2 = fig.add_subplot(inner_gs[1])
side_ax = fig.add_subplot(outer_gs[1])# 填充内容
main_ax1.plot([1, 2, 3], [1, 2, 1])
main_ax2.scatter([1, 2, 3], [3, 1, 2])
side_ax.bar(['A', 'B', 'C'], [2, 3, 1])plt.show()
实用嵌套模式
# 放大局部区域
import matplotlib.pyplot as plt
import numpy as npfig, ax = plt.subplots(figsize=(8, 6))x = np.linspace(0, 10, 1000)
y = np.sin(x) * np.exp(-x/10)
ax.plot(x, y)# 创建放大区域
inset_ax = inset_axes(ax, width="40%", height="30%", loc='upper right')
inset_ax.plot(x, y)
inset_ax.set_xlim(4, 6) # 放大x=4到6的区域
inset_ax.set_ylim(0.2, 0.5)# 添加连接线
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
mark_inset(ax, inset_ax, loc1=2, loc2=4, fc="none", ec="0.5")plt.show()# 仪表板式嵌套布局
fig = plt.figure(figsize=(12, 10))# 定义布局:主图+3个小图
main_ax = fig.add_axes([0.1, 0.3, 0.6, 0.6]) # 主图
small1 = fig.add_axes([0.75, 0.7, 0.2, 0.2]) # 右上小图
small2 = fig.add_axes([0.75, 0.4, 0.2, 0.2]) # 右中小图
small3 = fig.add_axes([0.1, 0.1, 0.6, 0.15]) # 底部长图# 填充内容
x = np.linspace(0, 2*np.pi, 100)
main_ax.plot(x, np.sin(x), label='sin(x)')
main_ax.plot(x, np.cos(x), label='cos(x)')
main_ax.legend()small1.pie([15, 30, 45, 10], labels=['A', 'B', 'C', 'D'])
small2.barh(['X', 'Y', 'Z'], [3, 7, 2])
small3.hist(np.random.randn(1000), bins=30)plt.show()
嵌套子图的样式控制
# 边框和背景控制
fig, ax = plt.subplots()# 创建嵌套子图并设置样式
inset_ax = inset_axes(ax, width="30%", height="30%", loc='lower left',borderpad=2, # 边框间距bbox_to_anchor=(0.4, 0.4), # 锚点位置bbox_transform=ax.transAxes) # 使用轴坐标inset_ax.plot([1, 2, 3], [3, 1, 2])
inset_ax.set_facecolor('lightgray') # 背景色
inset_ax.spines['top'].set_linestyle('--') # 上边框虚线
inset_ax.spines['right'].set_visible(False) # 隐藏右边框plt.show()# 共享坐标轴
fig, axs = plt.subplots(2, 1, figsize=(8, 6))# 在第一个子图中创建嵌套子图
inset_ax = axs[0].inset_axes([0.6, 0.6, 0.3, 0.3])# 共享x轴
shared_inset = axs[1].inset_axes([0.1, 0.6, 0.3, 0.3], sharex=axs[1])# 填充内容
axs[0].plot([1, 2, 3], [1, 2, 1])
inset_ax.plot([1.5, 2.5], [1.5, 1.5], 'r-')axs[1].plot(np.arange(10), np.random.rand(10))
shared_inset.plot(np.arange(3, 7), np.random.rand(4), 'g--')plt.show()
3:图形样式设置
3.1:颜色设置
Matplotlib 提供了多种方式来指定颜色:
import matplotlib.pyplot as plt
import numpy as np# 1. 使用预定义的颜色名称
plt.plot([1, 2, 3], color='red')# 2. 使用十六进制颜色代码
plt.plot([1, 2, 3], color='#FF5733')# 3. RGB或RGBA元组 (值在0-1之间)
plt.plot([1, 2, 3], color=(0.1, 0.2, 0.5, 0.8)) # RGBA# 4. 使用灰度字符串 (0-1之间的字符串)
plt.plot([1, 2, 3], color='0.75') # 75%灰度# 5. 使用CN颜色循环中的颜色
plt.plot([1, 2, 3], color='C1') # 使用颜色循环中的第二个颜色
Matplotlib 支持所有标准的HTML/CSS颜色名称,如:
- 基本颜色:
'red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'black', 'white'
- 灰色调:
'gray', 'lightgray', 'darkgray'
- 其他:
'orange', 'purple', 'pink', 'brown'
同时还可以进行颜色映射:
x = np.linspace(0, 10, 100)
y = np.sin(x)
colors = np.linspace(0, 1, len(x))# 使用colormap
plt.scatter(x, y, c=colors, cmap='viridis')
plt.colorbar() # 显示颜色条
常用colormap:
- 顺序型:
'viridis', 'plasma', 'inferno', 'magma', 'cividis'
- 发散型:
'coolwarm', 'bwr', 'seismic'
- 循环型:
'twilight', 'hsv'
3.2:线型设置
基本线型如下:
# 实线 (默认)
plt.plot([1, 2, 3], linestyle='-') # 或 '-'# 虚线
plt.plot([1, 2, 3], linestyle='--') # 或 '--'# 点划线
plt.plot([1, 2, 3], linestyle='-.') # 或 '-.'# 点线
plt.plot([1, 2, 3], linestyle=':') # 或 ':'# 无线条 (只显示标记)
plt.plot([1, 2, 3], linestyle='None') # 或 'None' 或 ''
还可以自定义线型
# 使用元组定义线型 (线段长度, 空白长度, ...)
plt.plot([1, 2, 3], linestyle=(0, (1, 1))) # 点线
plt.plot([1, 2, 3], linestyle=(0, (5, 5, 1, 5))) # 自定义点划线
3.3:标记设置
基本标记设置:
# 圆形
plt.plot([1, 2, 3], marker='o') # 或 'o'# 方形
plt.plot([1, 2, 3], marker='s') # 或 's'# 三角形
plt.plot([1, 2, 3], marker='^') # 向上三角形# 其他常见标记
# '+' 加号, 'x' 叉号, '*' 星号, 'D' 钻石形, 'd' 小钻石形, 'p' 五边形
标记大小颜色和样式填充
plt.plot([1, 2, 3], marker='o', markersize=10, # 或 ms=10markerfacecolor='red', # 标记填充色markeredgecolor='blue', # 标记边缘色markeredgewidth=2) # 标记边缘宽度plt.plot([1, 2, 3], marker='o', markerfacecolor='none', # 无填充markeredgecolor='blue')
3.4:透明度设置
# global
plt.plot([1, 2, 3], alpha=0.5) # 50%透明度# 不同元素的透明度
# 填充区域的透明度
plt.fill_between([1, 2, 3], [1, 2, 1], alpha=0.3)# 散点图的透明度
plt.scatter(np.random.rand(50), np.random.rand(50), alpha=0.6)# 条形图的透明度
plt.bar([1, 2, 3], [3, 2, 1], alpha=0.7)
还可以设置图片的透明度
img = np.random.rand(10, 10)
plt.imshow(img, alpha=0.8)
3.5:图形尺寸设置
创建图形时设置尺寸
# 设置图形尺寸 (宽度, 高度) 单位英寸
plt.figure(figsize=(8, 6)) # 8英寸宽,6英寸高
DPI设置
# 设置DPI (每英寸点数)
plt.figure(figsize=(8, 6), dpi=100)
调整现有图形尺寸
fig = plt.gcf()
fig.set_size_inches(10, 5) # 调整现有图形尺寸
保存图形时的尺寸和DPI
plt.savefig('output.png', dpi=300, bbox_inches='tight')
子图间距调整
plt.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9,wspace=0.4, hspace=0.4)
约束布局
# 自动调整布局
plt.figure(constrained_layout=True)
三:高级绘图功能
1:高级图标类型
1.1:面积图stackplot
面积图(stackplot)是一种用于展示多个数据序列累积效果的可视化图表,特别适合显示各部分随时间变化的累积关系。Matplotlib 中的 stackplot()
函数可以方便地创建这种图表。
基本用法
最简单的堆叠面积图
import matplotlib.pyplot as plt
import numpy as np# 创建数据
x = np.arange(1, 6) # x轴数据
y1 = np.array([1, 2, 3, 4, 5]) # 第一组数据
y2 = np.array([2, 3, 4, 5, 6]) # 第二组数据
y3 = np.array([3, 4, 5, 6, 7]) # 第三组数据# 绘制堆叠面积图
plt.stackplot(x, y1, y2, y3)
plt.title('基本堆叠面积图')
plt.show()
参数详解
主要参数
x
:x轴数据(1D数组)y
:y轴数据(多个1D数组或2D数组)labels
:各系列的标签(用于图例)colors
:各系列的颜色baseline
:基线计算方法(‘zero’(默认), ‘sym’, ‘wiggle’, ‘weighted_wiggle’)
完整参数示例
plt.stackplot(x, y1, y2, y3,labels=['系列A', '系列B', '系列C'],colors=['#FF5733', '#33FF57', '#3357FF'],alpha=0.8, # 透明度baseline='zero') # 基线方法
plt.legend(loc='upper left')
plt.title('带标签和自定义颜色的堆叠面积图')
plt.show()
高级用法
使用DataFrame数据
import pandas as pd# 创建DataFrame
data = {'年份': [2018, 2019, 2020, 2021, 2022],'产品A': [200, 220, 250, 270, 300],'产品B': [150, 160, 170, 190, 210],'产品C': [100, 120, 140, 160, 180]
}
df = pd.DataFrame(data)# 绘制堆叠面积图
plt.stackplot(df['年份'], df['产品A'], df['产品B'], df['产品C'],labels=['产品A', '产品B', '产品C'],colors=['#FF9999', '#66B2FF', '#99FF99'])
plt.legend(loc='upper left')
plt.title('使用DataFrame绘制的堆叠面积图')
plt.xlabel('年份')
plt.ylabel('销售额')
plt.show()
自定义基线方法
# 创建数据
x = np.linspace(0, 2*np.pi, 100)
y1 = np.sin(x)
y2 = np.cos(x)# 四种不同的基线方法
baselines = ['zero', 'sym', 'wiggle', 'weighted_wiggle']fig, axs = plt.subplots(2, 2, figsize=(12, 8))
axs = axs.flatten()for ax, baseline in zip(axs, baselines):ax.stackplot(x, y1, y2, baseline=baseline)ax.set_title(f"基线方法: '{baseline}'")ax.set_xlim(0, 2*np.pi)plt.tight_layout()
plt.show()
边缘线样式设置
# 创建数据
days = np.arange(1, 8)
sleep = [7, 6, 8, 7, 9, 8, 10]
work = [8, 9, 7, 8, 6, 9, 5]
leisure = [9, 9, 9, 9, 9, 7, 9]# 绘制堆叠面积图并设置边缘线
plt.stackplot(days, sleep, work, leisure,labels=['睡眠', '工作', '休闲'],colors=['#8ECFC9', '#FFBE7A', '#FA7F6F'],edgecolor='black', # 边缘颜色linewidth=0.5) # 边缘线宽plt.legend(loc='upper left')
plt.title('每日活动时间分配')
plt.xlabel('星期')
plt.ylabel('小时')
plt.xticks(days, ['周一', '周二', '周三', '周四', '周五', '周六', '周日'])
plt.show()
部分堆叠面积图
# 创建数据
months = np.arange(1, 13)
sales_A = np.random.randint(20, 50, size=12)
sales_B = np.random.randint(10, 30, size=12)
sales_C = np.random.randint(5, 20, size=12)# 只堆叠B和C,A单独显示
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))# 上方:全部堆叠
ax1.stackplot(months, sales_A, sales_B, sales_C,labels=['产品A', '产品B', '产品C'])
ax1.set_title('完全堆叠面积图')
ax1.legend(loc='upper left')# 下方:部分堆叠
ax2.plot(months, sales_A, label='产品A', color='#FF5733')
ax2.stackplot(months, sales_B, sales_C,labels=['产品B', '产品C'],colors=['#33FF57', '#3357FF'])
ax2.set_title('部分堆叠面积图')
ax2.legend(loc='upper left')plt.tight_layout()
plt.show()
实用技巧
添加数值标签
# 创建数据
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
revenue = [40, 60, 80, 70]
cost = [20, 30, 40, 35]
profit = [20, 30, 40, 35]# 计算累积高度用于标签位置
cum_height = np.vstack((np.zeros(len(quarters)), np.array(revenue), np.array(revenue)+np.array(cost))).T# 绘制堆叠面积图
plt.stackplot(quarters, revenue, cost, profit,labels=['收入', '成本', '利润'],colors=['#4CAF50', '#F44336', '#2196F3'])# 添加数值标签
for i, q in enumerate(quarters):plt.text(i, cum_height[i][1]/2, f'{revenue[i]}', ha='center', va='center')plt.text(i, cum_height[i][1]+cost[i]/2, f'{cost[i]}', ha='center', va='center')plt.text(i, cum_height[i][2]+profit[i]/2, f'{profit[i]}', ha='center', va='center')plt.legend(loc='upper left')
plt.title('季度财务数据堆叠面积图')
plt.ylabel('金额(万元)')
plt.show()
平滑曲线堆叠面积图
from scipy.interpolate import make_interp_spline# 原始数据
x = np.array([1, 2, 3, 4, 5])
y1 = np.array([2, 3, 5, 7, 6])
y2 = np.array([3, 4, 6, 4, 7])# 创建平滑曲线
x_smooth = np.linspace(x.min(), x.max(), 300)
spl1 = make_interp_spline(x, y1, k=3)
spl2 = make_interp_spline(x, y2, k=3)
y1_smooth = spl1(x_smooth)
y2_smooth = spl2(x_smooth)# 绘制平滑的堆叠面积图
plt.stackplot(x_smooth, y1_smooth, y2_smooth,labels=['系列A', '系列B'],colors=['#FF9AA2', '#FFB7B2'],alpha=0.8)# 添加原始数据点
plt.scatter(x, y1, color='#FF5D73', zorder=3)
plt.scatter(x, y2+y1, color='#D81159', zorder=3)plt.legend(loc='upper left')
plt.title('平滑曲线堆叠面积图')
plt.show()
时间序列堆叠面积图
import pandas as pd# 创建时间序列数据
date_rng = pd.date_range(start='2023-01-01', end='2023-12-31', freq='M')
categories = ['电子产品', '家居用品', '服装']
data = np.random.randint(10, 50, size=(len(date_rng), len(categories)))
df = pd.DataFrame(data, index=date_rng, columns=categories)# 绘制时间序列堆叠面积图
plt.stackplot(df.index, df['电子产品'], df['家居用品'], df['服装'],labels=categories,colors=['#7BC8F6', '#FF7373', '#FFA500'])plt.legend(loc='upper left')
plt.title('2023年各月销售额分布')
plt.ylabel('销售额(万元)')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
1.2:等高线图contour/contourf
等高线图是用于可视化三维数据的二维表示方法,通过等高线展示数据的分布特征。Matplotlib提供contour和contourf两种函数来绘制等高线图,前者绘制线条,后者填充颜色区域。
基本等高线图(contour)
contour函数的基本使用需要三个二维数组:X,Y坐标网格和Z值数据。创建方法如下:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy as np# plt.rcParams['font.sans-serif'] = ['PingFang'] # Windows系统使用黑体
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falsedef grid_spec_test():# 生成地形数据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)) # 圆形波浪地形# 绘制地形plt.figure(figsize=(10, 6))# 通过contourf绘制等值线图cf = plt.contourf(X, Y, Z, levels=20, cmap='terrain')c = plt.contour(X, Y, Z, levels=20, colors='black', linewidths=0.5)plt.clabel(c, inline=True, fontsize=8)plt.colorbar(cf, label='高度')plt.title('地形高度图')plt.xlabel('经度')plt.ylabel('纬度')plt.show()if __name__ == '__main__':grid_spec_test()
contour会自动选择等高线的数量和位置,也可以通过levels参数手动指定:
# 指定10条等高线
plt.contour(X, Y, Z, levels=10)# 指定具体等高线位置
plt.contour(X, Y, Z, levels=[0.1, 0.3, 0.5, 0.7, 0.9])
填充等高线图(contourf)
contourf会填充等高线之间的区域,比contour更直观:
plt.contourf(X, Y, Z, levels=10, cmap='RdYlBu') # 使用红-黄-蓝色图
plt.colorbar()
plt.title('填充等高线图')
plt.show()
可以同时使用contour和contourf增强可视化效果:
# 先绘制填充
cf = plt.contourf(X, Y, Z, levels=10, cmap='coolwarm')# 再绘制等高线
c = plt.contour(X, Y, Z, levels=10, colors='black', linewidths=0.5)# 添加等高线标签
plt.clabel(c, inline=True, fontsize=8)plt.colorbar(cf)
plt.title('组合等高线图')
plt.show()
高级定制选项
线型和颜色
对于contour图,可以自定义线型和颜色:
# 不同等高线使用不同颜色和线型
CS = plt.contour(X, Y, Z, levels=5, colors=('r', 'g', 'b', 'c', 'm'),linestyles=('--', '-.', '-', ':', '--'))
plt.clabel(CS, fmt='%1.1f') # 格式化标签
透明度设置
可以设置填充区域的透明度:
plt.contourf(X, Y, Z, levels=10, alpha=0.6)
plt.contour(X, Y, Z, levels=10, colors='k', linewidths=0.5)
不等间距等高线
可以创建不等间距的等高线来突出特定区域:
levels = [0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0]
plt.contourf(X, Y, Z, levels=levels, extend='both') # extend允许超出范围
plt.colorbar()
实际应用示例
地形高度
# 生成地形数据
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)) # 圆形波浪地形# 绘制地形
plt.figure(figsize=(10, 6))
cf = plt.contourf(X, Y, Z, levels=20, cmap='terrain')
c = plt.contour(X, Y, Z, levels=20, colors='black', linewidths=0.5)
plt.clabel(c, inline=True, fontsize=8)
plt.colorbar(cf, label='高度')
plt.title('地形高度图')
plt.xlabel('经度')
plt.ylabel('纬度')
plt.show()
温度分布图
# 生成温度数据
x = np.linspace(0, 24, 100)
y = np.linspace(0, 30, 100)
X, Y = np.meshgrid(x, y)
Z = 20 + 10*np.sin(X/2) + 5*np.cos(Y/6) # 模拟昼夜和季节变化# 绘制温度分布
plt.figure(figsize=(10, 6))
cf = plt.contourf(X, Y, Z, levels=np.linspace(5, 35, 13), cmap='jet')
c = plt.contour(X, Y, Z, levels=np.linspace(5, 35, 13), colors='k', linewidths=0.5)
plt.clabel(c, inline=True, fmt='%1.0f°C')
plt.colorbar(cf, label='温度 (°C)')
plt.title('温度时空分布')
plt.xlabel('时间 (小时)')
plt.ylabel('天数')
plt.show()
数学函数可视化
# 定义复杂函数
def f(x, y):return np.sin(x) * np.cos(y) + np.sin(y/2) * np.cos(x/3)# 生成数据
x = np.linspace(-2*np.pi, 2*np.pi, 200)
y = np.linspace(-2*np.pi, 2*np.pi, 200)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)# 绘制函数图像
plt.figure(figsize=(10, 8))
plt.contourf(X, Y, Z, levels=20, cmap='coolwarm')
plt.contour(X, Y, Z, levels=20, colors='k', linewidths=0.3)
plt.colorbar(label='函数值')
plt.title('复杂函数 f(x,y) = sin(x)cos(y) + sin(y/2)cos(x/3)')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()
常见问题解决
- 锯齿状等高线:增加网格密度(np.linspace点数)
- 颜色条范围不合适:使用vmin/vmax参数手动设置范围
- 标签重叠:调整fmt格式或使用manual参数手动放置
- 内存不足:对于大数据集,减少网格点数或使用pcolormesh
- 数值范围过大:考虑对数据取对数(np.log)后再绘图
1.3:3D 绘图mplot3d
Matplotlib的mplot3d工具包提供了丰富多样的三维数据可视化功能,可以创建各种类型的三维图表
方法一:首先可以使用
projection="3d"
直接构建3d效果,可以拖动
import matplotlib.pyplot as plt
import numpy as np
# from mpl_toolkits.mplot3d import Axes3D# plt.rcParams['font.sans-serif'] = ['PingFang'] # Windows系统使用黑体
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falsedef grid_spec_test():# 创建图形和三维坐标轴fig = plt.axes(projection="3d")x = np.linspace(-5, 5, 100)y = np.linspace(-5, 5, 100)# 生成网格X, Y = np.meshgrid(x, y)# 计算Z, 创建三维曲面Z = np.sin(np.sqrt(X ** 2 + Y ** 2))# 绘制fig.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow')plt.show()if __name__ == '__main__':grid_spec_test()
方式二:使用Axes3D子图实现
# 创建画布,并在画布上创建对应的3D子图
fig = plt.figure()
ax = Axes3D(fig)
...
1.4:极坐标图polar
极坐标图是一种在极坐标系(半径和角度)而非笛卡尔坐标系(x和y)中绘制的图表,非常适合展示周期性或方向性数据。
要创建极坐标图,需要在创建子图时指定polar=True
参数
import numpy as np
import matplotlib.pyplot as plt# 创建极坐标图
ax = plt.subplot(111, polar=True)# 生成数据
theta = np.linspace(0, 2*np.pi, 100) # 角度
r = np.abs(np.sin(5*theta)) # 半径# 绘制极坐标线图
ax.plot(theta, r)plt.title('基本极坐标图')
plt.show()
主要极坐标图表类型
极坐标线图:
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, polar=True)# 生成更复杂的数据
theta = np.linspace(0, 2*np.pi, 200)
r1 = 1 + 0.3*np.sin(8*theta)
r2 = 0.8 + 0.2*np.cos(12*theta)# 绘制多条极坐标曲线
ax.plot(theta, r1, label='曲线1', lw=2)
ax.plot(theta, r2, label='曲线2', ls='--', lw=2)# 设置图例位置(转换为极坐标位置)
ax.legend(bbox_to_anchor=(1.1, 1.1))plt.title('极坐标线图')
plt.show()
极坐标散点图:
plt.figure(figsize=(8, 6))
ax = plt.subplot(111, polar=True)# 生成随机数据
theta = np.random.uniform(0, 2*np.pi, 50)
r = np.random.uniform(0, 1, 50)
colors = theta # 使用角度值作为颜色
sizes = 100 * r**2 # 使用半径值决定点大小# 绘制极坐标散点图
sc = ax.scatter(theta, r, c=colors, s=sizes, cmap='hsv', alpha=0.7)# 添加颜色条
plt.colorbar(sc, label='角度值')plt.title('极坐标散点图')
plt.show()
极坐标柱状图(风玫瑰图):
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, polar=True)# 生成数据 - 16个方向的频率
directions = np.linspace(0, 2*np.pi, 16, endpoint=False)
frequencies = np.random.randint(1, 10, 16)
width = 2*np.pi/16 * 0.8 # 柱宽# 绘制极坐标柱状图
bars = ax.bar(directions, frequencies, width=width, bottom=0.0, alpha=0.7, color=plt.cm.viridis(frequencies/10))# 设置角度刻度
ax.set_xticks(directions)
ax.set_xticklabels(['N', '', 'NE', '', 'E', '', 'SE', '', 'S', '', 'SW', '', 'W', '', 'NW', ''])plt.title('风玫瑰图(极坐标柱状图)')
plt.show()
极坐标填充图:
plt.figure(figsize=(8, 6))
ax = plt.subplot(111, polar=True)theta = np.linspace(0, 2*np.pi, 100)
r = 2 + np.sin(5*theta)# 填充极坐标曲线下方的区域
ax.fill(theta, r, 'skyblue', alpha=0.6)
ax.plot(theta, r, 'b-', lw=2)plt.title('极坐标填充图')
plt.show()
高级极坐标图定制
极坐标网格和刻度定制:
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, polar=True)theta = np.linspace(0, 2*np.pi, 100)
r = np.exp(0.1*theta)ax.plot(theta, r)# 自定义径向网格和标签
ax.set_rgrids([1, 2, 3, 4, 5], angle=45, labels=['1x', '2x', '3x', '4x', '5x'],color='gray', linestyle='--')# 自定义角度网格
ax.set_thetagrids(np.arange(0, 360, 45), labels=np.arange(0, 360, 45))# 设置径向范围
ax.set_rlim(0, 6)plt.title('自定义网格的极坐标图')
plt.show()
多极坐标子图:
fig = plt.figure(figsize=(12, 6))# 第一个子图
ax1 = fig.add_subplot(121, polar=True)
theta = np.linspace(0, 2*np.pi, 100)
r1 = np.abs(np.sin(3*theta))
ax1.plot(theta, r1)
ax1.set_title('3叶玫瑰线')# 第二个子图
ax2 = fig.add_subplot(122, polar=True)
r2 = np.abs(np.cos(4*theta))
ax2.plot(theta, r2, color='red')
ax2.set_title('4叶玫瑰线')plt.tight_layout()
plt.show()
极坐标等高线图:
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, polar=True)# 生成网格数据
theta = np.linspace(0, 2*np.pi, 100)
r = np.linspace(0, 3, 100)
T, R = np.meshgrid(theta, r)
Z = ((R**2 - 1)**2)# 绘制极坐标等高线图
contour = ax.contour(T, R, Z, levels=10, cmap='rainbow')# 添加标签
ax.clabel(contour, inline=True, fontsize=8)plt.title('极坐标等高线图')
plt.show()
实际应用示例
雷达图(蜘蛛网图):
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D# plt.rcParams['font.sans-serif'] = ['PingFang'] # Windows系统使用黑体
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falsedef grid_spec_test():fig = plt.figure(figsize=(8, 6))ax = fig.add_subplot(111, polar=True)# 数据 - 五个维度的评分categories = ['速度', '力量', '技巧', '防守', '耐力']values1 = [4, 3, 5, 2, 4]values2 = [3, 4, 2, 3, 4]N = len(categories)# 闭合数据values1 += values1[:1]angles1 = np.linspace(0, 2 * np.pi, N, endpoint=False).tolist()angles1 += angles1[:1]values2 += values2[:1]angles2 = np.linspace(0, 2 * np.pi, N, endpoint=False).tolist()angles2 += angles2[:1]# 绘制雷达图ax.plot(angles1, values1, 'b-', linewidth=2, label='球员A')ax.fill(angles1, values1, 'b', alpha=0.2)ax.plot(angles2, values2, 'r-', linewidth=2, label='球员B')ax.fill(angles2, values2, 'r', alpha=0.2)# 设置角度刻度ax.set_xticks(angles1[:-1])ax.set_xticklabels(categories1)ax.set_xticks(angles2[:-1])ax.set_xticklabels(categories2)# 设置径向刻度ax.set_yticks([1, 2, 3, 4, 5])ax.set_ylim(0, 5)plt.title('运动员能力雷达图')plt.legend(loc='upper right')plt.show()if __name__ == '__main__':grid_spec_test()
24小时极坐标时钟图:
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, polar=True)# 生成24小时数据
hours = np.linspace(0, 2*np.pi, 24, endpoint=False)
activity = np.random.randint(1, 10, 24)# 绘制柱状图
bars = ax.bar(hours, activity, width=2*np.pi/24*0.8,color=plt.cm.plasma(activity/10),edgecolor='k')# 设置时钟样式
ax.set_theta_zero_location('N') # 0度在顶部
ax.set_theta_direction(-1) # 顺时针方向
ax.set_xticks(hours)
ax.set_xticklabels(range(24))
ax.set_rgrids([2, 4, 6, 8], angle=0)plt.title('24小时活动极坐标图')
plt.show()
常见问题与技巧
-
角度方向控制:
ax.set_theta_direction(-1) # 顺时针方向 ax.set_theta_zero_location('N') # 0度在顶部
-
径向标签位置:
ax.set_rlabel_position(135) # 径向标签放在135度位置
-
极坐标与笛卡尔坐标转换:
# 极坐标转笛卡尔坐标 x = r * np.cos(theta) y = r * np.sin(theta)
-
处理负半径值:
- 负半径会显示在相反方向的角度上
- 可以使用
np.abs()
处理数据,如果不需要这种特性
-
极坐标图保存:
plt.savefig('polar_plot.png', dpi=300, bbox_inches='tight', transparent=True)
极坐标图是展示周期性数据、方向性数据和多变量比较的理想选择。通过合理设置角度、径向参数以及颜色映射,可以创建出信息丰富且美观的可视化图表。
1.5:热力图imshow/pcolor
热力图是一种用颜色矩阵展示数据值的二维可视化方法,Matplotlib提供了imshow
和pcolor
两种主要函数来创建热力图
imshow
是最常用的热力图函数,适合显示规则的二维数组数据:
import numpy as np
import matplotlib.pyplot as plt# 创建数据(10x10的随机矩阵)
data = np.random.rand(10, 10)# 基础热力图
plt.figure(figsize=(8, 6))
plt.imshow(data)
plt.colorbar() # 添加颜色条
plt.title('基础imshow热力图')
plt.show()
plt.imshow(data,cmap='viridis', # 颜色映射interpolation='nearest', # 插值方式aspect='auto', # 纵横比('auto','equal',数字)origin='upper', # 原点位置('upper','lower')vmin=0, vmax=1, # 颜色范围限制alpha=0.8) # 透明度
pcolor
和更高效的pcolormesh
适合非均匀网格数据:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D# plt.rcParams['font.sans-serif'] = ['PingFang'] # Windows系统使用黑体
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falsedef grid_spec_test():# 创建非均匀网格数据x = np.arange(0, 10, 1)y = np.arange(0, 15, 1.5)X, Y = np.meshgrid(x, y)Z = np.sin(X) + np.cos(Y)# pcolormesh绘图plt.figure(figsize=(10, 6))plt.pcolormesh(X, Y, Z,shading='auto', # 着色方式('auto','flat','gouraud')cmap='coolwarm')plt.colorbar(label='数值')plt.title('pcolormesh热力图')plt.xlabel('X轴')plt.ylabel('Y轴')plt.show()if __name__ == '__main__':grid_spec_test()
2:动画和交互
2.1:基本动画
Matplotlib的动画功能主要通过animation模块实现,可以创建各种动态可视化效果。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(8, 5))
x = np.linspace(0, 2*np.pi, 200)
line, = ax.plot(x, np.sin(x))
ax.set_ylim(-1.5, 1.5)# 动画更新函数
def update(frame):line.set_ydata(np.sin(x + frame/10)) # 更新y数据return line,# 创建动画
ani = FuncAnimation(fig, update, frames=100, interval=50, blit=True)plt.title('正弦波动画')
plt.show()
可以保存为gif或者mp4
# 保存为GIF需要安装pillow
ani.save('sine_wave.gif', writer='pillow', fps=20, dpi=100)# 保存为MP4需要安装ffmpeg
ani.save('sine_wave.mp4', writer='ffmpeg', fps=20, bitrate=1800, dpi=100)
2.2:交互式绘图
缩放和平移
plt.ion() # 开启交互模式fig, ax = plt.subplots(figsize=(8, 5))
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), label='sin(x)')
ax.plot(x, np.cos(x), label='cos(x)')
ax.legend()
# 交互功能会自动启用
plt.title('可缩放平移的图表 (尝试用鼠标操作)')
plt.ioff() # 关闭交互模式
plt.show()
数据光标功能
from matplotlib.widgets import Cursorfig, ax = plt.subplots(figsize=(8, 5))
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax.plot(x, y)
# 添加十字光标
cursor = Cursor(ax, horizOn=True, vertOn=True, color='red', linewidth=1)plt.title('带数据光标的图表 (鼠标移动查看坐标)')
plt.show()
交互式标记点
class ClickMarker:def __init__(self, ax):self.ax = axself.xs, self.ys = [], []self.line, = ax.plot([], [], 'ro', ms=8)self.cid = fig.canvas.mpl_connect('button_press_event', self)def __call__(self, event):if event.inaxes != self.ax: returnself.xs.append(event.xdata)self.ys.append(event.ydata)self.line.set_data(self.xs, self.ys)fig.canvas.draw()fig, ax = plt.subplots(figsize=(8, 5))
ax.set_xlim(0, 10); ax.set_ylim(-2, 2)
ax.plot(np.linspace(0, 10, 100), np.sin(np.linspace(0, 10, 100)))click = ClickMarker(ax)
plt.title('点击图表添加标记点')
plt.show()
交互式控件
from matplotlib.widgets import Slider, Button
import matplotlib.pyplot as plt
import numpy as np# plt.rcParams['font.sans-serif'] = ['PingFang'] # Windows系统使用黑体
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # macOS系统
# plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # Linux系统或通用方案# 解决负号('-')显示为方块的问题
plt.rcParams['axes.unicode_minus'] = Falsefig, (ax, slider_ax) = plt.subplots(2, 1, figsize=(8, 6),gridspec_kw={'height_ratios': [4, 1]})x = np.linspace(0, 2*np.pi, 200)
freq_init = 1.0
line, = ax.plot(x, np.sin(freq_init * x))
ax.set_ylim(-1.5, 1.5)# 创建滑块
slider = Slider(slider_ax, '频率', 0.1, 5.0, valinit=freq_init)def update(val):freq = slider.valline.set_ydata(np.sin(freq * x))fig.canvas.draw_idle()slider.on_changed(update)# 添加重置按钮
reset_ax = plt.axes([0.8, 0.025, 0.1, 0.04])
button = Button(reset_ax, '重置')def reset(event):slider.reset()button.on_clicked(reset)plt.title('带交互控件的图表')
plt.tight_layout()
plt.show()
2.3:事件处理
Matplotlib提供了完善的事件处理系统,可以捕获并响应各种用户交互事件。
键盘事件处理
def on_key(event):print(f'你按下了: {event.key}')if event.key == 'escape':plt.close(event.canvas.figure)fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(np.random.rand(10))fig.canvas.mpl_connect('key_press_event', on_key)
plt.title('尝试按键盘按键 (ESC键退出)')
plt.show()
鼠标事件处理
def on_move(event):if event.inaxes:print(f'鼠标位置: x={event.xdata:.2f}, y={event.ydata:.2f}')def on_click(event):if event.inaxes:print(f'在位置 ({event.xdata:.2f}, {event.ydata:.2f}) 点击了 {event.button} 键')fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(np.random.rand(10))fig.canvas.mpl_connect('motion_notify_event', on_move)
fig.canvas.mpl_connect('button_press_event', on_click)
plt.title('移动鼠标和点击查看事件')
plt.show()
自定义选取区域
class RegionSelector:def __init__(self, ax):self.ax = axself.start = Noneself.rect = Noneself.cid_press = fig.canvas.mpl_connect('button_press_event', self.on_press)self.cid_release = fig.canvas.mpl_connect('button_release_event', self.on_release)def on_press(self, event):if event.inaxes != self.ax: returnself.start = (event.xdata, event.ydata)self.rect = plt.Rectangle((event.xdata, event.ydata), 0, 0, fill=False, edgecolor='red', linewidth=2)self.ax.add_patch(self.rect)def on_release(self, event):if self.start is None: returnx0, y0 = self.startx1, y1 = event.xdata, event.ydatawidth = x1 - x0height = y1 - y0print(f'选取区域: x={min(x0,x1):.2f}-{max(x0,x1):.2f}, y={min(y0,y1):.2f}-{max(y0,y1):.2f}')self.rect.set_width(width)self.rect.set_height(height)fig.canvas.draw()self.start = Nonefig, ax = plt.subplots(figsize=(8, 5))
ax.plot(np.random.rand(100))selector = RegionSelector(ax)
plt.title('鼠标拖拽选取区域')
plt.show()
复杂事件处理示例
class InteractivePlot:def __init__(self):self.fig, self.ax = plt.subplots(figsize=(10, 6))self.x = np.linspace(0, 10, 100)self.line, = self.ax.plot(self.x, np.sin(self.x))self.fig.canvas.mpl_connect('key_press_event', self.on_key)self.fig.canvas.mpl_connect('scroll_event', self.on_scroll)self.freq = 1.0self.amp = 1.0self.ax.set_title("使用↑↓调整频率(当前:1.0), 滚轮调整振幅(当前:1.0)")def on_key(self, event):if event.key == 'up':self.freq += 0.1elif event.key == 'down':self.freq -= 0.1self.update_plot()def on_scroll(self, event):if event.button == 'up':self.amp += 0.1elif event.button == 'down':self.amp -= 0.1self.update_plot()def update_plot(self):self.line.set_ydata(self.amp * np.sin(self.freq * self.x))self.ax.set_title(f"使用↑↓调整频率(当前:{self.freq:.1f}), 滚轮调整振幅(当前:{self.amp:.1f})")self.fig.canvas.draw()interactive_plot = InteractivePlot()
plt.show()