
文章目录
📖 开篇导读
在上一课中,我们学习了Pandas,掌握了数据清洗、筛选、分组聚合等核心技能。但仅仅处理数据还不够——人类对图形的敏感度远超纯数字表格。数据可视化就是将数据转化为图表的过程,它帮助我们更直观地理解数据背后的规律、趋势和异常。无论是商业报告、学术论文还是数据新闻,精美的图表总能让人眼前一亮。
💡 工作场景:
- 数据分析报告:从销售数据中绘制趋势图、对比图,直观展示业绩变化。
- 机器学习:绘制损失曲线、特征分布、混淆矩阵,评估模型效果。
- 科研实验:展示实验数据、模拟结果的折线图、散点图、误差条图。
- 金融分析:股票K线图、收益率分布、相关性热力图。
本课将讲解Python最基础的绘图库——Matplotlib。它是Python可视化生态的基石,其他高级库(如Seaborn、Plotly)都建立在它之上。我们会学习:
- Matplotlib的基本架构和绘图流程
- 各类图表的绘制:折线图、散点图、柱状图、直方图、饼图、箱线图等
- 图表元素的定制:标题、轴标签、图例、刻度、颜色、样式
- 多子图布局
- 图形保存和中文显示问题
学完本课,你将能够用Matplotlib绘制专业的数据图表,让数据自己说话。
🎯 学习目标
| 目标编号 | 具体掌握内容 | 对应面试/工作价值 |
|---|---|---|
| 1️⃣ | 理解Matplotlib的绘图模型(Figure、Axes、pyplot) | 掌握绘图基本概念 |
| 2️⃣ | 掌握折线图、散点图、柱状图、直方图、饼图的绘制方法 | 不同场景选择正确图表 |
| 3️⃣ | 学会定制图表元素(标题、标签、图例、网格、刻度、颜色) | 让图表更专业 |
| 4️⃣ | 能够绘制多子图,组织多个图表在同一画布 | 复杂报告必备 |
| 5️⃣ | 掌握保存图表为图片文件以及处理中文乱码 | 输出成品 |
| 6️⃣ | 了解高级图表类型(箱线图、热力图、三维图)的简单绘制 | 扩展视野 |
🔥 面试考点:“Matplotlib中
plt.plot和plt.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.plot和plt.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线图(开盘、最高、最低、收盘),可使用随机生成的数据。
🧠 知识点思维导图总结
🔜 下节课预告
Matplotlib是基础可视化工具,但对于复杂的数据分析师还不够便捷。下一节课我们将学习Seaborn,它基于Matplotlib,提供了更高层次的接口和更美观的默认样式,非常适合统计可视化。
第44课:网络爬虫基础:Requests、BeautifulSoup网页解析实战
内容包括:
- HTTP请求与响应原理
- Requests库的使用
- BeautifulSoup解析HTML
- 实战抓取静态网页数据
网络爬虫是获取数据的重要手段,掌握它将极大扩展你的数据来源。
🌟 学习鼓励:数据可视化是将枯燥数字变为直观图形的艺术。本课内容较多,建议你边学边在Jupyter Notebook中练习。掌握Matplotlib后,你再去看Seaborn、Plotly会事半功倍。多动手,画出漂亮的图表吧!
🔗《50节课 Python 从入门到精通》系列课程导航
🌟 感谢您耐心阅读到这里!
💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~

244

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



