Python matplotlib详解:从入门到精通,数据可视化利器

在数据分析和机器学习中,"可视化"是理解数据、呈现结果的核心环节。matplotlib作为Python最经典的可视化库,以其灵活的绘图能力和丰富的图表类型,成为数据从业者的必备工具。无论是简单的折线图、散点图,还是复杂的热图、3D图表,matplotlib都能轻松实现。本文将从基础概念→核心绘图函数→自定义美化→实战案例,手把手带你掌握matplotlib,让你的数据"说话"更直观。

一、什么是matplotlib?为什么需要它?

matplotlib是Python的一个2D绘图库,诞生于2003年,设计初衷是"让Python拥有像MATLAB一样的绘图能力"。它支持几乎所有常见的图表类型,且高度可定制------从颜色、字体到坐标轴刻度,都能精细调整。

为什么matplotlib是数据可视化首选?

  • 功能全面:支持折线图、散点图、柱状图、直方图、饼图、热图等数十种图表;
  • 高度定制:从全局样式到局部细节(如点的大小、线的粗细),均可灵活调整;
  • 兼容性强:与NumPy、Pandas无缝配合(可直接传入数组或DataFrame绘图);
  • 输出多样:可保存为PNG、PDF、SVG等多种格式,适配报告、论文、网页等场景。

举个例子:用Pandas分析完一组销售数据后,只需一行代码调用plot()(底层基于matplotlib),就能生成趋势图,直观发现数据规律。

二、安装与导入:5分钟准备工作

1. 安装matplotlib

matplotlib不是Python标准库,需用pip安装:

bash 复制代码
pip install matplotlib  # 基础安装,支持所有核心功能

2. 导入matplotlib

惯例将matplotlib.pyplot简写为plt(行业通用约定,简化代码):

python 复制代码
import matplotlib.pyplot as plt  # 导入绘图核心模块
import numpy as np  # 配合生成示例数据

三、核心概念:Figure与Axes(画布与子图)

matplotlib的绘图逻辑基于两个核心对象:Figure(画布)Axes(子图/轴),理解它们是用好matplotlib的关键。

  • Figure:整个绘图区域的"画布",可以看作一个窗口或页面,所有图表都绘制在Figure上。
  • Axes:画布上的"子图",一个Figure可以包含多个Axes(比如一行两列的图表有2个Axes)。每个Axes有自己的坐标轴(x轴、y轴)、标题、图例等。

(图片来源:matplotlib官方文档)

快速创建画布与子图

python 复制代码
# 方法1:先创建画布,再添加子图
fig = plt.figure(figsize=(8, 4))  # 创建画布,指定大小(宽8英寸,高4英寸)
ax = fig.add_subplot(1, 1, 1)  # 添加1行1列的第1个子图(整个画布仅1个图)

# 方法2:同时创建画布和子图(推荐,更简洁)
fig, ax = plt.subplots(figsize=(8, 4))  # 等价于上面的代码

# 绘图:在子图上画一条线
ax.plot([1, 2, 3, 4], [1, 4, 9, 16])  # x=[1,2,3,4], y=[1,4,9,16]

# 显示图表(必须调用,否则不显示)
plt.show()

四、基础图表绘制:从简单到复杂

matplotlib支持数十种图表,以下是最常用的5种,覆盖80%的可视化场景。

1. 折线图(plot):展示趋势变化

折线图适合展示数据随时间或有序变量的变化趋势(如股票价格、温度变化)。

python 复制代码
# 生成示例数据(x:时间,y:数值)
x = np.linspace(0, 10, 100)  # 0到10的100个均匀点
y1 = np.sin(x)  # 正弦曲线
y2 = np.cos(x)  # 余弦曲线

# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 5))

# 绘制折线图
ax.plot(x, y1, label="sin(x)", color="blue", linewidth=2, linestyle="-")  # 实线
ax.plot(x, y2, label="cos(x)", color="red", linewidth=1.5, linestyle="--")  # 虚线

