Matplotlib 基础
问题
Matplotlib 的 Figure/Axes 体系是怎样的?如何定制专业的图表?
答案
Figure 与 Axes 体系
两种 API
- pyplot 风格(
plt.plot()):快速出图,适合简单场景 - OO 风格(
fig, ax = plt.subplots()):推荐,更灵活可控
基础绘图
OO 风格基础绘图
import matplotlib.pyplot as plt
import numpy as np
# 创建画布和子图
fig, ax = plt.subplots(figsize=(8, 5))
# 绘制数据
x = np.arange(1, 13)
y1 = [120, 135, 140, 155, 170, 180, 175, 165, 150, 140, 130, 125]
y2 = [100, 110, 125, 140, 155, 165, 160, 150, 135, 120, 110, 105]
ax.plot(x, y1, marker='o', linewidth=2, label='2024', color='#2196F3')
ax.plot(x, y2, marker='s', linewidth=2, label='2023', color='#9E9E9E', linestyle='--')
# 定制外观
ax.set_xlabel('月份', fontsize=12)
ax.set_ylabel('收入(万元)', fontsize=12)
ax.set_title('月度收入对比', fontsize=14, fontweight='bold')
ax.set_xticks(x)
ax.set_xticklabels([f'{i}月' for i in x])
ax.legend(frameon=False)
ax.spines[['top', 'right']].set_visible(False) # 去掉上右边框
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()
子图布局
多子图布局
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
# 左上:折线图
axes[0, 0].plot(range(12), np.random.cumsum(np.random.randn(12)))
axes[0, 0].set_title('趋势')
# 右上:柱状图
axes[0, 1].bar(['A', 'B', 'C', 'D'], [25, 40, 30, 35])
axes[0, 1].set_title('对比')
# 左下:散点图
axes[1, 0].scatter(np.random.rand(50), np.random.rand(50), alpha=0.6)
axes[1, 0].set_title('关系')
# 右下:直方图
axes[1, 1].hist(np.random.normal(100, 15, 500), bins=25, edgecolor='white')
axes[1, 1].set_title('分布')
fig.suptitle('数据看板', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
高级定制
图表美化技巧
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
fig, ax = plt.subplots(figsize=(10, 6))
categories = ['搜索', '社交', '直接', '邮件', '广告', '联盟']
values = [320, 280, 150, 90, 60, 40]
colors = ['#2196F3', '#4CAF50', '#FF9800', '#9C27B0', '#F44336', '#607D8B']
# 水平条形图,排序后绘制
order = np.argsort(values)
bars = ax.barh(
[categories[i] for i in order],
[values[i] for i in order],
color=[colors[i] for i in order],
height=0.6
)
# 在条形末端添加数值标签
for bar in bars:
width = bar.get_width()
ax.text(width + 5, bar.get_y() + bar.get_height()/2,
f'{width:,.0f}', va='center', fontsize=11)
# 美化
ax.set_xlabel('访客数', fontsize=12)
ax.set_title('各渠道访客数', fontsize=14, fontweight='bold', pad=15)
ax.spines[['top', 'right', 'bottom']].set_visible(False)
ax.xaxis.set_visible(False) # 已有数值标签,隐藏 X 轴
plt.tight_layout()
plt.show()
保存图表
高质量导出
# PNG(适合 Web、PPT)
fig.savefig('chart.png', dpi=150, bbox_inches='tight', facecolor='white')
# SVG(适合论文、无损缩放)
fig.savefig('chart.svg', format='svg', bbox_inches='tight')
# PDF(适合印刷)
fig.savefig('chart.pdf', format='pdf', bbox_inches='tight')
中文显示
解决中文显示问题
import matplotlib.pyplot as plt
# 方式一:全局设置(macOS)
plt.rcParams['font.sans-serif'] = ['PingFang SC', 'Heiti TC', 'SimHei']
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示
# 方式二:指定字体
from matplotlib.font_manager import FontProperties
font = FontProperties(fname='/System/Library/Fonts/PingFang.ttc', size=12)
ax.set_title('中文标题', fontproperties=font)
常见面试问题
Q1: plt.plot() 和 ax.plot() 有什么区别?
答案:
plt.plot():pyplot 接口,操作"当前"子图,适合快速出图ax.plot():面向对象接口,明确指定在哪个 Axes 上绑图- 实际项目推荐 OO 风格,多子图时不会混淆
Q2: Matplotlib 图表怎么美化?
答案:
- 去掉上右边框:
ax.spines[['top','right']].set_visible(False) - 柔和网格线:
ax.grid(alpha=0.3) - 有意义的颜色(不要默认色)
- 添加数值标签
- 合适的 figsize 和 dpi
Q3: figsize 怎么选?
答案:
- 单图默认
(8, 5)或(10, 6) - PPT 宽屏
(12, 6) - 多子图
(12, 8)或更大 - 保存时用
dpi=150(Web)或dpi=300(印刷)