Python Matplotlib 可视化全攻略:从基础图表到交互可视化,搞定数据呈现核心技能

目录

引言

一、为什么 Matplotlib 是 Python 可视化的 “基石”?

二、环境搭建与核心概念:从安装到理解 Matplotlib 的 “绘图逻辑”

2.1 安装 Matplotlib

2.2 验证安装

2.3 核心概念:搞懂 Figure、Axes、Axis 的关系

代码示例:直观理解三大对象

三、核心图表绘制:覆盖 90% 的可视化场景

3.1 折线图:展示趋势变化

基础折线图

关键参数说明

3.2 柱状图:对比类别数据

基础柱状图(单组)

分组柱状图(多组对比)

3.3 直方图:展示数据分布

关键区别:柱状图 vs 直方图

3.4 散点图:分析变量相关性

结果解读:

3.5 饼图:展示占比关系

关键参数说明

3.6 箱线图:分析数据离散程度

箱线图解读:

3.7 热力图:展示矩阵数据相关性

热力图解读:

四、进阶技巧:打造专业级可视化图表

4.1 图表样式定制:颜色、字体与主题

4.1.1 颜色定制

4.1.2 字体定制(解决中文显示乱码)

4.1.3 主题切换

4.2 子图布局:灵活排列多个图表

4.2.1 用subplots创建均匀布局

4.2.2 用gridspec创建非均匀布局

4.3 文字标注与箭头:突出关键信息

4.4 保存图片:高清无失真

4.5 交互可视化:让图表 “活” 起来

4.5.1 基础交互(Jupyter Notebook 中生效)

4.5.2 用mpld3实现网页交互可视化

五、实战案例:电商销售数据可视化全流程

5.1 数据说明

5.2 分析目标

5.3 代码实现

5.4 可视化结果解读

六、避坑指南:Matplotlib 新手常犯的 8 个错误

1. 中文显示乱码

2. 图片保存不清晰

3. 坐标轴标签重叠

4. 子图布局混乱

5. 忘记显示或保存图表

6. 数据类型错误导致绘图失败

7. 饼图变形为椭圆

8. 交互模式开启后无法正常显示

七、总结:Matplotlib 学习路径与进阶建议

核心知识点回顾

进阶学习建议


 

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 等高级库的基础:

  1. 图表类型全覆盖:支持折线图、柱状图、直方图、散点图、饼图、箱线图、3D 图等数十种图表;
  2. 定制化程度极高:从颜色、线型到坐标轴、图例,每一个细节都可手动调整,满足专业汇报、论文发表的需求;
  3. 无缝衔接数据处理库:与 NumPy 数组、Pandas DataFrame 完美兼容,直接读取数据绘图;
  4. 跨平台与多格式支持:可在 Windows、Linux、Mac 上运行,支持保存为 PNG、JPG、PDF、SVG 等多种格式;
  5. 支持交互可视化:结合 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_toolkitsipywidgets可实现缩放、拖拽、动态更新。

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 分析目标

  1. 分析每日销售额趋势;
  2. 对比各地区销售额占比;
  3. 分析不同商品类别的销量与销售额;
  4. 展示各地区不同商品类别的销售额分布(热力图)。

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. 每日销售额趋势:1 月中旬和 3 月下旬出现销售高峰(可能与春节促销、月末冲量有关);
  2. 地区占比:华东地区销售额占比最高(38.5%),其次是华北地区(29.2%);
  3. 商品类别:电子产品销售额最高(42.1%),食品类销量最高(2.3 万件);
  4. 热力图:华东地区电子产品销售额最高,西南地区日用品销售额相对较低。

六、避坑指南: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 学习路径与进阶建议

核心知识点回顾

  1. 基础操作:Figure、Axes、Axis 核心对象关系,常用图表(折线图、柱状图、散点图等)绘制;
  2. 样式定制:颜色、字体、主题设置,解决中文乱码、图片保存等问题;
  3. 进阶技巧:子图布局、文字标注、交互可视化,打造专业级图表;
  4. 实战应用:结合 Pandas 处理数据,完成完整的可视化分析流程。

进阶学习建议

  1. 结合高级库提升效率:学习 Seaborn(基于 Matplotlib,简化代码,美化样式)、Plotly(交互式可视化,适合网页展示);
  2. 3D 可视化:学习mpl_toolkits.mplot3d绘制 3D 曲面图、散点图,用于科学计算数据展示;
  3. 动画制作:使用matplotlib.animation模块制作动态图表,用于展示数据变化过程;
  4. 嵌入应用:将 Matplotlib 图表嵌入 Tkinter、PyQt 等 GUI 应用,开发桌面可视化工具;
  5. 论文级图表定制:深入学习rcParams全局配置,定制符合期刊要求的图表样式(字体、颜色、线型)。

Matplotlib 的学习核心是 “多动手实践”—— 找一份实际数据(如个人消费记录、公开数据集),尝试用不同图表展示,逐步掌握参数调整和样式优化。从基础图表到专业可视化,Matplotlib 能伴随你从数据分析新手成长为可视化高手。

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值