# 添加标题和标签
ax.set_title("正弦函数与余弦函数曲线", fontsize=15)  # 标题
ax.set_xlabel("x值", fontsize=12)  # x轴标签
ax.set_ylabel("y值", fontsize=12)  # y轴标签

# 添加图例(显示label)
ax.legend(fontsize=10)

# 添加网格线(便于读数)
ax.grid(alpha=0.3)  # alpha控制透明度

# 显示图表
plt.show()

关键参数说明

  • label:图例名称(需配合ax.legend()显示);
  • color:线的颜色(支持英文名称如"red"、十六进制如"#FF0000");
  • linewidth:线的粗细;
  • linestyle:线的样式("-"实线、"--"虚线、":"点线等)。

2. 散点图(scatter):展示变量关系

散点图用于观察两个变量之间的相关性(如身高与体重、学习时间与成绩)。

python 复制代码
# 生成示例数据(100个随机点)
np.random.seed(42)  # 固定随机种子,结果可复现
x = np.random.randn(100)  # 均值0、标准差1的随机数(x变量)
y = 2 * x + np.random.randn(100) * 0.5  # y与x近似线性相关,加噪声

# 创建画布和子图
fig, ax = plt.subplots(figsize=(8, 6))

# 绘制散点图
scatter = ax.scatter(
    x, y, 
    c=y,  # 点的颜色由y值决定(颜色映射)
    cmap="viridis",  # 颜色映射方案(内置多种,如"coolwarm"、"rainbow")
    s=50,  # 点的大小
    alpha=0.7,  # 透明度(0-1)
    edgecolors="black"  # 点的边缘颜色
)

# 添加颜色条(解释颜色含义)
cbar = plt.colorbar(scatter)
cbar.set_label("y值", fontsize=10)

# 添加标题和标签
ax.set_title("x与y的散点图(带颜色映射)", fontsize=15)
ax.set_xlabel("x变量", fontsize=12)
ax.set_ylabel("y变量", fontsize=12)

# 添加网格
ax.grid(alpha=0.3)

plt.show()

关键参数说明

  • c:点的颜色(可传入数组,实现按值着色);
  • cmap:颜色映射表(让颜色随值变化更有层次感);
  • s:点的大小(可传入数组,实现不同点不同大小);
  • alpha:透明度(避免点重叠时看不清)。

3. 柱状图(bar/barh):对比分类数据

柱状图用于对比不同类别的数值(如各产品销量、各班级平均分),bar是垂直柱状图,barh是水平柱状图。

python 复制代码
# 示例数据(类别与数值)
categories = ["产品A", "产品B", "产品C", "产品D"]
values = [35, 52, 28, 41]  # 销量

# 创建画布和子图
fig, ax = plt.subplots(figsize=(8, 5))

# 绘制垂直柱状图
ax.bar(
    categories, values,
    color=["#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A"],  # 每个柱子不同颜色
    width=0.6,  # 柱子宽度
    edgecolor="black"  # 柱子边缘颜色
)

# 在柱子顶部添加数值标签
for i, v in enumerate(values):
    ax.text(i, v + 1, str(v), ha="center", fontsize=10)  # ha="center"水平居中

# 添加标题和标签
ax.set_title("各产品季度销量对比", fontsize=15)
ax.set_xlabel("产品类别", fontsize=12)
ax.set_ylabel("销量(件)", fontsize=12)

# 设置y轴范围(让顶部标签不溢出)
ax.set_ylim(0, max(values) + 10)

plt.show()

水平柱状图(barh)示例

python 复制代码
# 只需将bar改为barh,x和y互换
ax.barh(categories, values)  # 水平柱状图,类别在y轴,数值在x轴

4. 直方图(hist):展示数据分布

直方图用于展示单变量的分布情况(如身高分布、成绩分布),与柱状图的区别是:直方图的x轴是连续区间( bins ),展示"在某个区间内有多少数据"。

python 复制代码
# 生成示例数据(1000个符合正态分布的随机数)
np.random.seed(42)
data = np.random.normal(loc=50, scale=10, size=1000)  # 均值50,标准差10

# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 5))

