目录
一、为什么 Matplotlib 是 Python 可视化的 “基石”?
二、环境搭建与核心概念:从安装到理解 Matplotlib 的 “绘图逻辑”
2.3 核心概念:搞懂 Figure、Axes、Axis 的关系
4.5.1 基础交互(Jupyter Notebook 中生效)

class 卑微码农:
def __init__(self):
self.技能 = ['能读懂十年前祖传代码', '擅长用Ctrl+C/V搭建世界', '信奉"能跑就别动"的玄学']
self.发量 = 100 # 初始发量
self.咖啡因耐受度 = '极限'
def 修Bug(self, bug):
try:
# 试图用玄学解决问题
if bug.严重程度 == '离谱':
print("这一定是环境问题!")
else:
print("让我看看是谁又没写注释...哦,是我自己。")
except Exception as e:
# 如果try块都救不了,那就...
print("重启一下试试?")
self.发量 -= 1 # 每解决一个bug,头发-1
# 实例化一个我
我 = 卑微码农()
引言
在数据分析、科研报告、商业汇报中,“一图胜千言” 永远是真理 —— 枯燥的数字表格难以让人快速抓住重点,而清晰直观的图表能瞬间传递数据背后的趋势、规律与差异。在 Python 生态中,Matplotlib 正是实现数据可视化的 “基石工具”:它灵活强大,能绘制从简单折线图到复杂 3D 曲面图的几乎所有图表类型;它兼容广泛,可与 NumPy、Pandas 无缝衔接,成为数据处理流程的最后一环。

无论是新手想要快速画出第一个数据图表,还是开发者需要定制化专业级可视化作品,Matplotlib 都能满足需求。本文从实际应用场景出发,通过 “基础概念→核心图表→进阶定制→实战案例” 的递进结构,搭配可直接运行的代码示例,帮你从 0 到 1 掌握 Matplotlib,轻松搞定 90% 以上的数据可视化需求。
一、为什么 Matplotlib 是 Python 可视化的 “基石”?

在 Matplotlib 出现之前,数据可视化的方式存在明显局限:
- Excel/Tableau:拖拽式操作简单,但定制化能力弱,复杂图表难以实现,且无法嵌入 Python 代码自动化流程;
- R 语言 ggplot2:语法优雅,但与 Python 生态融合性差,Python 开发者需额外学习 R 语言;
- Python 原生绘图:需手动处理像素、坐标计算,代码繁琐,效率极低。
而 Matplotlib 的核心优势在于 **“灵活可控、生态兼容、功能全面”**,它不仅是 Python 可视化的 “开山鼻祖”,更是后续 Seaborn、Plotly 等高级库的基础:
- 图表类型全覆盖:支持折线图、柱状图、直方图、散点图、饼图、箱线图、3D 图等数十种图表;
- 定制化程度极高:从颜色、线型到坐标轴、图例,每一个细节都可手动调整,满足专业汇报、论文发表的需求;
- 无缝衔接数据处理库:与 NumPy 数组、Pandas DataFrame 完美兼容,直接读取数据绘图;
- 跨平台与多格式支持:可在 Windows、Linux、Mac 上运行,支持保存为 PNG、JPG、PDF、SVG 等多种格式;
- 支持交互可视化:结合 mpl_toolkits、ipywidgets 等工具,可实现缩放、拖拽、动态更新的交互效果。
无论是学生做课程报告、分析师呈现数据结论,还是科研人员发表论文图表,Matplotlib 都是 Python 用户的首选可视化工具。
二、环境搭建与核心概念:从安装到理解 Matplotlib 的 “绘图逻辑”

