第43课:Python|Matplotlib数据可视化各类图表绘制全教程

在这里插入图片描述


📖 开篇导读

在上一课中,我们学习了Pandas,掌握了数据清洗、筛选、分组聚合等核心技能。但仅仅处理数据还不够——人类对图形的敏感度远超纯数字表格。数据可视化就是将数据转化为图表的过程,它帮助我们更直观地理解数据背后的规律、趋势和异常。无论是商业报告、学术论文还是数据新闻,精美的图表总能让人眼前一亮。

💡 工作场景

  • 数据分析报告:从销售数据中绘制趋势图、对比图,直观展示业绩变化。
  • 机器学习:绘制损失曲线、特征分布、混淆矩阵,评估模型效果。
  • 科研实验:展示实验数据、模拟结果的折线图、散点图、误差条图。
  • 金融分析:股票K线图、收益率分布、相关性热力图。

本课将讲解Python最基础的绘图库——Matplotlib。它是Python可视化生态的基石,其他高级库(如Seaborn、Plotly)都建立在它之上。我们会学习:

  • Matplotlib的基本架构和绘图流程
  • 各类图表的绘制:折线图、散点图、柱状图、直方图、饼图、箱线图等
  • 图表元素的定制:标题、轴标签、图例、刻度、颜色、样式
  • 多子图布局
  • 图形保存和中文显示问题

学完本课,你将能够用Matplotlib绘制专业的数据图表,让数据自己说话。


🎯 学习目标

目标编号具体掌握内容对应面试/工作价值
1️⃣理解Matplotlib的绘图模型(Figure、Axes、pyplot)掌握绘图基本概念
2️⃣掌握折线图、散点图、柱状图、直方图、饼图的绘制方法不同场景选择正确图表
3️⃣学会定制图表元素(标题、标签、图例、网格、刻度、颜色)让图表更专业
4️⃣能够绘制多子图,组织多个图表在同一画布复杂报告必备
5️⃣掌握保存图表为图片文件以及处理中文乱码输出成品
6️⃣了解高级图表类型(箱线图、热力图、三维图)的简单绘制扩展视野

🔥 面试考点:“Matplotlib中plt.plotplt.scatter的区别?”“如何在一张图上画多条线?”“如何设置图例和标题?”“怎么解决中文显示问题?”


📚 知识点理论精讲

一、Matplotlib概述

1.1 什么是Matplotlib?

Matplotlib是一个用于创建静态、动画和交互式可视化的Python库。它提供了一套类似MATLAB的绘图接口,可以生成高质量的图表。

1.2 安装

pip install matplotlib

通常导入约定:

import matplotlib.pyplot as plt
import numpy as np

1.3 绘图核心概念

  • Figure:画布,包含所有图表元素。
  • Axes:坐标轴区域,每个Figure可以包含多个Axes。
  • Axis:坐标轴(X轴、Y轴),包含刻度、标签等。
  • Artist:所有可见元素的基类(文本、线条、图例等)。

二、基本绘图:折线图

折线图用于展示数据随时间或其他连续变量的变化趋势。

2.1 简单折线图

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y)
plt.show()

2.2 多条折线

x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x, y1, label='sin(x)')
plt.plot(x, y2, label='cos(x)', linestyle='--', color='red')
plt.legend()
plt.show()

