Python 从入门到实战(十一):数据可视化(用图表让数据 “说话”)

文章目录

    • [一、为什么需要数据可视化?先看 "数字 vs 图表" 的差距](#一、为什么需要数据可视化?先看 “数字 vs 图表” 的差距)
    • [二、可视化基础:Matplotlib 入门(基础图表绘制)](#二、可视化基础:Matplotlib 入门(基础图表绘制))
      • [1. 安装与基础配置](#1. 安装与基础配置)
        • [▶ 安装 Matplotlib](#▶ 安装 Matplotlib)
        • [▶ 基础配置(解决中文字体乱码)](#▶ 基础配置(解决中文字体乱码))
      • [2. 核心概念:Matplotlib 的 "图层" 逻辑](#2. 核心概念:Matplotlib 的 “图层” 逻辑)
      • [3. 实战 1:柱状图(对比数据大小)](#3. 实战 1:柱状图(对比数据大小))
      • [4. 实战 2:饼图(展示数据占比)](#4. 实战 2:饼图(展示数据占比))
      • [5. 实战 3:折线图(展示数据趋势)](#5. 实战 3:折线图(展示数据趋势))
    • [三、可视化进阶:Seaborn 美化与复杂图表](#三、可视化进阶:Seaborn 美化与复杂图表)
      • [1. 安装与基础配置](#1. 安装与基础配置)
        • [▶ 安装 Seaborn](#▶ 安装 Seaborn)
        • [▶ 基础配置(启用 Seaborn 样式)](#▶ 基础配置(启用 Seaborn 样式))
      • [2. 实战 1:箱线图(展示数据分布与异常值)](#2. 实战 1:箱线图(展示数据分布与异常值))
        • [示例:用 Seaborn 绘制 "各科成绩箱线图"](#示例:用 Seaborn 绘制 “各科成绩箱线图”)
        • 箱线图解读
        • 运行结果
      • [3. 实战 2:热力图(展示变量间的相关性)](#3. 实战 2:热力图(展示变量间的相关性))
        • [示例:用 Seaborn 绘制 "学生 - 课程成绩热力图"](#示例:用 Seaborn 绘制 “学生 - 课程成绩热力图”)
        • 运行结果
        • 热力图适用场景
    • 四、综合实操:学生成绩可视化报告(多图表组合)
    • [五、新手必踩的 5 个坑:避坑指南](#五、新手必踩的 5 个坑:避坑指南)
      • [坑 1:中文字体乱码(最常见)](#坑 1:中文字体乱码(最常见))
      • [坑 2:子图布局重叠(标签被截断)](#坑 2:子图布局重叠(标签被截断))
      • [坑 3:Seaborn 和 Matplotlib 样式冲突](#坑 3:Seaborn 和 Matplotlib 样式冲突)
      • [坑 4:饼图标签拥挤(类别过多)](#坑 4:饼图标签拥挤(类别过多))
      • [坑 5:保存图表时标签被截断](#坑 5:保存图表时标签被截断)
    • 六、小结与下一篇预告

欢迎回到「Python 从入门到实战」系列专栏。上一篇咱们用 Pandas 搞定了学生成绩的筛选、清洗和统计 ------ 比如算出 "数学平均分 86 分""小红是优秀学生",但这些数字总感觉不够直观:各科成绩差距有多大?成绩等级分布是否均衡?不同学生的总分对比如何?只看数字很难快速 get 到这些信息。

今天咱们要学 Python 数据可视化的 "双王牌"------MatplotlibSeaborn。它们就像数据的 "化妆师",能把枯燥的数字变成直观的图表(柱状图、折线图、饼图等),让数据的趋势、分布、对比关系一目了然。咱们会从基础的 "Matplotlib 绘图" 入手,再用 Seaborn 美化图表,最后结合上一篇的学生成绩数据,实战生成 "成绩分析可视化报告",让你的数据分析结果既有深度又有颜值。

一、为什么需要数据可视化?先看 "数字 vs 图表" 的差距

上一篇我们用 Pandas 统计了学生成绩的核心信息,比如:

  • 数学平均分 86.0,英语平均分 87.3;
  • 成绩等级分布:A 级 2 人,B 级 3 人,C 级 1 人;
  • 学生总分:小红 183 分,小明 177 分,小刚 160 分。

这些数字很准确,但不够直观 ------ 比如 "各科平均分差距",你需要手动计算差值(87.3-86.0=1.3)才能知道差距小;而用柱状图展示,一眼就能看出两科分数的高度差异:

数字统计 柱状图可视化
数学平均分 86.0,英语平均分 87.3 (示意:英语柱略高于数学柱)

再比如 "成绩等级分布",数字 "A 级 2 人、B 级 3 人、C 级 1 人" 需要在脑子里换算比例;而用饼图展示,各等级的占比一眼就能看清:

数字统计 饼图可视化
A 级 2 人、B 级 3 人、C 级 1 人 (示意:B 级占比最大,约 50%)

这就是数据可视化的核心价值:将抽象数字转化为直观图形,降低理解成本,快速传递数据洞察

二、可视化基础:Matplotlib 入门(基础图表绘制)

Matplotlib 是 Python 最核心的可视化库,几乎所有其他可视化库(包括 Seaborn)都基于它开发。它支持绘制折线图、柱状图、饼图等多种图表,灵活性极高。咱们先从 "安装" 和 "基础配置" 入手,再实战绘制常用图表。

1. 安装与基础配置

▶ 安装 Matplotlib

打开终端 / 命令提示符,输入以下命令安装:

bash

bash 复制代码
pip install matplotlib
▶ 基础配置(解决中文字体乱码)

Matplotlib 默认不支持中文字体,直接绘图会出现 "方框乱码",需要提前配置。在代码开头添加以下配置(复制即用):

python

python 复制代码
import matplotlib.pyplot as plt
import pandas as pd

# 解决中文字体乱码(Windows用SimHei,macOS用PingFang SC)
plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC']  # 中文支持
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

2. 核心概念:Matplotlib 的 "图层" 逻辑

Matplotlib 绘图像 "叠报纸",有三个核心图层,理解它们才能灵活调整图表:

  1. Figure(画布):最外层的 "大画板",所有图表都在画布上绘制;
  2. Axes(子图):画布上的 "小画板",一个画布可以有多个子图(比如一行两列的子图);
  3. 元素(标签、标题、图例):绘制在 Axes 上的细节,比如轴标签、图表标题、图例等。

简单来说:先创建 "画布(Figure)",再在画布上划分 "子图(Axes)",最后在子图上添加 "元素"。

3. 实战 1:柱状图(对比数据大小)

柱状图适合 "对比不同类别数据的大小",比如各科平均分、各学生总分。

示例:用柱状图展示 "各科平均分"

用上一篇的学生成绩数据,先通过 Pandas 计算各科平均分,再用 Matplotlib 绘制柱状图:

python

python 复制代码
import matplotlib.pyplot as plt
import pandas as pd

# 1. 配置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC']
plt.rcParams['axes.unicode_minus'] = False

# 2. 读取数据(上一篇的学生成绩数据)
df = pd.read_csv("students_data.csv", encoding="utf-8", dtype={"course_score": int})

# 3. 用Pandas计算各科平均分
course_avg = df.groupby("course_name")["course_score"].mean().round(1)
print("各科平均分:")
print(course_avg)

# 4. 绘制柱状图
# 创建画布(figsize:宽8英寸,高5英寸;dpi:分辨率)
fig, ax = plt.subplots(figsize=(8, 5), dpi=100)

# 绘制柱状图(x=课程名,y=平均分,颜色=蓝色,边框=黑色)
bars = ax.bar(
    x=course_avg.index,  # x轴:课程名
    height=course_avg.values,  # y轴:平均分
    color='skyblue',  # 柱体颜色
    edgecolor='black'  # 柱体边框颜色
)

# 5. 添加图表元素(标题、轴标签、数值标签)
ax.set_title("学生各科平均分对比", fontsize=14, pad=20)  # 标题(字号14,距离轴20像素)
ax.set_xlabel("课程名称", fontsize=12)  # x轴标签
ax.set_ylabel("平均分(分)", fontsize=12)  # y轴标签

# 在每个柱子顶部添加数值标签
for bar in bars:
    height = bar.get_height()  # 获取柱子高度(即平均分)
    ax.text(
        bar.get_x() + bar.get_width()/2,  # x坐标:柱子中心
        height + 0.5,  # y坐标:柱子顶部+0.5(避免和柱子重叠)
        str(height),  # 显示的数值
        ha='center', va='bottom', fontsize=11  # 水平居中、垂直靠下
    )

# 6. 调整y轴范围(让图表更美观)
ax.set_ylim(80, 90)  # y轴从80到90,突出差距

# 7. 保存图表(bbox_inches='tight':避免标签被截断)
plt.savefig("course_avg_bar.png", bbox_inches='tight')
# 显示图表(Jupyter Notebook中需加plt.show())
plt.show()
运行结果
  • 控制台输出

    plaintext

    plaintext 复制代码
    各科平均分:
    course_name
    数学    86.0
    英语    87.3
    Name: course_score, dtype: float64
  • 生成的图表course_avg_bar.png(蓝色柱状图,数学柱高 86.0,英语柱高 87.3,顶部有数值标签,标题和轴标签清晰)。

柱状图适用场景
  • 对比不同类别的数据(如各科成绩、各部门销售额);
  • 展示单一指标在不同维度的大小差异。

4. 实战 2:饼图(展示数据占比)

饼图适合 "展示各部分占总体的比例",比如成绩等级分布、各年龄段学生占比。

示例:用饼图展示 "成绩等级分布"

python

python 复制代码
import matplotlib.pyplot as plt
import pandas as pd

# 1. 配置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC']
plt.rcParams['axes.unicode_minus'] = False

# 2. 读取数据并计算等级分布
df = pd.read_csv("students_data.csv", encoding="utf-8", dtype={"course_score": int})
# 添加成绩等级列
df["grade"] = df["course_score"].apply(lambda x: "A级(90+)" if x >=90 else ("B级(80-89)" if x>=80 else "C级(<80)"))
# 统计各等级数量
grade_count = df["grade"].value_counts()
print("成绩等级分布:")
print(grade_count)

# 3. 绘制饼图
fig, ax = plt.subplots(figsize=(6, 6), dpi=100)

# 定义颜色(避免默认颜色单调)
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']

# 绘制饼图(autopct:显示百分比;startangle:起始角度;explode:突出某部分)
wedges, texts, autotexts = ax.pie(
    x=grade_count.values,  # 各部分数量
    labels=grade_count.index,  # 各部分标签
    autopct='%1.1f%%',  # 显示百分比(保留1位小数)
    startangle=90,  # 起始角度90度(让饼图更美观)
    colors=colors,  # 颜色列表
    explode=(0.05, 0, 0)  # 突出A级(偏移5%)
)

# 4. 美化饼图(调整文字样式)
ax.set_title("学生成绩等级分布", fontsize=14, pad=20)
# 调整百分比文字颜色和字号
for autotext in autotexts:
    autotext.set_color('white')  # 百分比文字白色
    autotext.set_fontsize(11)

# 5. 保存图表
plt.savefig("grade_pie.png", bbox_inches='tight')
plt.show()
运行结果
  • 控制台输出

    plaintext

    plaintext 复制代码
    成绩等级分布:
    grade
    B级(80-89)    3
    A级(90+)      2
    C级(<80)      1
    Name: count, dtype: int64
  • 生成的图表grade_pie.png(圆形饼图,B 级占 50.0%,A 级占 33.3%,C 级占 16.7%,A 级部分轻微突出,百分比文字白色醒目)。

饼图适用场景
  • 展示各部分占总体的比例(如市场份额、成绩等级占比);
  • 类别数量不宜过多(建议不超过 6 类,否则饼图会拥挤)。

5. 实战 3:折线图(展示数据趋势)

折线图适合 "展示数据随时间或顺序的变化趋势",比如学生总分排名、月度销售额变化。

示例:用折线图展示 "学生总分排名"

python

python 复制代码
import matplotlib.pyplot as plt
import pandas as pd

# 1. 配置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC']
plt.rcParams['axes.unicode_minus'] = False

# 2. 读取数据并计算学生总分
df = pd.read_csv("students_data.csv", encoding="utf-8", dtype={"course_score": int})
# 按姓名分组计算总分,按总分降序排序
student_total = df.groupby("name")["course_score"].sum().sort_values(ascending=False).reset_index()
print("学生总分排名:")
print(student_total)

# 3. 绘制折线图
fig, ax = plt.subplots(figsize=(8, 5), dpi=100)

# 绘制折线图(marker:添加数据点;linewidth:线宽;markersize:点大小)
ax.plot(
    student_total["name"],  # x轴:学生姓名
    student_total["course_score"],  # y轴:总分
    marker='o',  # 数据点为圆形
    linewidth=2,  # 线宽2像素
    markersize=8,  # 数据点大小8
    color='#FF6B6B'  # 线和点的颜色
)

# 4. 添加图表元素
ax.set_title("学生总分排名趋势", fontsize=14, pad=20)
ax.set_xlabel("学生姓名", fontsize=12)
ax.set_ylabel("总分(分)", fontsize=12)
ax.grid(True, alpha=0.3)  # 添加网格(透明度0.3,不影响数据)

# 在每个数据点上添加数值标签
for i, row in student_total.iterrows():
    ax.text(
        i,  # x坐标:行索引(0,1,2)
        row["course_score"] + 2,  # y坐标:总分+2(避免重叠)
        str(row["course_score"]),  # 显示的数值
        ha='center', va='bottom', fontsize=11
    )

# 5. 调整y轴范围
ax.set_ylim(150, 190)

# 6. 保存图表
plt.savefig("student_total_line.png", bbox_inches='tight')
plt.show()
运行结果
  • 控制台输出

    plaintext

    plaintext 复制代码
    学生总分排名:
      name  course_score
    0   小红           183
    1   小明           177
    2   小刚           160
  • 生成的图表student_total_line.png(红色折线,从左到右依次是小红 183、小明 177、小刚 160,数据点为圆形,顶部有数值标签,背景有浅灰色网格)。

折线图适用场景
  • 展示数据随顺序或时间的变化趋势(如排名、时间序列);
  • 对比多个数据系列的趋势(如多个学生的多科成绩变化)。

三、可视化进阶:Seaborn 美化与复杂图表

Matplotlib 功能强大,但默认样式比较朴素;Seaborn 是基于 Matplotlib 的高级库,自带美观的样式和复杂图表(如箱线图、热力图),一行代码就能让图表颜值翻倍。

1. 安装与基础配置

▶ 安装 Seaborn

bash

bash 复制代码
pip install seaborn
▶ 基础配置(启用 Seaborn 样式)

Seaborn 可以直接调用 Matplotlib 的 API,也可以用自己的样式:

python

python 复制代码
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

# 1. 启用Seaborn默认样式(美观且无需手动调颜色)
sns.set_style("whitegrid")  # 白色网格背景(适合大多数图表)
# 2. 解决中文字体(Seaborn依赖Matplotlib的字体配置)
plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC']
plt.rcParams['axes.unicode_minus'] = False

2. 实战 1:箱线图(展示数据分布与异常值)

箱线图适合 "展示数据的分布特征(中位数、四分位数、异常值)",比如各科成绩的分布范围、是否有异常高分 / 低分。

示例:用 Seaborn 绘制 "各科成绩箱线图"

python

python 复制代码
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

# 1. 配置样式和中文字体
sns.set_style("whitegrid")
plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC']
plt.rcParams['axes.unicode_minus'] = False

# 2. 读取数据
df = pd.read_csv("students_data.csv", encoding="utf-8", dtype={"course_score": int})

# 3. 绘制箱线图(Seaborn一行代码)
fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
sns.boxplot(
    x="course_name",  # x轴:课程名
    y="course_score",  # y轴:成绩
    data=df,  # 数据源
    palette="Set2",  # 颜色主题
    ax=ax  # 指定子图(和Matplotlib兼容)
)

# 4. 添加图表元素
ax.set_title("各科成绩分布箱线图", fontsize=14, pad=20)
ax.set_xlabel("课程名称", fontsize=12)
ax.set_ylabel("成绩(分)", fontsize=12)
# 调整y轴范围(0-100,符合成绩逻辑)
ax.set_ylim(0, 100)

# 5. 保存图表
plt.savefig("course_score_box.png", bbox_inches='tight')
plt.show()
箱线图解读

箱线图的每个 "箱子" 代表数据的核心分布:

  • 箱子中间的线:中位数(50% 分位数);
  • 箱子上下沿:25% 分位数和 75% 分位数(中间 50% 的数据在箱子内);
  • 箱子外的线(须):数据的合理范围(通常是 1.5 倍四分位距);
  • 须外的点:异常值(如 0 分或 100 分以外的极端值)。
运行结果

生成的course_score_box.png中,数学和英语的箱子清晰展示了各自的成绩分布 ------ 比如数学成绩的中位数略低于英语,说明英语整体成绩稍好,且两科都没有异常值。

3. 实战 2:热力图(展示变量间的相关性)

热力图适合 "展示两个分类变量的交叉统计结果",比如 "学生 - 课程 - 成绩" 的交叉表,用颜色深浅表示成绩高低。

示例:用 Seaborn 绘制 "学生 - 课程成绩热力图"

python

python 复制代码
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

# 1. 配置样式和中文字体
sns.set_style("white")  # 白色背景(热力图适合无网格)
plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC']
plt.rcParams['axes.unicode_minus'] = False

# 2. 读取数据并创建交叉表(学生-课程-成绩)
df = pd.read_csv("students_data.csv", encoding="utf-8", dtype={"course_score": int})
# 创建交叉表:行=学生,列=课程,值=成绩
score_cross = df.pivot_table(
    index="name",  # 行:学生姓名
    columns="course_name",  # 列:课程名
    values="course_score"  # 值:成绩
)
print("学生-课程成绩交叉表:")
print(score_cross)

# 3. 绘制热力图
fig, ax = plt.subplots(figsize=(6, 4), dpi=100)
sns.heatmap(
    data=score_cross,  # 数据源(交叉表)
    annot=True,  # 在热力图上显示数值
    fmt="d",  # 数值格式:整数
    cmap="YlOrRd",  # 颜色映射(黄色到红色,红色表示高分)
    cbar=True,  # 显示颜色条(右侧,解释颜色含义)
    ax=ax
)

# 4. 添加图表元素
ax.set_title("学生-课程成绩热力图", fontsize=14, pad=20)
ax.set_xlabel("课程名称", fontsize=12)
ax.set_ylabel("学生姓名", fontsize=12)

# 5. 保存图表
plt.savefig("student_course_heatmap.png", bbox_inches='tight')
plt.show()
运行结果
  • 控制台输出

    plaintext

    plaintext 复制代码
    学生-课程成绩交叉表:
    course_name  数学  英语
    name               
    小明          85  92
    小红          95  88
    小刚          78  82
  • 生成的图表student_course_heatmap.png(热力图中,小红的数学成绩 95(深红色)、小明的英语成绩 92(深红色),小刚的数学成绩 78(浅黄色),颜色越深表示成绩越高,右侧颜色条标注了成绩范围)。

热力图适用场景
  • 展示两个分类变量的交叉统计(如学生 - 课程 - 成绩、产品 - 地区 - 销量);
  • 快速识别 "高值区域" 或 "低值区域"(如哪些学生在哪些课程上表现好)。

四、综合实操:学生成绩可视化报告(多图表组合)

咱们结合前面的所有图表类型,用 Matplotlib 和 Seaborn 制作一个 "学生成绩可视化报告"------ 在一个画布上绘制 4 个子图(柱状图、饼图、箱线图、热力图),形成完整的分析报告。

完整代码

python

python 复制代码
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

def student_score_visual_report(input_file="students_data.csv", output_file="score_report.png"):
    print("===== 学生成绩可视化报告生成中 =====")
    
    # 1. 全局配置(样式、中文字体、分辨率)
    sns.set_style("whitegrid")
    plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC']
    plt.rcParams['axes.unicode_minus'] = False
    plt.rcParams['figure.dpi'] = 100  # 全局分辨率

    # 2. 读取并预处理数据
    df = pd.read_csv(input_file, encoding="utf-8", dtype={"course_score": int})
    # 添加成绩等级列
    df["grade"] = df["course_score"].apply(lambda x: "A级(90+)" if x >=90 else ("B级(80-89)" if x>=80 else "C级(<80)"))
    # 计算辅助数据
    course_avg = df.groupby("course_name")["course_score"].mean().round(1)  # 各科平均分
    grade_count = df["grade"].value_counts()  # 成绩等级分布
    student_total = df.groupby("name")["course_score"].sum().sort_values(ascending=False).reset_index()  # 学生总分
    score_cross = df.pivot_table(index="name", columns="course_name", values="course_score")  # 交叉表

    # 3. 创建画布和4个子图(2行2列)
    fig, axes = plt.subplots(2, 2, figsize=(12, 10))  # 2行2列,总宽12,高10
    fig.suptitle("学生成绩可视化分析报告", fontsize=16, y=0.98)  # 总标题(y=0.98:靠近顶部)

    # 子图1:各科平均分柱状图(第1行第1列)
    ax1 = axes[0, 0]
    bars = ax1.bar(course_avg.index, course_avg.values, color='skyblue', edgecolor='black')
    ax1.set_title("各科平均分对比", fontsize=12)
    ax1.set_xlabel("课程名称")
    ax1.set_ylabel("平均分(分)")
    ax1.set_ylim(80, 90)
    # 添加数值标签
    for bar in bars:
        height = bar.get_height()
        ax1.text(bar.get_x()+bar.get_width()/2, height+0.5, str(height), ha='center', va='bottom')

    # 子图2:成绩等级分布饼图(第1行第2列)
    ax2 = axes[0, 1]
    colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
    wedges, texts, autotexts = ax2.pie(grade_count.values, labels=grade_count.index, autopct='%1.1f%%', 
                                       startangle=90, colors=colors, explode=(0.05, 0, 0))
    ax2.set_title("成绩等级分布", fontsize=12)
    # 美化百分比文字
    for autotext in autotexts:
        autotext.set_color('white')
        autotext.set_fontsize(10)

    # 子图3:各科成绩箱线图(第2行第1列)
    ax3 = axes[1, 0]
    sns.boxplot(x="course_name", y="course_score", data=df, palette="Set2", ax=ax3)
    ax3.set_title("各科成绩分布", fontsize=12)
    ax3.set_xlabel("课程名称")
    ax3.set_ylabel("成绩(分)")
    ax3.set_ylim(0, 100)

    # 子图4:学生-课程成绩热力图(第2行第2列)
    ax4 = axes[1, 1]
    sns.heatmap(score_cross, annot=True, fmt="d", cmap="YlOrRd", cbar=True, ax=ax4)
    ax4.set_title("学生-课程成绩热力图", fontsize=12)
    ax4.set_xlabel("课程名称")
    ax4.set_ylabel("学生姓名")

    # 4. 调整子图间距(避免标签重叠)
    plt.tight_layout()  # 自动调整间距
    plt.subplots_adjust(top=0.93)  # 预留总标题空间

    # 5. 保存报告
    plt.savefig(output_file, bbox_inches='tight', dpi=150)  # 高分辨率保存(150dpi)
    plt.close()  # 关闭画布,释放内存

    print(f"✅ 可视化报告已保存到:{output_file}")
    print("===== 报告生成完成 =====")

# 运行报告生成函数
if __name__ == "__main__":
    student_score_visual_report()

关键功能说明

  1. 多子图布局 :用plt.subplots(2, 2)创建 2 行 2 列的子图,通过axes[行索引, 列索引]访问每个子图;
  2. 全局样式:统一配置 Seaborn 样式和中文字体,确保所有子图风格一致;
  3. 间距调整plt.tight_layout()自动调整子图间距,plt.subplots_adjust(top=0.93)为总标题预留空间,避免重叠;
  4. 高分辨率保存 :保存时设置dpi=150,让图表更清晰,适合打印或插入文档。

运行结果

生成的score_report.png包含 4 个子图,从不同维度展示学生成绩:

  • 左上:各科平均分对比(英语略高);
  • 右上:成绩等级分布(B 级占比最高);
  • 左下:各科成绩分布(无异常值);
  • 右下:学生 - 课程成绩热力图(小红数学最好,小明英语最好)。

五、新手必踩的 5 个坑:避坑指南

数据可视化看似简单,但新手容易在 "字体""布局""样式" 上踩坑,导致图表不美观或报错。咱们总结 5 个高频问题:

坑 1:中文字体乱码(最常见)

python

python 复制代码
# 错误示例:未配置中文字体,图表中中文显示为方框
import matplotlib.pyplot as plt
plt.plot(["小明", "小红"], [177, 183])
plt.title("学生总分")
plt.show()  # 标题"学生总分"显示为方框

解决:在代码开头添加字体配置:

python

python 复制代码
plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC']
plt.rcParams['axes.unicode_minus'] = False

坑 2:子图布局重叠(标签被截断)

python

python 复制代码
# 错误示例:多子图未调整间距,标签重叠
fig, axes = plt.subplots(2, 2, figsize=(8, 6))
# 绘制4个子图后,标签重叠
plt.savefig("overlap.png")  # 部分标签被截断

解决 :添加plt.tight_layout()自动调整间距,或plt.subplots_adjust()手动调整:

python

python 复制代码
plt.tight_layout()  # 自动调整
# 或手动调整上下左右间距
plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)

坑 3:Seaborn 和 Matplotlib 样式冲突

python

python 复制代码
# 错误示例:先画Matplotlib图表,再启用Seaborn样式,样式不生效
import seaborn as sns
import matplotlib.pyplot as plt

# 先画图表,再启用样式
plt.plot([1,2,3], [4,5,6])
sns.set_style("whitegrid")  # 样式不生效
plt.show()

解决:先启用 Seaborn 样式,再绘制图表:

python

python 复制代码
sns.set_style("whitegrid")  # 先启用样式
plt.plot([1,2,3], [4,5,6])  # 再画图表
plt.show()

坑 4:饼图标签拥挤(类别过多)

python

python 复制代码
# 错误示例:饼图类别超过6个,标签拥挤
grade_count = pd.Series([1,2,3,4,5,6,7], index=[f"等级{i}" for i in range(7)])
plt.pie(grade_count.values, labels=grade_count.index)
plt.show()  # 标签重叠,无法看清

解决 :减少类别数量(合并相似类别),或用labeldistance调整标签距离:

python

python 复制代码
plt.pie(grade_count.values, labels=grade_count.index, labeldistance=1.2)  # 标签远离饼图

坑 5:保存图表时标签被截断

python

python 复制代码
# 错误示例:未加bbox_inches='tight',标题被截断
plt.plot([1,2,3], [4,5,6])
plt.title("这是一个很长的标题,用来测试保存时是否被截断")
plt.savefig("cutoff.png")  # 标题右侧被截断

解决 :保存时添加bbox_inches='tight'

python

python 复制代码
plt.savefig("cutoff.png", bbox_inches='tight')  # 自动适配所有标签

六、小结与下一篇预告

这篇你学到了什么?

  1. 可视化基础:理解数据可视化的价值,掌握 Matplotlib 的 "画布 - 子图 - 元素" 逻辑;
  2. Matplotlib 实战:绘制柱状图(对比)、饼图(占比)、折线图(趋势),添加标题、标签、数值等元素;
  3. Seaborn 进阶:用 Seaborn 美化图表,绘制箱线图(分布)、热力图(交叉统计),一行代码提升颜值;
  4. 综合报告:制作多子图的可视化报告,调整布局和分辨率,生成完整分析结果;
  5. 避坑指南:解决中文字体、子图重叠、样式冲突等常见问题。

下一篇预告

今天的可视化让数据 "说话",但前面的所有知识都是 "单机运行"------ 如果想让你的学生管理系统被多人访问(比如老师和学生都能查看成绩),就需要开发 Web 应用。下一篇咱们会学 Python 的 Web 框架Flask,结合前面的 Pandas 和可视化知识,开发一个 "在线学生成绩管理系统",支持浏览器访问、数据查询和图表展示,让你的项目从 "本地工具" 升级为 "Web 应用"。

如果这篇内容帮你掌握了数据可视化,欢迎在评论区分享你的 "可视化作品"(比如用图表分析你的消费数据),咱们一起交流进步~

相关推荐
Pyeako2 小时前
机器学习--逻辑回归相关案例
人工智能·python·机器学习·逻辑回归·下采样·交叉验证·过采样
gf13211112 小时前
python_制作视频开头_根据短句字长占总字幕的长度比例拆分
windows·python·音视频
StudyWinter2 小时前
【c++】thread总结
开发语言·c++·算法
摸鱼仙人~2 小时前
angent调用的tools数目增多的时候,错误率显著增加如何解决
python
NicoNicoleNi2 小时前
Anaconda安装和环境配置实践记录
python·conda
小鸡脚来咯2 小时前
java泛型详解
java·开发语言
爱笑的眼睛112 小时前
JAX 函数变换:超越传统自动微分的编程范式革命
java·人工智能·python·ai
liuyouzhang2 小时前
备忘-国密解密算法
java·开发语言
北冥有一鲲2 小时前
LangChain.js:Tool、Memory 与 Agent 的深度解析与实战
开发语言·javascript·langchain