2.1 安装 Matplotlib
Matplotlib 是第三方库,需手动安装,推荐搭配 NumPy(生成测试数据)和 Pandas(处理实际数据)使用:
# 基础安装(推荐pip方式)
pip install matplotlib
# 安装最新版本(包含新功能与bug修复)
pip install matplotlib --upgrade
# 搭配数据处理库安装(推荐)
pip install matplotlib numpy pandas
2.2 验证安装
安装完成后,在 Python 环境中导入库,绘制一个简单折线图,若能正常显示则安装成功:
import matplotlib.pyplot as plt
import numpy as np
# 生成测试数据
x = np.linspace(0, 10, 100) # 0到10之间生成100个均匀分布的点
y = np.sin(x) # 计算正弦值
# 绘制折线图
plt.plot(x, y)
plt.title("简单正弦曲线")
plt.show() # 显示图表
运行后若弹出包含正弦曲线的窗口,则说明安装成功。
2.3 核心概念:搞懂 Figure、Axes、Axis 的关系
Matplotlib 的绘图逻辑围绕三个核心对象展开,这是理解其用法的关键,新手常因混淆这三个概念导致代码混乱:
| 对象 | 通俗理解 | 作用 |
|---|---|---|
| Figure | 绘图的 “画布” | 所有图表的容器,可包含多个子图(Axes) |
| Axes | 画布上的 “子图” | 实际绘制图表的区域,一个 Figure 可包含多个 Axes |
| Axis | 子图的 “坐标轴” | 控制坐标轴的范围、刻度、标签等细节 |
形象比喻:Figure 就像一块白板,Axes 是白板上划分的一个个 “绘图区域”,每个区域(Axes)都有自己的 x 轴、y 轴(Axis),可以画不同的图表。
代码示例:直观理解三大对象
import matplotlib.pyplot as plt
# 1. 创建Figure(画布),指定大小
fig = plt.figure(figsize=(10, 6)) # 宽10英寸,高6英寸
# 2. 在Figure上添加Axes(子图):2行1列的第1个位置
ax1 = fig.add_subplot(2, 1, 1) # (rows, cols, index),index从1开始
ax1.set_title("第一个子图(折线图)")
# 3. 在Axes上添加Axis细节(可选,自动生成默认坐标轴)
ax1.set_xlabel("X轴标签")
ax1.set_ylabel("Y轴标签")
# 4. 在Axes上绘图
ax1.plot([1, 2, 3, 4], [10, 20, 15, 25])
# 5. 添加第二个子图:2行1列的第2个位置
ax2 = fig.add_subplot(2, 1, 2)
ax2.set_title("第二个子图(柱状图)")
ax2.bar([1, 2, 3], [5, 15, 10])
# 调整子图间距,避免标题重叠
plt.tight_layout()
# 显示画布
plt.show()
运行后会看到一个包含两个子图的画布,清晰体现了 Figure→Axes→图表的层级关系。
三、核心图表绘制:覆盖 90% 的可视化场景