# 绘制直方图
n, bins, patches = ax.hist(
    data,
    bins=20,  # 区间数量(分20个桶)
    density=True,  # 是否归一化(显示概率密度)
    color="#6495ED",
    alpha=0.7,
    edgecolor="black"
)

# 添加正态分布曲线(更直观展示分布)
from scipy.stats import norm  # 需安装scipy:pip install scipy
mu, sigma = norm.fit(data)  # 拟合均值和标准差
x = np.linspace(bins[0], bins[-1], 100)
ax.plot(x, norm.pdf(x, mu, sigma), "r--", linewidth=2)  # 概率密度曲线

# 添加标题和标签
ax.set_title("数据分布直方图(正态分布)", fontsize=15)
ax.set_xlabel("数值", fontsize=12)
ax.set_ylabel("概率密度", fontsize=12)
ax.grid(alpha=0.3, axis="y")  # 只显示y轴网格

plt.show()

关键参数说明

  • bins:区间数量(值越大,分桶越细,细节越清晰但可能噪声多);
  • density:若为True,y轴显示概率密度(总面积为1),否则显示频数。

5. 饼图(pie):展示占比关系

饼图用于展示各部分占总体的比例(如市场份额、投票结果),适合类别较少的场景(建议不超过5类,否则可读性差)。

python 复制代码
# 示例数据(各部分占比)
labels = ["直接访问", "搜索引擎", "社交媒体", "广告推广"]
sizes = [30, 40, 20, 10]  # 总和100
explode = [0, 0.1, 0, 0]  # 突出显示第2部分(搜索引擎)

# 创建画布和子图
fig, ax = plt.subplots(figsize=(7, 7))  # 饼图建议用正方形画布(避免变形)

# 绘制饼图
ax.pie(
    sizes,
    explode=explode,  # 部分扇形偏离中心
    labels=labels,  # 类别标签
    autopct="%1.1f%%",  # 显示百分比(保留1位小数)
    shadow=True,  # 添加阴影(增强立体感)
    startangle=90,  # 起始角度(90度为从正上方开始)
    colors=["#FF9999", "#66B2FF", "#99FF99", "#FFCC99"]
)

# 保证饼图是正圆形(否则可能椭圆)
ax.axis("equal")

# 添加标题
ax.set_title("网站访问来源占比", fontsize=15)

plt.show()

关键参数说明

  • explode:控制各扇形是否偏离中心(突出重要部分);
  • autopct:格式化百分比显示(如"%d%%"整数百分比);
  • startangle:起始角度(0度从x轴正方向开始,90度从y轴正方向开始)。

五、自定义图表:让你的图更"专业"

默认图表往往不够美观,matplotlib支持从字体、颜色到坐标轴的全方位定制,以下是核心技巧。

1. 解决中文显示问题(关键!)

matplotlib默认不支持中文字体,直接显示中文会变成方框或乱码,需手动设置字体:

python 复制代码
# 方法1:全局设置(一次设置,所有图表生效)
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]  # 支持中文的字体
plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题

# 方法2:局部设置(仅当前图表生效,更灵活)
fig, ax = plt.subplots()
ax.set_title("中文标题", fontproperties="SimHei", fontsize=15)  # 指定字体

常用中文字体

  • SimHei(黑体,Windows系统);
  • WenQuanYi Micro Hei(文泉驿微米黑,Linux系统);
  • Heiti TC(黑体,Mac系统)。

2. 调整坐标轴范围与刻度

python 复制代码
x = np.linspace(0, 10, 100)
y = np.sin(x)

fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, y)

# 设置坐标轴范围
ax.set_xlim(2, 8)  # x轴只显示2到8
ax.set_ylim(-1.2, 1.2)  # y轴范围扩大,避免线条贴边

# 自定义刻度(替换默认刻度)
ax.set_xticks([2, 4, 6, 8])  # x轴显示的刻度点
ax.set_xticklabels(["2π/5", "4π/5", "6π/5", "8π/5"], rotation=30)  # 刻度标签(旋转30度避免重叠)
ax.set_yticks([-1, 0, 1])  # y轴刻度点

plt.show()

3. 保存图表(高清无水印)

