系列文章

Python 从入门到精通

第 30 / 36 篇

从环境安装和基础语法出发,逐步学习工程实践、自动化、数据处理与 Web 开发。

  1. 01
    Python 怎么装、怎么用
  2. 02
    变量、数字和字符串
  3. 03
    列表:把一组数据放在一起
  4. 04
    元组、集合和字典
  5. 05
    条件判断:让程序做选择
  6. 06
    循环:重复的事交给程序
  7. 07
    函数:把代码整理成可复用的块
  8. 08
    模块与包:拆分你的程序
  9. 09
    输入、输出与字符串格式化
  10. 10
    文件读写:保存程序的数据
  11. 11
    异常处理:程序出错时怎么办
  12. 12
    基础阶段练习:命令行记账本
  13. 13
    类和对象:面向对象入门
  14. 14
    继承、组合与特殊方法
  15. 15
    迭代器与生成器
  16. 16
    列表推导式与生成器表达式
  17. 17
    装饰器:给函数增加能力
  18. 18
    上下文管理器与 with
  19. 19
    类型标注与 dataclass
  20. 20
    正则表达式:从文本中找规律
  21. 21
    日期、时间与时区
  22. 22
    日志与调试
  23. 23
    虚拟环境与依赖管理
  24. 24
    测试:让修改不再提心吊胆
  25. 25
    网络请求:用 Python 调用 API
  26. 26
    网页解析与合规采集
  27. 27
    操作 Excel、CSV 与批量文件
  28. 28
    SQLite:给程序加一个数据库
  29. 29
    数据分析入门:NumPy 与 Pandas
  30. 30
    画图:把数据变得直观正在阅读
  31. 31
    Flask 入门:做一个小网站
  32. 32
    异步编程:同时处理多项任务
  33. 33
    线程、进程与并发选择
  34. 34
    性能分析与优化
  35. 35
    项目结构、配置与发布
  36. 36
    综合项目:从需求到上线

查看整个系列 →

数据算出来了,但一堆数字摆在那里,老板看不懂,你也讲不清。这时候就需要画图——一张好图胜过千言万语。这一篇用 matplotlib 学最常见的几种图表。

安装和第一张图

pip install matplotlib
import matplotlib.pyplot as plt

# 简单折线图
x = [1, 2, 3, 4, 5]
y = [2, 4, 1, 5, 3]

plt.plot(x, y)          # 画折线
plt.title("我的第一张图")
plt.xlabel("X 轴")
plt.ylabel("Y 轴")
plt.show()              # 显示(脚本运行会弹窗)
# plt.savefig("chart.png")   # 服务器/脚本环境用保存,dpi=200 更清晰

流程固定:plt.plot(...) 画图 → 加标题标签 → plt.show()savefig 输出。所有图表都这个套路。

非交互环境(服务器、脚本)记得用 plt.savefig("xx.png", dpi=200) 代替 show(),并加 plt.close() 释放。

折线图:趋势

折线图适合展示随时间的变化趋势:

import matplotlib.pyplot as plt

months = ["1月", "2月", "3月", "4月", "5月", "6月"]
visits = [1200, 1500, 1300, 1800, 2200, 2600]

plt.plot(months, visits, marker="o", color="#4d6bfe", linewidth=2)
plt.title("网站月度访问量")
plt.xlabel("月份")
plt.ylabel("访问次数")
plt.grid(True, alpha=0.3)          # 网格线,方便读数
plt.savefig("trend.png", dpi=200)
plt.close()

柱状图:对比

柱状图适合不同类别之间的对比:

import matplotlib.pyplot as plt

categories = ["吃饭", "交通", "购物", "娱乐"]
amounts = [820, 260, 640, 180]

plt.bar(categories, amounts, color=["#4d6bfe", "#7c8cf8", "#a5b4fc", "#c7d2fe"])
plt.title("月度支出分类对比")
plt.xlabel("类别")
plt.ylabel("金额(元)")
# 在柱子上标数值
for i, v in enumerate(amounts):
    plt.text(i, v + 10, str(v), ha="center")
plt.savefig("bar.png", dpi=200)
plt.close()

饼图:占比

import matplotlib.pyplot as plt

categories = ["吃饭", "交通", "购物", "娱乐"]
amounts = [820, 260, 640, 180]