Matplotlib 支持数十种图表类型,以下是最常用的 7 种图表,每种都包含 “场景说明 + 代码示例 + 参数解析”,可直接套用。
3.1 折线图:展示趋势变化
适用场景:时间序列数据的趋势展示(如每日销售额、气温变化、股票价格走势)。
基础折线图
import matplotlib.pyplot as plt
import numpy as np
# 生成数据:0到10之间100个点,计算正弦和余弦值
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制折线图:label用于图例,linewidth控制线宽,color指定颜色
ax.plot(x, y1, label="sin(x)", linewidth=2, color="blue", linestyle="-") # 实线
ax.plot(x, y2, label="cos(x)", linewidth=2, color="red", linestyle="--") # 虚线
# 设置标题和坐标轴标签
ax.set_title("正弦函数与余弦函数曲线", fontsize=15, pad=20) # pad控制标题与图表的间距
ax.set_xlabel("X轴(0-10)", fontsize=12)
ax.set_ylabel("Y轴(函数值)", fontsize=12)
# 设置x轴和y轴范围
ax.set_xlim(0, 10)
ax.set_ylim(-1.2, 1.2)
# 添加网格线(便于读取数值)
ax.grid(True, alpha=0.3) # alpha控制透明度
# 添加图例(显示label)
ax.legend(loc="upper right", fontsize=10)
# 显示图表
plt.show()
关键参数说明
linestyle:线型(-实线、--虚线、-.点划线、:点线);marker:数据点标记(o圆圈、s正方形、^三角形、*星号);color:颜色(支持英文单词、十六进制代码如#FF5733、RGB tuple 如(0.2, 0.8, 0.5))。
3.2 柱状图:对比类别数据
适用场景:不同类别数据的数值对比(如各地区销售额、各学科成绩、不同产品销量)。
基础柱状图(单组)
import matplotlib.pyplot as plt
import numpy as np
# 数据:产品类别和对应的销量
products = ["产品A", "产品B", "产品C", "产品D"]
sales = [350, 420, 280, 500]
# 创建画布和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 绘制柱状图:width控制柱子宽度
bars = ax.bar(products, sales, width=0.6, color=["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4"])
# 在柱子顶部添加数值标签
for bar in bars:
height = bar.get_height()
ax.text(
bar.get_x() + bar.get_width()/2, # x坐标(柱子中心)
height + 5, # y坐标(柱子顶部+5,避免与柱子重叠)
f"{height}", # 显示的数值
ha="center", # 水平居中
va="bottom", # 垂直底部对齐
fontsize=10
)
# 设置标题和标签
ax.set_title("四款产品月度销量对比", fontsize=15)
ax.set_xlabel("产品类别", fontsize=12)
ax.set_ylabel("销量(单位:件)", fontsize=12)
# 设置y轴范围(从0开始,更直观)
ax.set_ylim(0, 550)
# 添加网格线(仅y轴,横向网格更易对比数值)
ax.grid(True, axis="y", alpha=0.3)
plt.show()
分组柱状图(多组对比)
import matplotlib.pyplot as plt
import numpy as np
# 数据:两个季度的产品销量对比
products = ["产品A", "产品B", "产品C", "产品D"]
q1_sales = [350, 420, 280, 500]
q2_sales = [400, 450, 320, 520]
# 设置柱子宽度和位置
width = 0.35
x = np.arange(len(products)) # 产品类别对应的x坐标(0,1,2,3)
# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制两组柱状图:一组在x - width/2,一组在x + width/2
bars1 = ax.bar(x - width/2, q1_sales, width, label="Q1销量", color="#FF6B6B")
bars2 = ax.bar(x + width/2, q2_sales, width, label="Q2销量", color="#4ECDC4")
# 添加数值标签
def add_labels(bars):
for bar in bars:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2, height + 5, f"{height}", ha="center", va="bottom")
add_labels(bars1)
add_labels(bars2)
# 设置x轴刻度和标签(居中显示在两组柱子中间)
ax.set_xticks(x)
ax.set_xticklabels(products)
# 设置标题、标签和图例
ax.set_title("四款产品Q1与Q2销量对比", fontsize=15)
ax.set_xlabel("产品类别", fontsize=12)
ax.set_ylabel("销量(单位:件)", fontsize=12)
ax.legend()
ax.grid(True, axis="y", alpha=0.3)
plt.show()
3.3 直方图:展示数据分布
适用场景:连续数据的分布情况(如学生成绩分布、身高分布、产品价格分布)。
import matplotlib.pyplot as plt
import numpy as np
# 生成模拟数据:1000个符合正态分布的随机数(均值100,标准差15)
data = np.random.normal(loc=100, scale=15, size=1000) # 模拟学生成绩
# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制直方图:bins控制柱子数量,density=True表示频率分布
n, bins, patches = ax.hist(
x=data,
bins=20, # 柱子数量(可根据数据调整,默认10)
density=True, # 若为False,显示频数;True显示频率
color="#45B7D1",
alpha=0.7, # 透明度
edgecolor="black" # 柱子边框颜色
)
# 添加正态分布拟合曲线(使分布更直观)
mu, sigma = np.mean(data), np.std(data)
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
ax.plot(x, (1/(sigma*np.sqrt(2*np.pi)))*np.exp(-0.5*((x-mu)/sigma)**2), color="red", linewidth=2)
# 设置标题和标签
ax.set_title("学生成绩分布直方图(正态分布)", fontsize=15)
ax.set_xlabel("成绩", fontsize=12)
ax.set_ylabel("频率密度", fontsize=12) # density=True时y轴为频率密度
# 添加网格线
ax.grid(True, alpha=0.3)
plt.show()
关键区别:柱状图 vs 直方图
- 柱状图:用于离散类别数据,柱子之间有空隙,宽度无意义;
- 直方图:用于连续数据,柱子之间无空隙,宽度表示区间范围。
3.4 散点图:分析变量相关性
适用场景:两个变量之间的关系分析(如广告投入与销售额、身高与体重、温度与销量)。
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 生成模拟数据:广告投入(x)与销售额(y),添加随机噪声
np.random.seed(42) # 设置随机种子,保证结果可复现
x = np.linspace(10, 100, 50) # 广告投入(10-100万元)
y = 2*x + np.random.normal(0, 10, 50) # 销售额=2*广告投入+噪声
# 转为DataFrame(模拟实际数据格式)
df = pd.DataFrame({"广告投入": x, "销售额": y})
# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制散点图:s控制点大小,c控制颜色,alpha控制透明度
scatter = ax.scatter(
x=df["广告投入"],
y=df["销售额"],
s=50, # 点的大小
c=df["广告投入"], # 按广告投入着色(颜色渐变)
cmap="viridis", # 颜色映射方案
alpha=0.7,
edgecolors="black",
linewidth=0.5
)
# 添加颜色条(解释颜色含义)
cbar = plt.colorbar(scatter)
cbar.set_label("广告投入(万元)", fontsize=10)
# 添加趋势线(线性回归拟合)
z = np.polyfit(df["广告投入"], df["销售额"], 1) # 一次多项式拟合
p = np.poly1d(z)
ax.plot(x, p(x), "r--", linewidth=2, label=f"趋势线:y={z[0]:.2f}x+{z[1]:.2f}")
# 设置标题和标签
ax.set_title("广告投入与销售额相关性分析", fontsize=15)
ax.set_xlabel("广告投入(万元)", fontsize=12)
ax.set_ylabel("销售额(万元)", fontsize=12)
# 添加网格线和图例
ax.grid(True, alpha=0.3)
ax.legend()
plt.show()
结果解读:
- 散点呈明显的正相关趋势,说明广告投入越多,销售额越高;
- 趋势线斜率为 2.03,表明广告投入每增加 1 万元,销售额平均增加 2.03 万元。
3.5 饼图:展示占比关系
适用场景:各部分占总体的比例(如市场份额、收入构成、用户分布)。
import matplotlib.pyplot as plt
import numpy as np
# 数据:各渠道收入占比
channels = ["线上平台", "线下门店", "代理商", "其他"]
revenues = [45, 30, 20, 5] # 占比总和为100%
colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4"]
explode = (0.05, 0, 0, 0) # 突出显示第一部分(线上平台)
# 创建画布(饼图建议用正方形画布,避免变形)
fig, ax = plt.subplots(figsize=(8, 8))
# 绘制饼图
wedges, texts, autotexts = ax.pie(
x=revenues,
labels=channels,
colors=colors,
explode=explode, # 部分扇形偏离中心
autopct="%1.1f%%", # 显示百分比(保留1位小数)
startangle=90, # 起始角度(90度为垂直向上)
shadow=True, # 添加阴影效果
textprops={"fontsize": 12} # 文本字体大小
)
# 美化百分比文本(颜色、字体)
for autotext in autotexts:
autotext.set_color("white")
autotext.set_fontweight("bold")
# 设置标题
ax.set_title("2024年各渠道收入占比", fontsize=16, pad=30)
# 保证饼图为正圆形
ax.axis("equal")
plt.show()
关键参数说明
explode:用于突出某个扇形,参数为与数据长度相同的 tuple,值越大偏离越远;autopct:百分比格式字符串(%1.1f%%表示保留 1 位小数,末尾加百分号);startangle:起始角度,默认 0 度(水平向右),90 度为垂直向上。
3.6 箱线图:分析数据离散程度
适用场景:展示数据的分布特征(中位数、四分位数、异常值),常用于多组数据对比(如不同班级成绩离散度、不同地区气温波动)。
import matplotlib.pyplot as plt
import numpy as np
# 生成模拟数据:3个班级的学生成绩
np.random.seed(42)
class1 = np.random.normal(80, 5, 50) # 班级1:均值80,标准差5
class2 = np.random.normal(75, 8, 50) # 班级2:均值75,标准差8(离散度更大)
class3 = np.random.normal(85, 6, 50) # 班级3:均值85,标准差6
data = [class1, class2, class3]
labels = ["班级1", "班级2", "班级3"]
# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制箱线图:patch_artist=True允许填充颜色
box_plot = ax.boxplot(
x=data,
labels=labels,
patch_artist=True, # 填充箱体颜色
notch=False, # 是否绘制凹槽(展示中位数置信区间)
showfliers=True, # 是否显示异常值
showmeans=True, # 是否显示均值(绿色三角形)
meanprops={"marker": "D", "markerfacecolor": "green"}, # 均值标记样式
flierprops={"marker": "o", "markerfacecolor": "red", "alpha": 0.5} # 异常值样式
)
# 为箱体设置不同颜色
colors = ["#FF6B6B", "#4ECDC4", "#45B7D1"]
for patch, color in zip(box_plot["boxes"], colors):
patch.set_facecolor(color)
patch.set_alpha(0.7)
# 设置标题和标签
ax.set_title("三个班级学生成绩离散度分析", fontsize=15)
ax.set_xlabel("班级", fontsize=12)
ax.set_ylabel("成绩", fontsize=12)
# 添加网格线(y轴)
ax.grid(True, axis="y", alpha=0.3)
plt.show()
箱线图解读:
- 箱体:上下沿为四分位数(Q1、Q3),中间线为中位数(Q2),箱体高度为四分位距(IQR=Q3-Q1);
- 须:上下须分别延伸至 Q1-1.5IQR 和 Q3+1.5IQR 范围内的最值;
- 异常值:超出须范围的点(红色圆点);
- 均值:绿色菱形标记,可与中位数对比观察数据对称性。
3.7 热力图:展示矩阵数据相关性
适用场景:矩阵数据的相关性分析(如特征相关性、用户行为热力图、地区 - 时间销量矩阵)。
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 生成模拟数据:5个特征之间的相关性矩阵
np.random.seed(42)
data = np.random.randn(100, 5) # 100个样本,5个特征
df = pd.DataFrame(data, columns=["特征A", "特征B", "特征C", "特征D", "特征E"])
corr_matrix = df.corr() # 计算相关性矩阵(Pearson相关系数)
# 创建画布和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 绘制热力图:cmap控制颜色映射,annot=True显示数值
im = ax.imshow(corr_matrix, cmap="RdBu_r", aspect="auto", vmin=-1, vmax=1)
# 添加颜色条(解释相关系数含义)
cbar = plt.colorbar(im)
cbar.set_label("Pearson相关系数", fontsize=10)
# 在热力图上显示相关系数数值
for i in range(len(corr_matrix.columns)):
for j in range(len(corr_matrix.columns)):
text = ax.text(
j, i,
f"{corr_matrix.iloc[i, j]:.2f}", # 保留2位小数
ha="center",
va="center",
color="white" if abs(corr_matrix.iloc[i, j]) > 0.5 else "black", # 数值深浅对应文字颜色
fontsize=10
)
# 设置坐标轴标签(旋转x轴标签避免重叠)
ax.set_xticks(np.arange(len(corr_matrix.columns)))
ax.set_yticks(np.arange(len(corr_matrix.columns)))
ax.set_xticklabels(corr_matrix.columns, rotation=45, ha="right")
ax.set_yticklabels(corr_matrix.columns)
# 设置标题
ax.set_title("特征相关性热力图", fontsize=15, pad=20)
plt.tight_layout()
plt.show()
热力图解读:
- 颜色越接近红色,正相关性越强;越接近蓝色,负相关性越强;白色为无相关性(相关系数 = 0);
- 对角线为特征自身的相关性(恒为 1);
- 可快速识别强相关特征,用于特征选择(如删除高度冗余的特征)。
四、进阶技巧:打造专业级可视化图表

