折线图:看趋势plt.plot()
一周气温变化 —— 最基础、也最常用的图表,按顺序连接数据点
图 2-1 一周最高 / 最低气温折线图
1# 折线图:一周气温变化2import matplotlib.pyplot as plt3 4plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei'] # 正常显示中文5plt.rcParams['axes.unicode_minus'] = False # 正常显示负号6 7days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']8high = [26, 28, 31, 29, 27, 30, 32] # 最高气温9low = [18, 19, 22, 21, 19, 20, 23] # 最低气温10 11plt.figure(figsize=(6.4, 4.2), dpi=120)12 13# label 是图例文字,marker 是数据点形状,linestyle 是线型14plt.plot(days, high, color='#f43f5e', marker='o', linewidth=2.2,15 markersize=7, label='最高气温')16plt.plot(days, low, color='#2563eb', marker='s', linewidth=2.2,17 markersize=6, linestyle='--', label='最低气温')18 19plt.title('本周气温变化趋势', fontsize=15, pad=14)20plt.xlabel('星期', fontsize=11)21plt.ylabel('温度(℃)', fontsize=11)22plt.ylim(14, 36)23plt.legend(frameon=False) # frameon=False 去掉图例边框24plt.grid(alpha=0.25, linestyle=':')25plt.tight_layout()26plt.savefig('line.png', dpi=150) # 保存为图片27plt.show()
要点
- 三条核心参数
color定线色,linewidth定粗细,linestyle定线型:'-'实线、'--'虚线、':'点线。 - 标记点用 marker
'o'圆、's'方、'^'三角、'*'星号;配markersize控制大小。 - 图例不是自动的每次
plot()都要给label,最后调用plt.legend()才会出现图例。 - 中文与负号默认字体没有中文,必须设
font.sans-serif;负号要额外关掉axes.unicode_minus。
柱状图:比大小plt.bar()
四个季度的销售额 —— 类别之间比较数量,长度编码最准确
图 2-2 各季度销售额柱状图(柱顶标注数值)
1# 柱状图:各季度销售额对比2import matplotlib.pyplot as plt3 4plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei']5plt.rcParams['axes.unicode_minus'] = False6 7quarters = ['第一季度', '第二季度', '第三季度', '第四季度']8sales = [128, 156, 141, 203]9colors = ['#bfdbfe', '#93c5fd', '#60a5fa', '#2563eb'] # 由浅到深,暗示递增10 11plt.figure(figsize=(6.4, 4.2), dpi=120)12bars = plt.bar(quarters, sales, width=0.56, color=colors, edgecolor='white')13 14# 遍历每根柱子,把数值标在柱顶15for bar, value in zip(bars, sales):16 plt.text(bar.get_x() + bar.get_width() / 2, # 柱子中心 x 坐标17 value + 4, # 略高于柱顶18 f'{value}', ha='center', va='bottom',19 fontsize=10.5, color='#334155')20 21plt.title('2025 年各季度销售额', fontsize=15, pad=14)22plt.ylabel('销售额(万元)', fontsize=11)23plt.ylim(0, 240)24plt.grid(axis='y', alpha=0.25, linestyle=':') # 只保留横向网格线25plt.tight_layout()26plt.savefig('bar.png', dpi=150)27plt.show()
要点
- 宽度的视觉作用
width取 0.5–0.7 比较协调;太宽显得笨重,太窄像牙签。 - 柱顶标数值
bar.get_x()拿左边界,加半个get_width()得到中心;再用plt.text写上去。 - 颜色可以编码顺序同一量级的数据用同色系由浅到深,比四种撞色更能传达"逐季增长"。
- 类别不要用折线折线会暗示类别之间存在连续变化,把 Q1 和 Q3 连起来是没有意义的。
散点图:找关系plt.scatter()
90 名学生的学习时长与成绩 —— 观察两个变量是否相关
图 2-3 学习时长与成绩散点图(颜色映射学习时长)
1# 散点图:学习时长与考试成绩的关系2import matplotlib.pyplot as plt3import numpy as np4 5plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei']6plt.rcParams['axes.unicode_minus'] = False7 8rng = np.random.default_rng(7) # 固定随机种子,结果可复现9hours = rng.normal(12, 4, 90).clip(3, 24) # 每周学习时长(小时)10score = 45 + 3.1 * hours + rng.normal(0, 6, 90) # 成绩 ≈ 45 + 3.1×时长 + 噪声11 12plt.figure(figsize=(6.4, 4.4), dpi=120)13 14# s 控制点的大小,c 按数值映射颜色,cmap 指定色带15scatter = plt.scatter(hours, score, s=52, c=hours, cmap='Blues',16 alpha=0.85, edgecolor='#1d4ed8', linewidth=0.7)17plt.colorbar(scatter, label='学习时长(小时)')18 19plt.title('学习时长与考试成绩的关系', fontsize=15, pad=14)20plt.xlabel('每周学习时长(小时)', fontsize=11)21plt.ylabel('考试成绩(分)', fontsize=11)22plt.grid(alpha=0.22, linestyle=':')23plt.tight_layout()24plt.savefig('scatter.png', dpi=150)25plt.show()
要点
- 三个维度一起画
x、y是位置,s是点大小,c可以再编码一个数值维度。 - 颜色映射要配 colorbar
c传数组时按数值上色,必须用plt.colorbar()说明颜色代表什么。 - alpha 解决重叠点密集时透明的
alpha=0.85能看出叠加的深浅,比纯色更诚实。 - 固定随机种子
np.random.default_rng(7)让每次生成的随机数据完全一致,方便复现和对比。
饼图:看构成plt.pie()
一天的 24 小时怎么分配 —— 部分与整体的比例关系
图 2-4 一天时间分配饼图(突出"娱乐"占比)
1# 饼图:一天 24 小时的时间分配2import matplotlib.pyplot as plt3 4plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei']5plt.rcParams['axes.unicode_minus'] = False6 7labels = ['睡眠', '上课', '自习', '娱乐', '运动']8hours = [8, 5, 3.5, 4.5, 1.5]9colors = ['#2563eb', '#60a5fa', '#93c5fd', '#fbbf24', '#14b8a6']10explode = [0, 0, 0, 0.08, 0] # 把"娱乐"这块稍微分离出来11 12plt.figure(figsize=(6.0, 4.6), dpi=120)13plt.pie(hours,14 labels=labels,15 colors=colors,16 explode=explode,17 autopct='%.1f%%', # 百分比保留一位小数18 startangle=90, # 从 12 点方向开始绘制19 counterclock=False, # 顺时针20 textprops={'fontsize': 11, 'color': '#334155'},21 wedgeprops={'edgecolor': 'white', 'linewidth': 2})22 23plt.title('一天 24 小时时间分配', fontsize=15, pad=14)24plt.axis('equal') # 保证是正圆而不是椭圆25plt.tight_layout()26plt.savefig('pie.png', dpi=150)27plt.show()
要点
- 百分比格式
autopct='%.1f%%'保留一位小数,%%是一个转义后的百分号。 - 突出某一块
explode是每块的偏移量列表,只把需要强调的那块设为 0.08。 - 必须 axis('equal')否则窗口一拉长,饼就变成椭圆,面积比例会被视觉扭曲。
- 类别超过 6 个别用人眼比较角度的精度远低于比较长度,这时应该换成条形图。
直方图:看分布plt.hist()
1000 名学生的成绩分布 —— 数据落在各区间的密集程度
图 2-5 成绩分布直方图(均值线与及格线)
1# 直方图:1000 名学生的成绩分布2import matplotlib.pyplot as plt3import numpy as np4 5plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei']6plt.rcParams['axes.unicode_minus'] = False7 8rng = np.random.default_rng(2025)9scores = rng.normal(72, 11, 1000).clip(0, 100) # 均值 72、标准差 11 的正态分布10scores = scores[(scores >= 0) & (scores <= 100)]11 12plt.figure(figsize=(6.4, 4.3), dpi=120)13 14# bins 是分箱数量,edgecolor 让相邻柱子之间有分隔线15plt.hist(scores, bins=22, color='#60a5fa',16 edgecolor='white', linewidth=1.2, alpha=0.9, label='成绩分布')17 18plt.axvline(scores.mean(), color='#f43f5e', linestyle='--',19 linewidth=2, label=f'均值 = {scores.mean():.1f}')20plt.axvline(60, color='#94a3b8', linestyle=':', linewidth=2, label='及格线 60')21 22plt.title('1000 名学生成绩分布直方图', fontsize=15, pad=14)23plt.xlabel('成绩(分)', fontsize=11)24plt.ylabel('人数', fontsize=11)25plt.legend(frameon=False)26plt.grid(axis='y', alpha=0.2, linestyle=':')27plt.tight_layout()28plt.savefig('hist.png', dpi=150)29plt.show()
要点
- bins 决定颗粒度分箱太少掩盖细节,太多则毛刺丛生;一般 15–30 个箱比较合适。
- 参考线点睛
plt.axvline()画竖线,标出均值、中位数或及格线,读者立刻有判断基准。 - 直方图 ≠ 柱状图柱状图比较"不同类别",直方图看"同一变量的分布",外形相似但含义完全不同。
- 先清洗再画图用布尔索引把数据过滤到合理区间,否则个别极端值会把整个分布压扁成一根柱子。
子图:排版式plt.subplots()
把折线、柱状、散点、饼图放进同一张 2×2 画布
图 2-6 subplots 2×2 组合布局
1# 子图:在一张画布上组合四张图表2import matplotlib.pyplot as plt3import numpy as np4 5plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei']6plt.rcParams['axes.unicode_minus'] = False7 8fig, axes = plt.subplots(2, 2, figsize=(9.2, 6.8), dpi=110)9fig.suptitle('subplots:2×2 组合布局', fontsize=16, y=0.985)10 11# 左上:折线图12ax = axes[0, 0]13ax.plot([1, 2, 3, 4, 5], [3, 7, 5, 9, 11], marker='o', color='#2563eb', linewidth=2)14ax.set_title('折线图 plot()', fontsize=12)15ax.grid(alpha=0.25, linestyle=':')16 17# 右上:柱状图18ax = axes[0, 1]19ax.bar(['A', 'B', 'C', 'D'], [12, 18, 9, 15],20 color=['#93c5fd', '#60a5fa', '#3b82f6', '#2563eb'])21ax.set_title('柱状图 bar()', fontsize=12)22ax.grid(axis='y', alpha=0.25, linestyle=':')23 24# 左下:散点图25ax = axes[1, 0]26rng = np.random.default_rng(3)27ax.scatter(rng.normal(0, 1, 60), rng.normal(0, 1, 60),28 s=26, color='#14b8a6', alpha=0.75)29ax.set_title('散点图 scatter()', fontsize=12)30ax.grid(alpha=0.25, linestyle=':')31 32# 右下:饼图33ax = axes[1, 1]34ax.pie([35, 25, 20, 20], labels=['甲', '乙', '丙', '丁'],35 colors=['#2563eb', '#60a5fa', '#93c5fd', '#fbbf24'],36 autopct='%d%%', textprops={'fontsize': 10},37 wedgeprops={'edgecolor': 'white', 'linewidth': 1.6})38ax.set_title('饼图 pie()', fontsize=12)39 40plt.tight_layout()41plt.savefig('subplots.png', dpi=150)42plt.show()
要点
- 一次拿到画布和坐标轴
fig, axes = plt.subplots(2, 2),axes是一个二维数组,用axes[行, 列]取子图。 - 两种标题
ax.set_title()是子图标题,fig.suptitle()是整张画布的总标题。 - 别忘了 tight_layout自动调整子图间距,避免标题、坐标轴标签互相重叠。
- 统一风格同一张画布里的四张图要共用一套配色和字号,否则看起来像四个人各画各的。
常用参数速查表
画图时反复要查的那几行,集中放在这里
| 需求 | 写法 | 说明 |
|---|---|---|
| 画布大小与清晰度 | plt.figure(figsize=(6, 4), dpi=120) | dpi 越高越清晰,打印用 300 |
| 标题 / 轴标签 | plt.title() / plt.xlabel() / plt.ylabel() | 配 fontsize、pad 调位置 |
| 坐标轴范围 | plt.xlim(a, b) / plt.ylim(a, b) | 不看数据分布时最好手动定范围 |
| 图例 | plt.legend(loc='upper right', frameon=False) | loc 控制九宫格位置 |
| 网格 | plt.grid(alpha=0.3, linestyle=':') | alpha 调淡,别盖过数据 |
| 刻度旋转 | plt.xticks(rotation=45) | 类别名太长时的必备操作 |
| 保存图片 | plt.savefig('a.png', dpi=300, bbox_inches='tight') | 必须写在 plt.show() 之前 |
| 显示图片 | plt.show() | 脚本里可省,Jupyter 中自动显示 |
六个新手最常踩的坑
这些报错基本每个人都会遇到一次,先记下来能省很多时间
中文全部变成方块
没设中文字体。加上 plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'](Mac 用 'PingFang SC')。如果还不行,清一下 matplotlib 缓存:删除 ~/.matplotlib/fontlist-*.json 后重启。
负号显示成方块
字体不支持 Unicode 负号,加 plt.rcParams['axes.unicode_minus'] = False 即可。
保存出来的图是空白
顺序写反了。plt.show() 之后画布会被清空,savefig 必须放在 show 之前。
图例没有出现
plot/bar/scatter 时漏了 label 参数,或者忘了调用 plt.legend()。
子图标题互相重叠
加一行 plt.tight_layout(),它会自动计算合适的间距。
图片模糊
dpi 太低。保存时 dpi=300,或者直接存 .svg / .pdf 矢量格式,任意放大都清晰。
本章小结
六种图表对应六种数据关系,选错图比画得难看更致命
先看数据关系,再选图形
随时间变化用折线,类别比大小用柱状,两变量找关系用散点,部分与整体用饼图,看分布用直方图。
四要素缺一不可
标题说清"这张图讲什么",轴标签带单位,图例区分系列,必要时补参考线——缺一个读者就得猜。
样式服务于信息
去掉多余的边框、压淡网格、统一配色。装饰越少,数据越突出;这一点比记住所有参数都重要。