github star gitee star atomgit star PyPI Downloads AI 编程 AI 交流群

大家好,我是正在实战各种AI项目的程序员晚枫。

今天继续Matplotlib进阶内容,学习如何让图表更专业、更美观。

同样的数据,普通的图表和精心设计的图表,给人的印象完全不同。掌握这些技巧,让你的图表达到汇报级别。


技巧1:设置全局样式

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt
import numpy as np

# 使用预设样式
plt.style.use('seaborn-v0_8-whitegrid') # 白色网格背景
# 其他可选:'ggplot', 'bmh', 'dark_background', 'fivethirtyeight'

# 自定义全局参数
plt.rcParams['font.size'] = 12
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['axes.grid'] = True
plt.rcParams['grid.alpha'] = 0.3

技巧2:配色方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 使用ColorBrewer配色(专业)
from matplotlib import cm

# 单色系
colors = cm.Blues(np.linspace(0.4, 0.8, 5))

# 多色系
colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd']

# 渐变色
x = np.arange(5)
y = [23, 45, 56, 78, 32]
bars = plt.bar(x, y, color=colors)

# 或使用colormap
for i, bar in enumerate(bars):
bar.set_color(plt.cm.viridis(i / len(bars)))

技巧3:添加注释和标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
x = np.arange(1, 6)
y = [120, 150, 180, 140, 200]

fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(x, y, 'o-', linewidth=2, markersize=8)

# 添加数据标签
for i, (xi, yi) in enumerate(zip(x, y)):
ax.annotate(f'{yi}万',
xy=(xi, yi),
xytext=(0, 10),
textcoords='offset points',
ha='center',
fontsize=10,
color='red')

# 高亮最高点
max_idx = np.argmax(y)
ax.scatter(x[max_idx], y[max_idx], s=200, c='red', marker='*', zorder=5)
ax.annotate('峰值',
xy=(x[max_idx], y[max_idx]),
xytext=(x[max_idx]+0.5, y[max_idx]+20),
arrowprops=dict(arrowstyle='->', color='red'))

ax.set_title('月度销售额趋势', fontsize=16, fontweight='bold')
plt.show()

技巧4:双Y轴图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
x = np.arange(1, 13)
sales = [120, 150, 180, 140, 200, 220, 210, 190, 230, 250, 280, 300]
profit_rate = [15, 18, 20, 16, 22, 25, 24, 21, 26, 28, 30, 32]

fig, ax1 = plt.subplots(figsize=(12, 6))

# 左Y轴:销售额
color1 = '#1f77b4'
ax1.set_xlabel('月份', fontsize=12)
ax1.set_ylabel('销售额(万元)', color=color1, fontsize=12)
line1 = ax1.plot(x, sales, color=color1, marker='o', linewidth=2, label='销售额')
ax1.tick_params(axis='y', labelcolor=color1)

# 右Y轴:利润率
ax2 = ax1.twinx()
color2 = '#ff7f0e'
ax2.set_ylabel('利润率(%)', color=color2, fontsize=12)
line2 = ax2.plot(x, profit_rate, color=color2, marker='s', linewidth=2, label='利润率')
ax2.tick_params(axis='y', labelcolor=color2)

# 合并图例
lines = line1 + line2
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper left')