基础图表能满足日常需求,进阶技巧可让图表更美观、更专业,适配汇报、论文等场景。
4.1 图表样式定制:颜色、字体与主题
4.1.1 颜色定制
Matplotlib 支持多种颜色指定方式,推荐使用专业的配色方案:
# 1. 英文颜色名(基础颜色)
plt.plot(x, y, color="blue")
# 2. 十六进制代码(精准配色,推荐从配色网站获取)
plt.plot(x, y, color="#FF5733")
# 3. RGB/RGBA tuple(透明度可控)
plt.plot(x, y, color=(0.2, 0.8, 0.5)) # RGB
plt.plot(x, y, color=(0.2, 0.8, 0.5, 0.6)) # RGBA,最后一位为透明度
# 4. 颜色映射(colormap):用于连续数据
cmap = plt.cm.viridis # 常用配色方案:viridis、plasma、coolwarm、RdBu_r
4.1.2 字体定制(解决中文显示乱码)
默认情况下 Matplotlib 不支持中文,需手动设置字体:
import matplotlib.pyplot as plt
# Windows系统(常用字体:SimHei黑体、Microsoft YaHei微软雅黑)
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示为方块的问题
# Linux系统(常用字体:WenQuanYi Micro Hei、DejaVu Sans)
plt.rcParams["font.sans-serif"] = ["WenQuanYi Micro Hei"]
# Mac系统(常用字体:Heiti TC、Arial Unicode MS)
plt.rcParams["font.sans-serif"] = ["Heiti TC"]
# 定制字体大小和样式
plt.rcParams["font.size"] = 10 # 全局字体大小
plt.rcParams["axes.titlesize"] = 15 # 标题字体大小
plt.rcParams["axes.labelsize"] = 12 # 坐标轴标签字体大小
4.1.3 主题切换
Matplotlib 提供多种预设主题,可快速美化图表:
# 查看所有可用主题
print(plt.style.available)
# 使用预设主题(推荐:seaborn-whitegrid、ggplot、fivethirtyeight)
plt.style.use("seaborn-v0_8-whitegrid") # seaborn风格的白色网格
# plt.style.use("ggplot") # R语言ggplot2风格
# plt.style.use("fivethirtyeight") # 538新闻网风格
4.2 子图布局:灵活排列多个图表
除了基础的subplot,Matplotlib 还提供更灵活的子图布局方式。
4.2.1 用subplots创建均匀布局
# 创建2行2列的子图,共享x轴和y轴
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 10), sharex=True, sharey=True)
# 第一个子图(0,0)
axes[0, 0].plot(x, y1)
axes[0, 0].set_title("子图1")
# 第二个子图(0,1)
axes[0, 1].bar(x, y2)
axes[0, 1].set_title("子图2")
# 第三个子图(1,0)
axes[1, 0].scatter(x, y3)
axes[1, 0].set_title("子图3")
# 第四个子图(1,1)
axes[1, 1].hist(x)
axes[1, 1].set_title("子图4")
# 统一设置x轴和y轴标签(仅需设置最后一行和第一列)
fig.text(0.5, 0.04, "X轴统一标签", ha="center", fontsize=12)
fig.text(0.04, 0.5, "Y轴统一标签", va="center", rotation=90, fontsize=12)
# 调整子图间距
plt.tight_layout()
plt.subplots_adjust(bottom=0.1, left=0.1) # 调整底部和左侧边距
plt.show()
4.2.2 用gridspec创建非均匀布局
当子图大小不同时,使用GridSpec更灵活:
import matplotlib.gridspec as gridspec
# 创建画布
fig = plt.figure(figsize=(12, 10))
# 定义网格布局:3行3列
gs = gridspec.GridSpec(3, 3, figure=fig)
# 第一个子图:占第1行,1-3列(跨3列)
ax1 = fig.add_subplot(gs[0, :])
ax1.set_title("子图1(跨3列)")
# 第二个子图:占第2行,1列
ax2 = fig.add_subplot(gs[1, 0])
ax2.set_title("子图2")
# 第三个子图:占第2-3行,2-3列(跨2行2列)
ax3 = fig.add_subplot(gs[1:, 1:])
ax3.set_title("子图3(跨2行2列)")
# 第四个子图:占第3行,1列
ax4 = fig.add_subplot(gs[2, 0])
ax4.set_title("子图4")
plt.tight_layout()
plt.show()
4.3 文字标注与箭头:突出关键信息
在图表中添加标注和箭头,可突出重要数据点或趋势:
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
x = np.linspace(0, 10, 100)
y = np.sin(x)
# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, y, linewidth=2, color="blue")
# 标注最大值点(x=π/2,y=1)
max_x = np.pi/2
max_y = 1
ax.scatter(max_x, max_y, color="red", s=100, zorder=5) # zorder确保点在直线上方
# 添加文字标注
ax.annotate(
"最大值:sin(π/2)=1", # 标注文本
xy=(max_x, max_y), # 标注目标点
xytext=(max_x + 1, max_y + 0.2), # 文本位置
fontsize=12,
color="red",
fontweight="bold",
# 添加箭头
arrowprops=dict(
arrowstyle="->", # 箭头样式
color="red",
linewidth=2
)
)
# 标注最小值点(x=3π/2,y=-1)
min_x = 3*np.pi/2
min_y = -1
ax.scatter(min_x, min_y, color="green", s=100, zorder=5)
ax.annotate(
"最小值:sin(3π/2)=-1",
xy=(min_x, min_y),
xytext=(min_x - 2, min_y - 0.3),
fontsize=12,
color="green",
fontweight="bold",
arrowprops=dict(arrowstyle="->", color="green", linewidth=2)
)
ax.set_title("正弦函数关键点位标注", fontsize=15)
ax.set_xlabel("X轴")
ax.set_ylabel("Y轴")
ax.grid(True, alpha=0.3)
plt.show()
4.4 保存图片:高清无失真
绘制完成后,需保存图片用于汇报或论文,关键是设置高清分辨率:
# 方法1:plt.savefig(保存当前画布)
plt.plot(x, y)
plt.title("示例图")
# dpi:分辨率(推荐300,高清;论文建议600),bbox_inches="tight"去除多余空白
plt.savefig("sin_curve.png", dpi=300, bbox_inches="tight", facecolor="white")
# 方法2:fig.savefig(保存指定画布)
fig, ax = plt.subplots()
ax.plot(x, y)
fig.savefig("sin_curve.pdf", dpi=300, bbox_inches="tight") # 保存为PDF(矢量图,无失真)
# 支持的格式:PNG、JPG、PDF、SVG、EPS等
# PNG:位图,适合屏幕显示;PDF/SVG:矢量图,适合印刷和放大
4.5 交互可视化:让图表 “活” 起来
Matplotlib 支持交互功能,结合mpl_toolkits或ipywidgets可实现缩放、拖拽、动态更新。
4.5.1 基础交互(Jupyter Notebook 中生效)
import matplotlib.pyplot as plt
import numpy as np
# 开启交互模式
plt.ion()
# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 10, 100)
line, = ax.plot(x, np.sin(x), linewidth=2) # line用于后续更新数据
ax.set_title("动态正弦曲线(按ESC退出)", fontsize=15)
ax.set_xlabel("X轴")
ax.set_ylabel("Y轴")
ax.grid(True, alpha=0.3)
# 动态更新曲线(频率逐渐增加)
for freq in np.linspace(1, 5, 50):
y = np.sin(freq * x)
line.set_ydata(y) # 更新y轴数据
ax.set_title(f"动态正弦曲线(频率={freq:.2f})", fontsize=15)
plt.draw() # 重新绘制
plt.pause(0.1) # 暂停0.1秒
# 关闭交互模式
plt.ioff()
plt.show()
4.5.2 用mpld3实现网页交互可视化
# 安装mpld3
# pip install mpld3
import matplotlib.pyplot as plt
import numpy as np
import mpld3
# 生成数据
x = np.linspace(0, 10, 100)
y = np.sin(x)
# 创建图表
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, y, linewidth=2, label="sin(x)")
ax.set_title("MPLD3交互图表")
ax.set_xlabel("X轴")
ax.set_ylabel("Y轴")
ax.legend()
ax.grid(True)
# 转换为HTML(支持缩放、平移、显示数据点坐标)
html = mpld3.fig_to_html(fig)
# 保存为HTML文件
with open("interactive_plot.html", "w") as f:
f.write(html)
# 在Jupyter Notebook中直接显示
# mpld3.display(fig)
打开生成的interactive_plot.html,可通过鼠标缩放、平移图表,hover 时显示数据点坐标。
五、实战案例:电商销售数据可视化全流程