plt.pie(
    amounts,
    labels=categories,
    autopct="%.1f%%",       # 显示百分比,保留 1 位小数
    startangle=90,          # 起始角度
)
plt.title("支出占比")
plt.savefig("pie.png", dpi=200)
plt.close()

散点图:相关性

散点图看两个变量的关系:

import matplotlib.pyplot as plt

# 学习时长 vs 分数(假装是数据)
hours = [1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5]
scores = [55, 60, 65, 68, 72, 75, 80, 83, 88]

plt.scatter(hours, scores, color="#4d6bfe", alpha=0.7)
plt.title("学习时长与成绩的关系")
plt.xlabel("每天学习时长(小时)")
plt.ylabel("成绩")
plt.savefig("scatter.png", dpi=200)
plt.close()

中文字体问题(必踩的坑)

matplotlib 默认字体不支持中文,直接画会出现方块乱码。解决:

import matplotlib.pyplot as plt

# 方案 1(推荐):指定支持中文的字体
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei", "Noto Sans CJK SC"]
plt.rcParams["axes.unicode_minus"] = False   # 负号正常显示

# 方案 2:查看系统有哪些中文字体
# import matplotlib.font_manager as fm
# fonts = [f.name for f in fm.fontManager.ttflist]
# print([f for f in fonts if "Hei" in f or "CJK" in f or "YaHei" in f])

# 方案 3:Linux 服务器没中文字体 → 安装或用英文标签
# apt install fonts-noto-cjk

每次画图前先设置这两行,否则中文全变方块。

多子图:一张图放多个

import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

fig, axes = plt.subplots(1, 2, figsize=(10, 4))   # 1 行 2 列

# 左边:折线
axes[0].plot([1, 2, 3], [3, 5, 4], marker="o")
axes[0].set_title("趋势")

# 右边:柱状
axes[1].bar(["A", "B", "C"], [5, 3, 7])
axes[1].set_title("对比")

plt.tight_layout()      # 自动调整间距
plt.savefig("subplots.png", dpi=200)
plt.close()

subplots(行, 列) 返回画布和子图数组,往每个子图里正常画就行。

结合 pandas:一行出图

pandas 集成了 matplotlib,DataFrame 直接 .plot():

import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

df = pd.DataFrame({
    "月份": ["1月", "2月", "3月", "4月"],
    "支出": [1200, 1500, 1300, 1800],
    "收入": [2000, 2000, 2500, 2500],
})

df.plot(x="月份", y=["支出", "收入"], kind="line", marker="o")
plt.title("收支趋势")
plt.savefig("finance.png", dpi=200)
plt.close()

# kind 可选:line 折线 / bar 柱状 / pie 饼图 / scatter 散点
df.plot(x="月份", y="支出", kind="bar")

seaborn:更好看的数据图

matplotlib 画出来偏朴素,追求美观用 seaborn(基于 matplotlib 封装):

pip install seaborn
import seaborn as sns
import matplotlib.pyplot as plt

sns.set_theme(style="whitegrid")     # 主题
tips = sns.load_dataset("tips")      # 自带示例数据

sns.boxplot(data=tips, x="day", y="total_bill")
plt.title("每天消费分布")
plt.savefig("seaborn_box.png", dpi=200)
plt.close()

seaborn 的强项:统计图表(分布、回归、热力图),配色好看,几行代码出图。

新手坑

坑 1:中文乱码。画图前先设 plt.rcParams["font.sans-serif"]

坑 2:show() 卡住。脚本/服务器环境用 savefig + close,别用 show。

坑 3:图例、标签缺失。有多个数据系列就要加 legend;坐标轴没标签,读者不知道看什么。

小结

  • 固定流程:画图 → 标题/标签 → show 或 savefig
  • 选型:趋势用折线、对比用柱状、占比用饼图、相关性用散点
  • 中文必设字体:rcParams["font.sans-serif"] + unicode_minus
  • 多图用 subplots;pandas 的 .plot() 一行出图
  • 追求美观用 seaborn;脚本环境用 savefig 别用 show

练习

  1. 用之前记账本的数据画一张”各分类支出”柱状图,标上数值
  2. 画一张”近 7 天网站访问量”折线图,带网格和标记点
  3. 思考:同样的数据,折线图、柱状图、饼图分别适合回答什么问题?”上个月哪天访问量最高”和”各分类占比”各该用哪种图?