2.3 常用样式参数

  • color:线条颜色('r', 'g', 'b', #FF0000等)
  • linestyle:线型('-'实线,'--'虚线,':'点线,'-.'点划线)
  • marker:数据点标记('o', '^', 's'等)
  • linewidth:线宽
plt.plot(x, y, 'o--', markersize=4, linewidth=1, color='green')

三、图表定制

3.1 标题和轴标签

plt.plot(x, y)
plt.title("正弦函数曲线")
plt.xlabel("x 值")
plt.ylabel("y 值")

3.2 图例

plt.plot(x, y1, label='sin')
plt.plot(x, y2, label='cos')
plt.legend(loc='upper right')   # 位置

3.3 坐标轴范围

plt.xlim(0, 5)
plt.ylim(-1.5, 1.5)

3.4 刻度

plt.xticks([0, np.pi, 2*np.pi], ['0', 'π', '2π'])

3.5 网格线

plt.grid(True, linestyle=':', alpha=0.7)

3.6 文本注释

plt.annotate('最大值', xy=(np.pi/2, 1), xytext=(np.pi/2, 1.2),
             arrowprops=dict(facecolor='black', shrink=0.05))

四、其他常用图表

4.1 散点图

适合展示两个变量的相关性或分布。

x = np.random.randn(100)
y = np.random.randn(100)
plt.scatter(x, y, c='blue', alpha=0.5, s=50)
plt.show()

4.2 柱状图

用于分类数据比较。

categories = ['A', 'B', 'C']
values = [15, 30, 45]
plt.bar(categories, values, color='skyblue')
plt.barh(categories, values)   # 水平柱状图

4.3 直方图

展示数据分布。

data = np.random.randn(1000)
plt.hist(data, bins=30, edgecolor='black', alpha=0.7)

4.4 饼图

展示占比。

sizes = [15, 30, 45, 10]
labels = ['A', 'B', 'C', 'D']
plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
plt.axis('equal')

4.5 箱线图

展示数据分布的五数概括(最小值、Q1、中位数、Q3、最大值)以及异常值。

data = [np.random.randn(100) for _ in range(3)]
plt.boxplot(data, labels=['组1', '组2', '组3'])

五、多子图布局

5.1 subplot() 方法

plt.subplot(2, 2, 1)  # 2行2列,第1个
plt.plot(x, y1)
plt.subplot(2, 2, 2)
plt.plot(x, y2)
# ...

5.2 subplots() 面向对象接口(推荐)

fig, axes = plt.subplots(2, 2, figsize=(10, 8))
axes[0, 0].plot(x, y1)
axes[0, 1].scatter(x, y2)
# ...

六、样式与美化

6.1 内置样式

print(plt.style.available)  # 查看可用样式
plt.style.use('ggplot')

6.2 颜色映射(colormap)

sc = plt.scatter(x, y, c=z, cmap='viridis')
plt.colorbar(sc)

6.3 保存图表

plt.savefig('figure.png', dpi=300, bbox_inches='tight')

七、中文显示问题及解决方案

Matplotlib默认字体不支持中文,显示为方框。解决方案:

plt.rcParams['font.sans-serif'] = ['SimHei']   # 使用黑体
plt.rcParams['axes.unicode_minus'] = False     # 解决负号显示异常

💻 代码案例实操

案例1:折线图——气温变化

"""
temperature_line.py
绘制一天内气温变化折线图
"""

import matplotlib.pyplot as plt
import numpy as np

# 时间点(小时)
hours = np.arange(0, 24)
# 模拟温度数据
temperatures = 15 + 5 * np.sin(np.linspace(0, 2*np.pi, 24)) + np.random.randn(24) * 0.5

plt.figure(figsize=(10, 5))
plt.plot(hours, temperatures, marker='o', linestyle='-', color='red', linewidth=2, markersize=5)
plt.title("2025年5月1日气温变化", fontsize=14)
plt.xlabel("时间 (小时)", fontsize=12)
plt.ylabel("温度 (°C)", fontsize=12)
plt.grid(True, linestyle=':', alpha=0.6)
plt.xticks(np.arange(0, 24, 2))
plt.ylim(10, 25)
plt.show()

案例2:柱状图——销售对比

"""
sales_bar.py
不同产品季度销售额柱状图
"""

import matplotlib.pyplot as plt
import numpy as np

products = ['产品A', '产品B', '产品C', '产品D']
sales_q1 = [120, 150, 80, 200]
sales_q2 = [140, 130, 100, 210]

x = np.arange(len(products))          # 标签位置
width = 0.35                           # 柱宽

fig, ax = plt.subplots()
rects1 = ax.bar(x - width/2, sales_q1, width, label='Q1')
rects2 = ax.bar(x + width/2, sales_q2, width, label='Q2')

ax.set_ylabel('销售额 (万元)')
ax.set_title('各产品季度销售额对比')
ax.set_xticks(x)
ax.set_xticklabels(products)
ax.legend()

# 添加数值标签
def autolabel(rects):
    for rect in rects:
        height = rect.get_height()
        ax.annotate(f'{height}', xy=(rect.get_x() + rect.get_width()/2, height),
                    xytext=(0, 3), textcoords="offset points", ha='center', va='bottom')

autolabel(rects1)
autolabel(rects2)
plt.show()

案例3:散点图——身高体重关系

"""
scatter_height_weight.py
身高与体重的散点图
"""

import matplotlib.pyplot as plt
import numpy as np

# 生成模拟数据
np.random.seed(42)
heights = 160 + np.random.randn(200) * 10   # 身高cm
weights = 55 + 0.5 * (heights - 160) + np.random.randn(200) * 5   # 体重kg

plt.figure(figsize=(8, 6))
plt.scatter(heights, weights, c=weights, cmap='viridis', alpha=0.6, edgecolors='black')
plt.colorbar(label='体重 (kg)')
plt.title("身高与体重关系")
plt.xlabel("身高 (cm)")
plt.ylabel("体重 (kg)")
plt.grid(True, alpha=0.3)
plt.show()

案例4:直方图——考试成绩分布

"""
score_histogram.py
学生考试成绩分布直方图
"""

import matplotlib.pyplot as plt
import numpy as np

# 随机生成1000个学生成绩(0-100)
scores = np.random.normal(75, 15, 1000)
scores = np.clip(scores, 0, 100)   # 截断到[0,100]

plt.figure(figsize=(10, 5))
plt.hist(scores, bins=20, edgecolor='black', alpha=0.7, color='skyblue')
plt.title("考试成绩分布")
plt.xlabel("分数")
plt.ylabel("人数")
plt.grid(axis='y', linestyle='--', alpha=0.5)
# 添加平均线
mean_score = np.mean(scores)
plt.axvline(mean_score, color='red', linestyle='-', linewidth=2, label=f'平均分: {mean_score:.1f}')
plt.legend()
plt.show()

案例5:饼图——市场份额

"""
pie_market_share.py
展示各品牌市场份额饼图
"""

import matplotlib.pyplot as plt

brands = ['品牌A', '品牌B', '品牌C', '品牌D', '其他']
shares = [35, 25, 20, 12, 8]
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#c2c2f0']
explode = (0.05, 0, 0, 0, 0)   # 突出第一块

plt.figure(figsize=(8, 8))
plt.pie(shares, explode=explode, labels=brands, colors=colors,
        autopct='%1.1f%%', startangle=90, shadow=True)
plt.title("智能手机市场份额")
plt.axis('equal')   # 保证饼图为圆形
plt.show()

案例6:箱线图——多组数据对比

"""
boxplot_demo.py
多组实验数据箱线图对比
"""

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data = [np.random.normal(50, 5, 100),   # 组1
        np.random.normal(55, 7, 100),   # 组2
        np.random.normal(48, 6, 100),   # 组3
        np.random.normal(52, 4, 100)]   # 组4

plt.figure(figsize=(8, 6))
bp = plt.boxplot(data, labels=['对照组', '实验组1', '实验组2', '实验组3'],
                 patch_artist=True, showmeans=True)
# 填充颜色
colors = ['lightblue', 'lightgreen', 'lightyellow', 'lightpink']
for patch, color in zip(bp['boxes'], colors):
    patch.set_facecolor(color)
plt.title("不同实验组数据分布")
plt.ylabel("测量值")
plt.grid(axis='y', linestyle='--', alpha=0.5)
plt.show()

案例7:多子图综合布局

"""
subplots_demo.py
展示四种常见图形的组合
"""

import matplotlib.pyplot as plt
import numpy as np

# 生成数据
x = np.linspace(0, 2*np.pi, 100)
y1 = np.sin(x)
y2 = np.cos(x)
data = np.random.randn(200)
categories = ['A', 'B', 'C']
values = [23, 45, 38]

fig, axes = plt.subplots(2, 2, figsize=(12, 8))
fig.suptitle("多种图形组合示例", fontsize=16)

# 子图1: 折线图
axes[0, 0].plot(x, y1, label='sin', color='b')
axes[0, 0].plot(x, y2, label='cos', color='r')
axes[0, 0].set_title("三角函数")
axes[0, 0].legend()
axes[0, 0].grid(True)

# 子图2: 柱状图
axes[0, 1].bar(categories, values, color='green')
axes[0, 1].set_title("分类数据")

# 子图3: 直方图
axes[1, 0].hist(data, bins=20, edgecolor='black', alpha=0.7)
axes[1, 0].set_title("数据分布")

# 子图4: 散点图
x_scatter = np.random.randn(50)
y_scatter = np.random.randn(50)
axes[1, 1].scatter(x_scatter, y_scatter, c='purple', alpha=0.6)
axes[1, 1].set_title("相关性")

plt.tight_layout()
plt.show()

案例8:绘制热力图(进阶)

"""
heatmap_demo.py
使用imshow绘制热力图
"""

import matplotlib.pyplot as plt
import numpy as np

# 创建一个相关性矩阵
np.random.seed(42)
data = np.random.rand(10, 10)
# 使对称
data = (data + data.T) / 2
np.fill_diagonal(data, 1)

plt.figure(figsize=(8, 6))
plt.imshow(data, cmap='RdYlBu', interpolation='nearest')
plt.colorbar(label='相关系数')
plt.title("特征相关性热力图")
plt.xticks(range(10), [f'特征{i}' for i in range(10)], rotation=45)
plt.yticks(range(10), [f'特征{i}' for i in range(10)])
plt.tight_layout()
plt.show()

⚠️ 易错点避坑总结

序号坑点描述后果解决方案
1中文字符显示为方框图表中中文乱码设置rcParams字体为支持中文的字体(如SimHei)
2忘记plt.show()图形不显示(在交互环境外)调用plt.show()
3多次调用plt.show()导致空白图图形被多次渲染通常最后调用一次即可
4混淆plt.plotplt.scatter数据点标记不符合预期根据需求选择,散点图更适合展示分布
5柱状图宽度设置不当重叠图表难以辨认调整width参数,使柱体间有间隔
6直方图bin数设置不合理掩盖或夸大分布特征使用bins='auto'或根据数据量调整
7在循环中创建大量Figure对象内存消耗大,性能差复用Figure或使用子图
8保存图形时未设置dpi或格式图片分辨率低或格式不对plt.savefig('name.png', dpi=300)
9未使用tight_layout导致标签重叠图表元素显示不全调用plt.tight_layout()
10图例位置挡住数据信息缺失设置loc参数为合适位置('upper left'等)

📝 课后实战练习题

第1题:折线图绘制

给定年份[2019,2020,2021,2022,2023]和销售额[120, 150, 180, 210, 260],绘制折线图,添加标题、坐标轴标签、网格,并显示数据点标记为圆圈。

第2题:柱状图对比

某班级月考成绩,数学平均分85,语文78,英语92。绘制柱状图,每个柱子用不同颜色,并在柱顶标注分数。

第3题:散点图与相关性

随机生成100个学生的学习时长(小时/周)(0-30)和考试成绩(0-100),绘制散点图,观察关系,并添加趋势线(可用np.polyfit)。

第4题:直方图绘制

模拟1000个正态分布随机数(均值70,标准差10),绘制直方图,设置30个bin,添加核密度估计曲线(可选)。

第5题:饼图绘制

根据以下数据绘制饼图:['苹果','香蕉','橙子','葡萄']占比[30, 25, 20, 25],突出苹果部分,显示百分比。

第6题:多子图布局

在一个Figure中创建2行2列子图,分别绘制正弦曲线、余弦曲线、正切曲线(仅-π/2到π/2)、一条随机折线。为每个子图添加标题。

第7题:箱线图异常值分析

生成三个包含异常值的数据集(每组100个数,随机加入几个特大/特小值),绘制箱线图,观察异常值。

第8题:综合应用——金融K线图(可选)

使用mplfinance库或直接使用Matplotlib绘制简化的K线图(开盘、最高、最低、收盘),可使用随机生成的数据。


🧠 知识点思维导图总结

第43课:Matplotlib可视化

基本架构

Figure画布

Axes坐标区

pyplot接口

基础图表

折线图 plot

散点图 scatter

柱状图 bar/barh

直方图 hist

饼图 pie

箱线图 boxplot

图表定制

标题/标签: title, xlabel, ylabel

图例: legend

范围: xlim, ylim

刻度: xticks, yticks

网格: grid

文本注释: annotate

多子图

subplot / subplots

tight_layout

样式美化

内置样式 style.use

颜色 colormap

颜色/线型/标记参数

中文支持

rcParams 设置字体

保存输出

savefig

面试考点

plot vs scatter

图例和标签设计

中文乱码解决

多子图布局


🔜 下节课预告

Matplotlib是基础可视化工具,但对于复杂的数据分析师还不够便捷。下一节课我们将学习Seaborn,它基于Matplotlib,提供了更高层次的接口和更美观的默认样式,非常适合统计可视化。

第44课:网络爬虫基础:Requests、BeautifulSoup网页解析实战

内容包括:

  • HTTP请求与响应原理
  • Requests库的使用
  • BeautifulSoup解析HTML
  • 实战抓取静态网页数据

网络爬虫是获取数据的重要手段,掌握它将极大扩展你的数据来源。

🌟 学习鼓励:数据可视化是将枯燥数字变为直观图形的艺术。本课内容较多,建议你边学边在Jupyter Notebook中练习。掌握Matplotlib后,你再去看Seaborn、Plotly会事半功倍。多动手,画出漂亮的图表吧!


🔗《50节课 Python 从入门到精通》系列课程导航

去订阅

🌟 感谢您耐心阅读到这里!
💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thomas.Sir

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值