结合前面的知识点,以 “某电商平台 2024 年第一季度销售数据” 为例,完整演示从数据准备到可视化的全流程。
5.1 数据说明
数据文件sales_q1.csv包含以下字段:
日期:订单日期(2024-01-01 至 2024-03-31)地区:用户所在地区(华北、华东、华南、西南)商品类别:电子产品、服装、食品、日用品销售额:订单金额(元)销量:订单商品数量
5.2 分析目标
- 分析每日销售额趋势;
- 对比各地区销售额占比;
- 分析不同商品类别的销量与销售额;
- 展示各地区不同商品类别的销售额分布(热力图)。
5.3 代码实现
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# ---------------------- 1. 数据准备 ----------------------
# 设置中文显示
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
# 读取数据
df = pd.read_csv("sales_q1.csv", parse_dates=["日期"])
# 数据预处理(检查缺失值、异常值)
print("数据基本信息:")
print(df.info())
print("缺失值情况:")
print(df.isnull().sum())
# 处理异常值(销售额不能为负)
df = df[df["销售额"] >= 0]
# ---------------------- 2. 每日销售额趋势 ----------------------
# 按日期分组计算每日销售额
daily_sales = df.groupby("日期")["销售额"].sum()
# 创建画布
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
fig.suptitle("2024年第一季度电商销售数据可视化分析", fontsize=18, y=0.95)
# 子图1:每日销售额趋势
ax1 = axes[0, 0]
ax1.plot(daily_sales.index, daily_sales.values, color="#FF6B6B", linewidth=2)
ax1.set_title("每日销售额趋势", fontsize=14)
ax1.set_xlabel("日期")
ax1.set_ylabel("销售额(元)")
ax1.grid(True, alpha=0.3)
# 格式化x轴日期(避免重叠)
fig.autofmt_xdate(ax=ax1)
# ---------------------- 3. 各地区销售额占比 ----------------------
# 按地区分组计算总销售额
region_sales = df.groupby("地区")["销售额"].sum().sort_values(ascending=False)
ax2 = axes[0, 1]
colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4"]
wedges, texts, autotexts = ax2.pie(
region_sales.values,
labels=region_sales.index,
colors=colors,
autopct="%1.1f%%",
startangle=90,
shadow=True
)
for autotext in autotexts:
autotext.set_color("white")
autotext.set_fontweight("bold")
ax2.set_title("各地区销售额占比", fontsize=14)
ax2.axis("equal")
# ---------------------- 4. 商品类别销量与销售额对比 ----------------------
# 按商品类别分组计算统计量
category_stats = df.groupby("商品类别").agg(
总销量=("销量", "sum"),
总销售额=("销售额", "sum")
).sort_values("总销售额", ascending=False)
ax3 = axes[1, 0]
x = np.arange(len(category_stats.index))
width = 0.35
# 绘制双柱状图
bars1 = ax3.bar(x - width/2, category_stats["总销量"], width, label="总销量", color="#FF6B6B", alpha=0.7)
bars2 = ax3.bar(x + width/2, category_stats["总销售额"]/100, width, label="总销售额(百元)", color="#4ECDC4", alpha=0.7)
# 添加数值标签
def add_labels(bars):
for bar in bars:
height = bar.get_height()
ax3.text(bar.get_x() + bar.get_width()/2, height + 5, f"{height:.0f}", ha="center", va="bottom")
add_labels(bars1)
add_labels(bars2)
ax3.set_title("商品类别销量与销售额对比", fontsize=14)
ax3.set_xlabel("商品类别")
ax3.set_ylabel("数量")
ax3.set_xticks(x)
ax3.set_xticklabels(category_stats.index, rotation=45)
ax3.legend()
ax3.grid(True, axis="y", alpha=0.3)
# ---------------------- 5. 地区-商品类别销售额热力图 ----------------------
# 构建地区-商品类别销售额矩阵
pivot_data = df.pivot_table(
values="销售额",
index="地区",
columns="商品类别",
aggfunc="sum"
)
ax4 = axes[1, 1]
im = ax4.imshow(pivot_data.values, cmap="RdBu_r", aspect="auto")
# 添加颜色条
cbar = plt.colorbar(im, ax=ax4)
cbar.set_label("销售额(元)", fontsize=10)
# 显示数值
for i in range(len(pivot_data.index)):
for j in range(len(pivot_data.columns)):
text = ax4.text(
j, i,
f"{pivot_data.iloc[i, j]:.0f}",
ha="center",
va="center",
color="white" if pivot_data.iloc[i, j] > pivot_data.values.mean() else "black"
)
ax4.set_xticks(np.arange(len(pivot_data.columns)))
ax4.set_yticks(np.arange(len(pivot_data.index)))
ax4.set_xticklabels(pivot_data.columns, rotation=45, ha="right")
ax4.set_yticklabels(pivot_data.index)
ax4.set_title("各地区商品类别销售额热力图", fontsize=14)
# 调整布局
plt.tight_layout()
plt.subplots_adjust(top=0.92)
# 保存图片
plt.savefig("sales_analysis_q1.png", dpi=300, bbox_inches="tight")
plt.show()
# ---------------------- 6. 分析结论 ----------------------
print("\n=== 2024年第一季度销售分析结论 ===")
print(f"1. 总销售额:{df['销售额'].sum():.2f}元")
print(f"2. 销售额最高地区:{region_sales.index[0]}({region_sales.iloc[0]:.2f}元,占比{region_sales.iloc[0]/region_sales.sum()*100:.1f}%)")
print(f"3. 销售额最高商品类别:{category_stats.index[0]}({category_stats['总销售额'].iloc[0]:.2f}元)")
print(f"4. 销量最高商品类别:{category_stats.sort_values('总销量', ascending=False).index[0]}({category_stats['总销量'].max():.0f}件)")
5.4 可视化结果解读
- 每日销售额趋势:1 月中旬和 3 月下旬出现销售高峰(可能与春节促销、月末冲量有关);
- 地区占比:华东地区销售额占比最高(38.5%),其次是华北地区(29.2%);
- 商品类别:电子产品销售额最高(42.1%),食品类销量最高(2.3 万件);
- 热力图:华东地区电子产品销售额最高,西南地区日用品销售额相对较低。
六、避坑指南:Matplotlib 新手常犯的 8 个错误