plt.savefig()保存图表,建议用dpi参数提高分辨率(默认100,300适合印刷):

python 复制代码
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 1])
ax.set_title("示例图表")

# 保存为PNG(高清)
plt.savefig("my_plot.png", dpi=300, bbox_inches="tight")  # bbox_inches="tight"去除多余空白
# 也可保存为PDF(矢量图,放大不失真)
# plt.savefig("my_plot.pdf", bbox_inches="tight")

plt.show()  # 注意:savefig必须在show()之前,否则保存空白图!

六、多子图布局:对比多个图表

当需要同时展示多个相关图表(如不同产品的销量趋势),可使用子图布局。

1. 规则网格布局(subplots)

plt.subplots(nrows, ncols)创建n行n列的子图网格:

python 复制代码
# 创建2行2列的子图(共4个子图)
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 10))  # axes是子图数组

# 第1行第1列子图(折线图)
x = np.linspace(0, 10, 100)
axes[0, 0].plot(x, np.sin(x))
axes[0, 0].set_title("正弦曲线")

# 第1行第2列子图(散点图)
np.random.seed(42)
axes[0, 1].scatter(np.random.randn(50), np.random.randn(50))
axes[0, 1].set_title("随机散点")

# 第2行第1列子图(柱状图)
axes[1, 0].bar(["A", "B", "C"], [3, 7, 2])
axes[1, 0].set_title("柱状图示例")

# 第2行第2列子图(饼图)
axes[1, 1].pie([15, 30, 45, 10], labels=["a", "b", "c", "d"])
axes[1, 1].set_title("饼图示例")
axes[1, 1].axis("equal")  # 饼图正圆

# 调整子图间距(避免标题/标签重叠)
plt.tight_layout()  # 自动调整间距
# 也可手动调整:plt.subplots_adjust(wspace=0.3, hspace=0.5)  # 水平/垂直间距

plt.show()

2. 不规则布局(gridspec)

对于非均匀分布的子图(如一个大图+几个小图),用plt.GridSpec更灵活:

python 复制代码
# 创建2行2列的网格,但第1行合并为1个大图
gs = plt.GridSpec(2, 2, figure=plt.figure(figsize=(12, 8)))

# 第1行:合并两列(大图)
ax1 = plt.subplot(gs[0, :])  # 第0行,所有列
ax1.plot(np.linspace(0, 10, 100), np.sin(np.linspace(0, 10, 100)))
ax1.set_title("大图:正弦曲线")

# 第2行第1列(小图1)
ax2 = plt.subplot(gs[1, 0])
ax2.hist(np.random.randn(1000), bins=20)
ax2.set_title("小图1:直方图")

# 第2行第2列(小图2)
ax3 = plt.subplot(gs[1, 1])
ax3.pie([30, 70], labels=["男", "女"])
ax3.set_title("小图2:饼图")
ax3.axis("equal")

plt.tight_layout()
plt.show()

七、实战案例:鸢尾花数据集可视化

用经典的鸢尾花数据集(包含3类鸢尾花的4个特征),展示matplotlib的综合应用:

python 复制代码
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import load_iris  # 从sklearn加载数据集

# 1. 加载数据
iris = load_iris()
X = iris.data  # 特征数据(4列:花萼长度、花萼宽度、花瓣长度、花瓣宽度)
y = iris.target  # 标签(0、1、2对应3类鸢尾花)
feature_names = iris.feature_names  # 特征名称

# 2. 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei"]
plt.rcParams["axes.unicode_minus"] = False

# 3. 创建4个子图(2x2),展示特征两两关系
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.flatten()  # 转为1D数组,便于循环

# 特征对(0-1, 0-2, 0-3, 1-2)
pairs = [(0, 1), (0, 2), (0, 3), (1, 2)]