ax1.set_title('销售额与利润率趋势', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()

技巧5:堆叠图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 堆叠柱状图
months = ['Q1', 'Q2', 'Q3', 'Q4']
product_a = [100, 120, 140, 160]
product_b = [80, 90, 110, 130]
product_c = [60, 70, 80, 90]

fig, ax = plt.subplots(figsize=(10, 6))

ax.bar(months, product_a, label='产品A', color='#3498db')
ax.bar(months, product_b, bottom=product_a, label='产品B', color='#2ecc71')
ax.bar(months, product_c, bottom=np.array(product_a)+np.array(product_b),
label='产品C', color='#e74c3c')

ax.set_ylabel('销售额(万元)')
ax.set_title('季度产品销售构成', fontsize=14, fontweight='bold')
ax.legend()

# 添加总计标签
totals = np.array(product_a) + np.array(product_b) + np.array(product_c)
for i, total in enumerate(totals):
ax.text(i, total + 5, f'{total}', ha='center', fontweight='bold')

plt.show()

技巧6:水平条形图+排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 城市销售排行
cities = ['北京', '上海', '广州', '深圳', '杭州', '成都']
sales = [520, 480, 350, 380, 290, 260]

# 排序
sorted_data = sorted(zip(sales, cities), reverse=True)
sales_sorted = [x[0] for x in sorted_data]
cities_sorted = [x[1] for x in sorted_data]

fig, ax = plt.subplots(figsize=(10, 6))

colors = plt.cm.RdYlGn(np.linspace(0.2, 0.8, len(cities)))[::-1]
bars = ax.barh(cities_sorted, sales_sorted, color=colors)

ax.set_xlabel('销售额(万元)', fontsize=12)
ax.set_title('城市销售排行榜', fontsize=14, fontweight='bold')

# 添加数值标签
for i, (bar, value) in enumerate(zip(bars, sales_sorted)):
ax.text(value + 10, i, f'{value}', va='center', fontsize=10)

ax.set_xlim(0, max(sales) * 1.15)
plt.tight_layout()
plt.show()

技巧7:热力图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import numpy as np

# 创建相关性矩阵
data = np.random.randn(100, 5)
corr_matrix = np.corrcoef(data.T)

fig, ax = plt.subplots(figsize=(8, 6))

im = ax.imshow(corr_matrix, cmap='RdYlBu_r', aspect='auto', vmin=-1, vmax=1)

# 添加颜色条
cbar = plt.colorbar(im, ax=ax)
cbar.set_label('相关系数', rotation=270, labelpad=20)

# 设置刻度
labels = ['A', 'B', 'C', 'D', 'E']
ax.set_xticks(np.arange(len(labels)))
ax.set_yticks(np.arange(len(labels)))
ax.set_xticklabels(labels)
ax.set_yticklabels(labels)

# 添加数值标注
for i in range(len(labels)):
for j in range(len(labels)):
text = ax.text(j, i, f'{corr_matrix[i, j]:.2f}',
ha="center", va="center", color="black", fontsize=10)

ax.set_title('变量相关性热力图', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()

技巧8:组合图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
x = np.arange(1, 13)
sales = [120, 150, 180, 140, 200, 220, 210, 190, 230, 250, 280, 300]
target = [130, 140, 160, 170, 190, 210, 220, 230, 240, 260, 270, 290]

fig, ax = plt.subplots(figsize=(12, 6))

# 柱状图:实际销售
bars = ax.bar(x, sales, alpha=0.7, color='skyblue', label='实际销售')

# 折线图:目标
ax.plot(x, target, 'ro-', linewidth=2, markersize=6, label='目标')

# 填充达标区域
ax.fill_between(x, sales, target, where=np.array(sales) >= np.array(target),
alpha=0.3, color='green', label='超额完成')
ax.fill_between(x, sales, target, where=np.array(sales) < np.array(target),
alpha=0.3, color='red', label='未达标')

ax.set_xlabel('月份', fontsize=12)
ax.set_ylabel('销售额(万元)', fontsize=12)
ax.set_title('年度销售业绩 vs 目标', fontsize=14, fontweight='bold')
ax.set_xticks(x)
ax.legend(loc='upper left')
ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

进阶用法

专业级配色方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用专业配色
import matplotlib.pyplot as plt

# 方案1:使用色板
colors = plt.cm.Set2(np.linspace(0, 1, 8)) # 8种柔和色

# 方案2:自定义品牌色
brand_colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']

# 方案3:渐变色
gradient = plt.cm.RdYlGn(np.linspace(0.2, 0.8, 10)) # 红到绿渐变

# 应用到图表
plt.bar(categories, values, color=brand_colors)

注释和标注

1
2
3
4
5
6
7
8
9
10
11
# 标注关键数据点
max_idx = values.index(max(values))
plt.annotate(f'最高: {max(values)}',
xy=(max_idx, max(values)),
xytext=(max_idx+1, max(values)*1.1),
arrowprops=dict(arrowstyle='->', color='red'),
fontsize=12, color='red')

# 标注区间
plt.axvspan(5, 8, alpha=0.2, color='green', label='增长期')
plt.axhline(y=100, linestyle='--', color='red', label='目标线')

自定义样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 全局样式
plt.style.use('seaborn-v0_8-whitegrid') # 或 'ggplot', 'fivethirtyeight'

# 自定义样式表
custom_style = {
'figure.facecolor': '#1a1a2e',
'axes.facecolor': '#16213e',
'axes.edgecolor': '#e94560',
'text.color': '#eaeaea',
'axes.labelcolor': '#eaeaea',
'xtick.color': '#eaeaea',
'ytick.color': '#eaeaea',
}
plt.rcParams.update(custom_style)

避坑指南

❌ 坑1:子图间距重叠

1
2
3
4
5
6
7
fig, axes = plt.subplots(3, 3)
# 默认间距太紧,标题和标签重叠

# 解决方案
plt.tight_layout() # 自动调整
plt.subplots_adjust(hspace=0.3, wspace=0.3) # 手动调整
plt.tight_layout(pad=2.0) # 带边距

❌ 坑2:图例遮挡数据

1
2
3
4
5
6
7
8
# 图例放在最佳位置
plt.legend(loc='best') # 自动选择

# 或者放在图外
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')

# 或者设为半透明
plt.legend(framealpha=0.5)

实战案例:制作年度经营分析仪表盘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np

plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize=(20, 14))
gs = gridspec.GridSpec(3, 4, figure=fig, hspace=0.35, wspace=0.3)

# 模拟数据
months = [f'{m}月' for m in range(1, 13)]
revenue = [120, 135, 148, 160, 155, 170, 185, 190, 175, 195, 210, 230]
cost = [80, 85, 90, 95, 92, 98, 105, 100, 95, 102, 110, 115]
profit = [r-c for r, c in zip(revenue, cost)]
categories = ['电子产品', '服装', '食品', '家居', '美妆']
cat_sales = [450, 380, 320, 280, 210]

# 1. 收入趋势(大图)
ax1 = fig.add_subplot(gs[0, :3])
ax1.fill_between(months, revenue, alpha=0.3, color='#4CAF50')
ax1.plot(months, revenue, 'o-', color='#4CAF50', linewidth=2, label='收入')
ax1.plot(months, cost, 's--', color='#FF5722', linewidth=2, label='成本')
ax1.set_title('月度收入与成本趋势', fontsize=16, fontweight='bold')
ax1.legend(fontsize=12)
ax1.set_ylabel('金额(万元)')

# 2. 利润率(右侧小图)
ax2 = fig.add_subplot(gs[0, 3])
profit_rate = [p/r*100 for p, r in zip(profit, revenue)]
colors = ['#4CAF50' if p > 30 else '#FF9800' for p in profit_rate]
ax2.barh(months, profit_rate, color=colors, height=0.6)
ax2.set_title('利润率(%)', fontsize=14)

# 3. 品类分布
ax3 = fig.add_subplot(gs[1, :2])
ax3.pie(cat_sales, labels=categories, autopct='%1.1f%%',
colors=plt.cm.Set3(np.linspace(0, 1, 5)))
ax3.set_title('品类销售占比', fontsize=14)

# 4. 品类柱状图
ax4 = fig.add_subplot(gs[1, 2:])
ax4.bar(categories, cat_sales, color=plt.cm.Set3(np.linspace(0, 1, 5)))
ax4.set_title('品类销售排行', fontsize=14)
ax4.set_ylabel('销售额(万元)')

# 5. 关键指标
ax5 = fig.add_subplot(gs[2, :])
ax5.axis('off')
metrics = [
f'全年总收入: ¥{sum(revenue):,}万',
f'全年总利润: ¥{sum(profit):,}万',
f'平均利润率: {np.mean(profit_rate):.1f}%',
f'增长趋势: +{((revenue[-1]-revenue[0])/revenue[0]*100):.1f}%'
]
for i, m in enumerate(metrics):
ax5.text(i*0.25+0.05, 0.5, m, fontsize=16, fontweight='bold',
transform=ax5.transAxes, ha='left', va='center',
bbox=dict(boxstyle='round,pad=0.5', facecolor='#E3F2FD', alpha=0.8))

plt.savefig('annual_dashboard.png', dpi=150, bbox_inches='tight')
plt.show()

动画图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
line, = ax.plot([], [], 'b-')
ax.set_xlim(0, 100)
ax.set_ylim(0, 10)

def init():
line.set_data([], [])
return line,

def animate(i):
x = np.arange(i)
y = np.random.randn(i).cumsum()
line.set_data(x, y)
return line,

anim = FuncAnimation(fig, animate, init_func=init, frames=100, interval=50, blit=True)
anim.save('animation.gif', writer='pillow')
plt.show()

3D图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

# 3D散点图
ax.scatter(df['x'], df['y'], df['z'], c=df['category'], s=50, alpha=0.6)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

# 3D曲面图
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
ax.plot_surface(X, Y, Z, cmap='viridis')

下节预告

下一课我们将学习Seaborn统计可视化,用更少的代码做出更漂亮的图表。

👉 继续阅读:Seaborn统计可视化-让图表更优雅


💬 加入学习交流群

扫码加入Python学习交流群,和数千名同学一起进步:

👉 点击加入交流群

群里不定期分享:

  • 数据分析实战案例
  • Python学习资料
  • 求职面试经验
  • 行业最新动态

推荐:AI Python数据分析实战营

🎁 限时福利:送《利用Python进行数据分析》实体书

👉 点击了解详情


课程导航

上一篇: Matplotlib基础-绘制你的第一张图表

下一篇: Seaborn统计可视化-让图表更优雅


PS:好的图表不仅要准确,还要美观。花点时间调整细节,让数据呈现更有说服力。



📚 推荐教材

主教材《Excel+Python 飞速搞定数据分析与处理(图灵出品)》

💬 联系我

平台账号/链接
微信扫码加好友
微博@程序员晚枫
知乎@程序员晚枫
抖音@程序员晚枫
小红书@程序员晚枫
B 站Python 自动化办公社区

主营业务:AI 编程培训、企业内训、技术咨询

🎓 AI 编程实战课程

想系统学习 AI 编程?程序员晚枫的 AI 编程实战课 帮你从零上手!