1. 中文显示乱码
错误:图表中中文标签显示为方块或问号。解决:手动设置字体(见 4.1.2 节),确保系统存在对应字体文件。
2. 图片保存不清晰
错误:保存的图片模糊,放大后有锯齿。解决:设置高分辨率dpi=300,保存为矢量图格式(PDF/SVG):
plt.savefig("figure.pdf", dpi=300, bbox_inches="tight")
3. 坐标轴标签重叠
错误:x 轴日期或类别标签过多,导致重叠。解决:旋转标签、调整画布大小或使用autofmt_xdate:
plt.xticks(rotation=45, ha="right") # 旋转45度,右对齐
fig.autofmt_xdate(ax=ax1) # 自动格式化日期标签
4. 子图布局混乱
错误:多个子图重叠或间距不合理。解决:使用plt.tight_layout()自动调整间距,或plt.subplots_adjust()手动调整:
plt.tight_layout() # 自动调整
plt.subplots_adjust(left=0.1, bottom=0.1, hspace=0.3, wspace=0.3) # 手动调整边距和间距
5. 忘记显示或保存图表
错误:运行代码后无图表显示,或保存后找不到文件。解决:绘制完成后必须调用plt.show()(显示)或plt.savefig()(保存),且savefig需在show之前调用:
plt.savefig("figure.png") # 先保存
plt.show() # 再显示
6. 数据类型错误导致绘图失败
错误:用字符串类型数据绘图(如df["销售额"]为字符串,导致plot失败)。解决:先转换为数值类型:
df["销售额"] = pd.to_numeric(df["销售额"], errors="coerce") # errors="coerce"将无法转换的值设为NaN
7. 饼图变形为椭圆
错误:饼图显示为椭圆,不美观。解决:设置ax.axis("equal")保证饼图为正圆形:
ax.pie(...)
ax.axis("equal")
8. 交互模式开启后无法正常显示
错误:开启plt.ion()后,图表一闪而过。解决:在循环中添加plt.pause(),结束后关闭交互模式plt.ioff():
plt.ion()
# 动态更新代码...
plt.pause(0.1)
plt.ioff()
plt.show()
七、总结:Matplotlib 学习路径与进阶建议
核心知识点回顾
- 基础操作:Figure、Axes、Axis 核心对象关系,常用图表(折线图、柱状图、散点图等)绘制;
- 样式定制:颜色、字体、主题设置,解决中文乱码、图片保存等问题;
- 进阶技巧:子图布局、文字标注、交互可视化,打造专业级图表;
- 实战应用:结合 Pandas 处理数据,完成完整的可视化分析流程。
进阶学习建议
- 结合高级库提升效率:学习 Seaborn(基于 Matplotlib,简化代码,美化样式)、Plotly(交互式可视化,适合网页展示);
- 3D 可视化:学习
mpl_toolkits.mplot3d绘制 3D 曲面图、散点图,用于科学计算数据展示; - 动画制作:使用
matplotlib.animation模块制作动态图表,用于展示数据变化过程; - 嵌入应用:将 Matplotlib 图表嵌入 Tkinter、PyQt 等 GUI 应用,开发桌面可视化工具;
- 论文级图表定制:深入学习
rcParams全局配置,定制符合期刊要求的图表样式(字体、颜色、线型)。
Matplotlib 的学习核心是 “多动手实践”—— 找一份实际数据(如个人消费记录、公开数据集),尝试用不同图表展示,逐步掌握参数调整和样式优化。从基础图表到专业可视化,Matplotlib 能伴随你从数据分析新手成长为可视化高手。
916

被折叠的 条评论
为什么被折叠?