for i, (x_idx, y_idx) in enumerate(pairs):
    # 绘制散点图(按类别着色)
    for target, color in zip([0, 1, 2], ["r", "g", "b"]):
        mask = (y == target)
        axes[i].scatter(
            X[mask, x_idx], X[mask, y_idx],
            c=color, label=iris.target_names[target],
            alpha=0.7
        )
    # 设置标题和标签
    axes[i].set_title(f"{feature_names[x_idx]} vs {feature_names[y_idx]}")
    axes[i].set_xlabel(feature_names[x_idx])
    axes[i].set_ylabel(feature_names[y_idx])
    axes[i].legend()

plt.tight_layout()
plt.show()

可视化效果:4个子图分别展示了鸢尾花不同特征之间的关系,通过颜色区分类别,可直观发现"花瓣长度"和"花瓣宽度"能很好地区分三类鸢尾花------这也是后续机器学习分类的重要依据。

八、避坑指南:matplotlib常见错误及解决

1. 中文显示为方框/乱码

问题 :图表中中文变成方框或乱码。
解决:设置支持中文的字体(见前文"解决中文显示问题")。

2. 保存的图片是空白

问题plt.savefig()保存的图片是空白。
原因savefig()plt.show()之后调用,show()会清空画布。
解决先调用savefig(),再调用show()

python 复制代码
plt.plot([1, 2, 3])
plt.savefig("plot.png")  # 先保存
plt.show()  # 再显示

3. 子图标题/标签重叠

问题 :多个子图的标题、坐标轴标签重叠。
解决 :用plt.tight_layout()自动调整间距,或plt.subplots_adjust(wspace=0.3, hspace=0.5)手动调整。

4. 饼图显示为椭圆

问题 :饼图看起来是椭圆而非正圆。
解决 :添加ax.axis("equal")保证x轴和y轴比例一致。

5. 图表大小不合适

问题 :图表太小或太大,元素显示不全。
解决 :创建画布时用figsize=(宽, 高)指定大小(单位为英寸),如plt.subplots(figsize=(10, 6))

九、总结:matplotlib是数据可视化的基石

matplotlib的核心价值在于**"灵活可控"**------从最简单的折线图到复杂的多子图组合,从默认样式到高度定制化的出版级图表,它都能满足需求。掌握matplotlib后,你可以:

  • 快速探索数据规律(通过散点图看相关性、直方图看分布);
  • 清晰呈现分析结果(用柱状图对比、折线图展示趋势);
  • 生成论文、报告所需的高清图表(支持矢量格式,放大不失真)。

学习建议:

  1. 先模仿再创新 :从官方示例(matplotlib示例库)开始,修改参数理解其作用;
  2. 结合实际数据练习:用自己的数据集(如CSV文件)绘制不同图表,对比哪种最能体现数据特点;
  3. 善用样式预设 :matplotlib提供多种预设样式(如plt.style.use("seaborn-v0_8")),可快速美化图表;
  4. 进阶学习seaborn:seaborn是基于matplotlib的高级库,代码更简洁,默认样式更美观,学会matplotlib后可快速上手。

数据可视化的核心是"清晰传达信息",工具是手段而非目的。选择合适的图表类型,配合简洁的样式,才能让你的数据故事更有说服力。

相关推荐
程序员大雄学编程3 小时前
用Python来学微积分22-费马定理
人工智能·python·数学·微积分
deephub3 小时前
sklearn 特征选择实战:用 RFE 找到最优特征组合
人工智能·python·机器学习·sklearn·特征选择
程序员杰哥3 小时前
外包干了三年,快要废了。。。
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
咩?3 小时前
10.27-yolov5代码
人工智能·python·深度学习
gfdgd xi4 小时前
好消息:KMRE 安卓模拟器现可在Debian/GXDE使用
android·python·架构·bug·deepin·龙芯
烟锁池塘柳04 小时前
【已解决】解决CondaVerificationError:PyTorch安装包损坏问题
人工智能·pytorch·python
程序员爱钓鱼4 小时前
Python编程实战 | 函数与模块化编程 - 第三方库的安装与管理(pip使用)
后端·python·ipython
国服第二切图仔4 小时前
Rust开发之Result枚举与?运算符简化错误传播
开发语言·python·rust
程序员爱钓鱼4 小时前
Python编程实战 | 面向对象与进阶语法-类与对象的概念
后端·python·ipython