Pandas绘图接口

基础概念与语法

基本语法结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 创建示例数据
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=100, freq='D')
df = pd.DataFrame({
'A': np.random.randn(100).cumsum(),
'B': np.random.randn(100).cumsum() + 10,
'C': np.random.randn(100).cumsum() + 20,
'D': np.random.randn(100).cumsum() + 30,
'Category': np.random.choice(['X', 'Y', 'Z'], 100)
}, index=dates)

# 基本绘图语法
df.plot(kind='line', # 图表类型
x=None, # x轴数据列
y=None, # y轴数据列
ax=None, # 目标坐标轴
**kwargs) # 其他参数

快速开始示例

1
2
3
4
5
6
7
8
9
# 绘制单列线图(默认类型)
df['A'].plot(figsize=(10, 6), title='Single Column Line Plot')

# 绘制多列线图
df[['A', 'B', 'C']].plot(figsize=(12, 8), title='Multiple Columns')

# 绘制所有数值列
df.plot(figsize=(12, 8)) # 自动选择数值列
plt.show()

图表类型详解

1. 折线图 (kind=’line’)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 基本线图
df[['A', 'B']].plot(kind='line',
figsize=(12, 8),
title='Line Plot Example',
grid=True,
alpha=0.8)

# 带标记的线图
df['A'].plot(kind='line',
marker='o',
markersize=4,
linestyle='--',
linewidth=2,
color='red')

2. 柱状图 (kind=’bar’ / ‘barh’)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 垂直柱状图
df_sample = df.resample('M').mean() # 按月重采样
df_sample[['A', 'B']].plot(kind='bar',
figsize=(12, 8),
title='Vertical Bar Chart',
alpha=0.7,
rot=45)

# 水平柱状图
df_sample[['A', 'B']].plot(kind='barh',
title='Horizontal Bar Chart',
alpha=0.7)

# 堆叠柱状图
df_sample[['A', 'B', 'C']].plot(kind='bar',
stacked=True,
title='Stacked Bar Chart')

3. 直方图 (kind=’hist’)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 单列直方图
df['A'].plot(kind='hist',
bins=30,
alpha=0.7,
title='Histogram of Column A',
grid=True)

# 多列直方图(堆叠)
df[['A', 'B']].plot(kind='hist',
bins=20,
alpha=0.6,
stacked=True,
title='Stacked Histogram')

# 多列直方图(并排)
df[['A', 'B']].plot(kind='hist',
bins=20,
alpha=0.6,
title='Side-by-Side Histogram')

4. 箱线图 (kind=’box’)

1
2
3
4
5
6
7
8
9
# 箱线图
df[['A', 'B', 'C']].plot(kind='box',
figsize=(10, 8),
title='Box Plot',
grid=True)

# 分组箱线图(按分类变量)
df.pivot(columns='Category', values='A').plot(kind='box',
title='Box Plot by Category')

5. 面积图 (kind=’area’)

1
2
3
4
5
6
7
8
9
10
11
12
# 面积图
df[['A', 'B', 'C']].plot(kind='area',
figsize=(12, 8),
title='Area Chart',
alpha=0.4,
grid=True)

# 堆叠面积图
df[['A', 'B', 'C']].plot(kind='area',
stacked=True,
title='Stacked Area Chart',
alpha=0.6)

6. 散点图 (kind=’scatter’)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 散点图(需要指定x和y)
df.plot(kind='scatter',
x='A',
y='B',
figsize=(10, 8),
title='Scatter Plot A vs B',
alpha=0.6,
s=50) # 点的大小

# 带颜色映射的散点图
scatter = df.plot(kind='scatter',
x='A',
y='B',
c='C', # 颜色基于C列的值
cmap='viridis',
s=df['D']/df['D'].max()*100, # 大小基于D列的值
alpha=0.6,
colorbar=True)

7. 饼图 (kind=’pie’)

1
2
3
4
5
6
7
8
# 饼图(通常用于聚合数据)
category_sum = df.groupby('Category')['A'].sum()
category_sum.plot(kind='pie',
figsize=(10, 8),
title='Pie Chart by Category',
autopct='%1.1f%%',
startangle=90,
shadow=True)

8. 六边形箱图 (kind=’hexbin’)

1
2
3
4
5
6
7
8
# 六边形箱图(用于大量数据点)
df.plot(kind='hexbin',
x='A',
y='B',
gridsize=20,
figsize=(10, 8),
title='Hexbin Plot',
cmap='viridis')

参数完整参考

核心参数

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
"""
kind: 图表类型 ('line', 'bar', 'barh', 'hist', 'box', 'kde', 'density', 'area', 'pie', 'scatter', 'hexbin')
x: x轴数据列名
y: y轴数据列名(可多个)
ax: matplotlib轴对象
figsize: 图形尺寸 (width, height)
title: 图表标题
grid: 是否显示网格
legend: 是否显示图例
logx/logy: 对数刻度
style: 线条样式列表
color: 颜色或颜色列表
colormap: 颜色映射
fontsize: 字体大小
rot: 刻度标签旋转角度
"""

### 线图特定参数
"""
linestyle: 线条样式 ('-', '--', '-.', ':')
linewidth: 线条宽度
marker: 标记样式
markersize: 标记大小
alpha: 透明度
"""

### 柱状图特定参数
"""
stacked: 是否堆叠
width: 柱宽
"""

### 直方图特定参数
"""
bins: 箱子数量
histtype: 直方图类型 ('bar', 'barstacked', 'step', 'stepfilled')
"""

### 散点图特定参数
"""
s: 点的大小
c: 点的颜色
colorbar: 是否显示颜色条
"""

返回值与进一步定制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# df.plot() 返回 matplotlib Axes 对象,可以进一步定制
ax = df[['A', 'B']].plot(figsize=(12, 8))

# 进一步定制
ax.set_facecolor('#f8f9fa') # 设置背景色
ax.spines['top'].set_visible(False) # 隐藏顶部边框
ax.spines['right'].set_visible(False) # 隐藏右侧边框

# 添加水平参考线
ax.axhline(y=df['A'].mean(), color='red', linestyle='--', alpha=0.7, label='Mean')

# 添加垂直参考线
ax.axvline(x=df.index[50], color='green', linestyle=':', alpha=0.7, label='Midpoint')

# 添加文本标注
ax.text(df.index[25], df['A'].max()*0.9, 'Peak Value',
fontsize=10, ha='center', color='blue')

plt.legend()
plt.tight_layout()
plt.show()

样式与外观定制

颜色控制

1
2
3
4
5
6
7
8
9
10
11
# 单色指定
df['A'].plot(color='red')

# 多色指定
df[['A', 'B', 'C']].plot(color=['red', 'blue', 'green'])

# 使用颜色映射
df[['A', 'B', 'C']].plot(colormap='viridis')

# 十六进制颜色
df[['A', 'B']].plot(color=['#FF5733', '#33FF57'])

线条与标记样式

1
2
3
4
5
6
7
8
9
10
11
12
# 线条样式
styles = ['-', '--', '-.', ':']
df[['A', 'B', 'C', 'D']].plot(style=styles, linewidth=2)

# 标记样式
markers = ['o', 's', '^', 'D']
df[['A', 'B', 'C', 'D']].plot(marker=markers, markersize=6)

# 综合样式
df[['A', 'B']].plot(style=['ro-', 'bs--'], # 红色圆点实线,蓝色方点虚线
linewidth=2,
markersize=8)

标题与标签

1
2
3
4
5
6
7
8
9
10
11
12
ax = df[['A', 'B']].plot(figsize=(12, 8),
title='Custom Title',
fontsize=12)

# 额外定制
ax.set_title('Detailed Title', fontsize=16, fontweight='bold')
ax.set_xlabel('Time', fontsize=12)
ax.set_ylabel('Values', fontsize=12)
ax.set_ylim(-10, 50) # 设置y轴范围

# 图例定制
ax.legend(['Series A', 'Series B'], loc='upper left', fontsize=10)

子图与布局控制

自动子图

1
2
3
4
5
6
7
# 自动创建子图
df[['A', 'B', 'C', 'D']].plot(subplots=True,
figsize=(12, 10),
layout=(2, 2),
sharex=True,
sharey=True,
title='Automatic Subplots')

手动子图控制

1
2
3
4
5
6
7
8
9
10
11
12
# 创建自定义布局
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('Manual Subplot Layout', fontsize=16)

# 在每个子图上绘制
df['A'].plot(ax=axes[0, 0], title='Column A', color='red', grid=True)
df['B'].plot(ax=axes[0, 1], title='Column B', color='blue', grid=True)
df['C'].plot(ax=axes[1, 0], title='Column C', color='green', grid=True)
df['D'].plot(ax=axes[1, 1], title='Column D', color='orange', grid=True)

plt.tight_layout()
plt.show()

混合图表类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建混合图表
fig, ax = plt.subplots(figsize=(12, 8))

# 线图
df['A'].plot(ax=ax, kind='line', color='blue', label='Line', alpha=0.7)

# 柱状图(使用次要y轴)
ax2 = ax.twinx()
df['B'].plot(ax=ax2, kind='bar', color='red', alpha=0.4, label='Bar')

# 添加图例
lines, labels = ax.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax.legend(lines + lines2, labels + labels2, loc='upper left')

plt.title('Mixed Chart Types')
plt.show()

高级功能与技巧

时间序列特定功能

1
2
3
4
5
6
7
8
9
10
11
12
# 重采样绘图
df['A'].resample('W').mean().plot( # 每周平均
kind='line',
title='Weekly Average',
marker='o',
grid=True)

# 滚动统计
df['A'].rolling(window=7).mean().plot(label='7D MA', alpha=0.7)
df['A'].rolling(window=30).mean().plot(label='30D MA', alpha=0.7)
df['A'].plot(label='Original', alpha=0.3)
plt.legend()

条件格式化

1
2
3
4
5
6
7
8
9
10
11
12
13
# 条件着色线图
ax = df['A'].plot(figsize=(12, 8), color='lightgray', linewidth=3)

# 高于平均值的部分
above_avg = df[df['A'] > df['A'].mean()]
above_avg['A'].plot(ax=ax, color='green', linewidth=2)

# 低于平均值的部分
below_avg = df[df['A'] <= df['A'].mean()]
below_avg['A'].plot(ax=ax, color='red', linewidth=2)

plt.title('Conditional Coloring')
plt.show()

交互式功能

1
2
3
4
5
6
7
8
9
10
11
# 在Jupyter中启用交互式
%matplotlib widget

# 创建交互式图表
df[['A', 'B']].plot(figsize=(10, 6),
title='Interactive Plot',
grid=True)

# 添加交互功能
plt.gca().set_facecolor('#f0f0f0')
plt.tight_layout()

批量处理与导出

1
2
3
4
5
6
7
8
9
10
# 批量绘制所有数值列
numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()

for i, col in enumerate(numeric_cols):
plt.figure(figsize=(10, 6))
df[col].plot(title=f'Plot of {col}', grid=True)
plt.ylabel('Values')
plt.tight_layout()
plt.savefig(f'plot_{col}.png', dpi=300, bbox_inches='tight')
plt.close() # 关闭图形以节省内存

实战示例

股票数据可视化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 模拟股票数据
stock_data = pd.DataFrame({
'Open': np.random.normal(100, 5, 100).cumsum(),
'High': np.random.normal(105, 6, 100).cumsum(),
'Low': np.random.normal(95, 4, 100).cumsum(),
'Close': np.random.normal(100, 5, 100).cumsum()
}, index=pd.date_range('2023-01-01', periods=100))

# 价格走势图
stock_data[['Open', 'High', 'Low', 'Close']].plot(
figsize=(14, 8),
title='Stock Price Movement',
linewidth=1,
alpha=0.8,
grid=True)

plt.ylabel('Price')
plt.show()

销售数据分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 模拟销售数据
sales_data = pd.DataFrame({
'Product_A': np.random.randint(50, 200, 12),
'Product_B': np.random.randint(30, 150, 12),
'Product_C': np.random.randint(70, 250, 12)
}, index=pd.date_range('2023-01-01', periods=12, freq='M'))

# 堆叠面积图显示销售构成
sales_data.plot(kind='area',
stacked=True,
figsize=(12, 8),
title='Sales Composition by Product',
alpha=0.7,
grid=True)

plt.ylabel('Sales Units')
plt.legend(title='Products')
plt.show()

Matplotlib面向对象接口

基本概念

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

## 基本绘图流程
x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure() ## 创建图形
plt.plot(x, y) ## 绘制图形
plt.title('Sine Wave') ## 添加标题
plt.xlabel('x') ## x轴标签
plt.ylabel('y') ## y轴标签
plt.grid(True) ## 显示网格
plt.show() ## 显示图形

图形结构

Matplotlib 的图形结构包含以下几个主要组件:

  • Figure:整个图形窗口
  • Axes:实际绘图的区域(可以包含多个)
  • Axis:坐标轴
  • Artist:所有可见元素(文本、线条等)
1
2
3
4
5
6
7
8
## 使用面向对象的方式(推荐)
fig, ax = plt.subplots() ## 创建图形和坐标轴
ax.plot(x, y) ## 在坐标轴上绘图
ax.set_title('Sine Wave') ## 设置标题
ax.set_xlabel('x') ## 设置x轴标签
ax.set_ylabel('y') ## 设置y轴标签
ax.grid(True) ## 显示网格
plt.show()

基本图表类型

折线图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
x = np.linspace(0, 10, 100)
y = np.sin(x)

fig, ax = plt.subplots()

ax.plot(x, y,
color='blue', ## 线条颜色
linestyle='-', ## 线条样式: '-', '--', '-.', ':'
linewidth=2, ## 线条宽度
marker='o', ## 标记点样式: 'o', 's', '^', 'D', etc.
markersize=8, ## 标记点大小
markerfacecolor='red', ## 标记点填充颜色
markeredgecolor='black', ## 标记点边缘颜色
markeredgewidth=1, ## 标记点边缘宽度
label='折线图') ## 图例标签

ax.legend() ## 显示图例
plt.show()

散点图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
x = np.random.randn(100)
y = np.random.randn(100)

fig, ax = plt.subplots()

ax.scatter(x, y,
s=100, ## 点的大小
c='red', ## 点的颜色
alpha=0.7, ## 透明度
marker='s', ## 点形状
edgecolors='black', ## 边缘颜色
linewidths=1, ## 边缘宽度
label='数据') ## 图例标签

plt.show()

柱状图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
x = ['A', 'B', 'C', 'D']
y = [10, 25, 15, 30]

fig, ax = plt.subplots()

ax.bar(x, y+5,
width=0.6, ## 条形宽度
color='green', ## 条形颜色
alpha=0.7, ## 透明度 (0-1)
edgecolor='black', ## 边缘颜色
linewidth=1, ## 边缘宽度
label='柱状图') ## 图例标签

plt.show()

## 水平柱状图
fig, ax = plt.subplots()
ax.barh(categories, values)
plt.show()

直方图

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
data = np.random.randn(1000)

fig, ax = plt.subplots()
ax.hist(data,
bins=30, ## 柱子数量或边界数组
range=(-3, 3), ## 数据范围
density=False, ## 是否显示密度而非计数
weights=None, ## 每个数据点的权重
cumulative=False, ## 是否显示累积分布
bottom=None, ## 底部基线
histtype='bar', ## 类型: 'bar', 'barstacked', 'step', 'stepfilled'
align='mid', ## 对齐方式: 'left', 'mid', 'right'
orientation='vertical', ## 方向: 'vertical', 'horizontal'
rwidth=0.8, ## 柱子相对宽度
log=False, ## 是否使用对数刻度
color='blue', ## 颜色
alpha=0.7, ## 透明度
label='数据分布', ## 图例标签
edgecolor='black', ## 边缘颜色
linewidth=1) ## 边缘宽度

## 设置标题和标签
ax.set_title('数据分布直方图')
ax.set_xlabel('数值')
ax.set_ylabel('频数')
ax.legend()
ax.grid(True, alpha=0.3)

plt.show()

饼图

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
sizes = [15, 30, 45, 10]
labels = ['A', 'B', 'C', 'D']

fig, ax = plt.subplots()
ax.pie(sizes,
explode=explode, ## 各部分突出程度
labels=labels, ## 各部分标签
colors=colors, ## 各部分颜色
autopct='%1.1f%%', ## 百分比格式
shadow=True, ## 是否显示阴影
startangle=90, ## 起始角度
radius=1.0, ## 半径
counterclock=True, ## 是否逆时针排列
wedgeprops={'edgecolor': 'black', 'linewidth': 1}, ## 楔形属性
textprops={'fontsize': 12}, ## 文本属性
center=(0, 0), ## 中心位置
frame=False, ## 是否显示框架
labeldistance=1.1, ## 标签距离中心的比例
pctdistance=0.6) ## 百分比文本距离中心的比例

## 设置标题
ax.set_title('饼图示例', fontsize=16)

## 设置纵横比相等,使饼图为圆形
ax.axis('equal')

plt.show()

箱线图

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
data = [np.random.normal(0, std, 100) for std in range(1, 4)]

fig, ax = plt.subplots()

ax.boxplot(data,
vert=True, ## 是否垂直显示
patch_artist=True, ## 是否填充箱体
labels=labels, ## 箱线图标签
notch=False, ## 是否显示缺口
bootstrap=None, ## 自举法参数
usermedians=None, ## 自定义中位数
conf_intervals=None, ## 置信区间
positions=None, ## 箱线图位置
widths=0.5, ## 箱体宽度
showmeans=False, ## 是否显示均值
meanline=False, ## 是否用线表示均值
showfliers=True, ## 是否显示异常值
meanprops=None, ## 均值属性
medianprops=None, ## 中位数属性
boxprops=None, ## 箱体属性
whiskerprops=None, ## 须线属性
capprops=None, ## 端点线属性
flierprops=None, ## 异常值属性
manage_ticks=True) ## 是否管理刻度

## 自定义样式
for box in boxplot['boxes']:
box.set(facecolor='lightblue', alpha=0.7, linewidth=2)

for whisker in boxplot['whiskers']:
whisker.set(color='gray', linewidth=1.5, linestyle='-')

for cap in boxplot['caps']:
cap.set(color='gray', linewidth=1.5)

for median in boxplot['medians']:
median.set(color='red', linewidth=2)

for flier in boxplot['fliers']:
flier.set(marker='o', color='red', alpha=0.5)

## 设置标题和标签
ax.set_title('箱线图示例')
ax.set_xlabel('组别')
ax.set_ylabel('数值')
ax.grid(True, alpha=0.3)

plt.show()

样式与颜色

线型与标记

1
2
3
4
5
6
7
8
9
10
11
x = np.linspace(0, 10, 20)

fig, ax = plt.subplots()
ax.plot(x, x, '-') ## 实线
ax.plot(x, x+1, '--') ## 虚线
ax.plot(x, x+2, '-.') ## 点划线
ax.plot(x, x+3, ':') ## 点线
ax.plot(x, x+4, 'o') ## 圆点标记
ax.plot(x, x+5, 's') ## 方形标记
ax.plot(x, x+6, '^') ## 三角形标记
plt.show()

颜色

1
2
3
4
5
6
7
## 颜色表示方式
fig, ax = plt.subplots()
ax.plot(x, x, 'r') ## 红色 (单字符)
ax.plot(x, x+1, 'green') ## 绿色 (名称)
ax.plot(x, x+2, '##FF0000') ## 红色 (十六进制)
ax.plot(x, x+3, (0.1, 0.2, 0.5)) ## RGB元组 (0-1)
plt.show()

样式表

1
2
3
4
5
6
7
8
9
10
11
12
## 使用预定义样式
plt.style.use('ggplot') ## 其他选项: 'seaborn', 'bmh', 'dark_background', 'classic'

x = np.linspace(0, 10, 100)
y = np.sin(x)

fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()

## 重置为默认样式
plt.style.use('default')

文本与标注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
x = np.linspace(0, 10, 100)
y = np.sin(x)

fig, ax = plt.subplots()
ax.plot(x, y)

## 添加文本
ax.text(5, 0, 'Zero Point', fontsize=12, color='red')

## 添加箭头标注
ax.annotate('Maximum', xy=(np.pi/2, 1), xytext=(3, 0.8),
arrowprops=dict(facecolor='black', shrink=0.05))

plt.show()

子图与布局

基本子图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
## 创建2x2的子图网格
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8))

## 在每个子图上绘图
axes[0, 0].plot(x, np.sin(x))
axes[0, 0].set_title('Sine Wave')

axes[0, 1].plot(x, np.cos(x))
axes[0, 1].set_title('Cosine Wave')

axes[1, 0].plot(x, np.tan(x))
axes[1, 0].set_title('Tangent Wave')
axes[1, 0].set_ylim(-5, 5) ## 设置y轴范围

axes[1, 1].scatter(np.random.rand(50), np.random.rand(50))
axes[1, 1].set_title('Random Scatter')

plt.tight_layout() ## 自动调整子图间距
plt.show()

复杂布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
## 使用GridSpec创建复杂布局
from matplotlib.gridspec import GridSpec

fig = plt.figure(figsize=(10, 8))
gs = GridSpec(3, 3, figure=fig)

ax1 = fig.add_subplot(gs[0, :]) ## 第一行所有列
ax2 = fig.add_subplot(gs[1, :-1]) ## 第二行,除最后一列
ax3 = fig.add_subplot(gs[1:, -1]) ## 从第二行开始,最后一列
ax4 = fig.add_subplot(gs[-1, 0]) ## 最后一行,第一列
ax5 = fig.add_subplot(gs[-1, -2]) ## 最后一行,倒数第二列

## 在各个子图上绘图
ax1.plot(x, np.sin(x))
ax2.plot(x, np.cos(x))
ax3.scatter(np.random.rand(10), np.random.rand(10))
ax4.hist(np.random.randn(100))
ax5.plot(x, np.tan(x))

plt.tight_layout()
plt.show()

3D绘图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from mpl_toolkits.mplot3d import Axes3D

## 创建3D图形
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

## 生成数据
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))

## 绘制3D曲面
surf = ax.plot_surface(X, Y, Z, cmap='viridis')

## 添加颜色条
fig.colorbar(surf)

## 设置标签
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

plt.show()

高级技巧

双Y轴

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x) * 100 ## 不同量级的数据

fig, ax1 = plt.subplots()

## 第一个Y轴
color = 'tab:red'
ax1.set_xlabel('x')
ax1.set_ylabel('sin(x)', color=color)
ax1.plot(x, y1, color=color)
ax1.tick_params(axis='y', labelcolor=color)

## 第二个Y轴
ax2 = ax1.twinx() ## 共享x轴
color = 'tab:blue'
ax2.set_ylabel('100*cos(x)', color=color)
ax2.plot(x, y2, color=color)
ax2.tick_params(axis='y', labelcolor=color)

plt.show()

保存图形

1
2
3
4
5
6
7
8
9
10
11
x = np.linspace(0, 10, 100)
y = np.sin(x)

fig, ax = plt.subplots()
ax.plot(x, y)

## 保存为不同格式
plt.savefig('figure.png', dpi=300, bbox_inches='tight') ## PNG格式
plt.savefig('figure.pdf') ## PDF格式
plt.savefig('figure.jpg', quality=95) ## JPG格式
plt.savefig('figure.svg') ## SVG格式

动画

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

## 创建动画
fig, ax = plt.subplots()
x = np.linspace(0, 2*np.pi, 100)
line, = ax.plot(x, np.sin(x))

def animate(i):
line.set_ydata(np.sin(x + i/10))
return line,

ani = FuncAnimation(fig, animate, frames=100, interval=50, blit=True)

## 在Jupyter中显示动画
## HTML(ani.to_jshtml())

## 保存动画
## ani.save('animation.gif', writer='pillow', fps=20)

自定义刻度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
x = np.linspace(0, 10, 100)
y = np.sin(x)

fig, ax = plt.subplots()
ax.plot(x, y)

## 设置刻度位置
ax.set_xticks([0, np.pi, 2*np.pi, 3*np.pi])

## 设置刻度标签
ax.set_xticklabels(['0', 'π', '2π', '3π'])

## 设置刻度范围
ax.set_xlim(0, 10)
ax.set_ylim(-1.5, 1.5)

plt.show()

Pandas 绘图接口 vs Matplotlib 面向对象接口:全面对比

Pandas 基于 Matplotlib 构建的高级绘图接口和 Matplotlib 的面向对象接口是 Python 数据可视化的两种主要方式,各有特点和适用场景。

核心区别概述

特性 Pandas 绘图接口 Matplotlib 面向对象接口
语法简洁性 非常高,一行代码即可绘图 相对复杂,需要更多代码
学习曲线 平缓,易于上手 较陡峭,需要理解更多概念
与DataFrame集成 紧密集成,直接使用列名 需要显式提取数据
定制灵活性 有限,适合快速绘图 极高,可精细控制每个元素
子图控制 有限,主要通过subplots参数 完全控制,可创建复杂布局
返回对象 通常返回Axes对象 返回Figure和Axes对象
适用场景 数据探索、快速原型 出版级图表、高度定制化需求

详细对比

1. 语法与易用性

Pandas 绘图接口

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd
import matplotlib.pyplot as plt

# 创建示例数据
df = pd.DataFrame({
'A': range(10),
'B': range(10, 20),
'C': range(20, 30)
})

# 一行代码绘制多线图
df.plot(kind='line', figsize=(10, 6), title='Pandas Plot Example')
plt.show()

Matplotlib 面向对象接口

1
2
3
4
5
6
7
8
# 需要更多代码
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(df.index, df['A'], label='A')
ax.plot(df.index, df['B'], label='B')
ax.plot(df.index, df['C'], label='C')
ax.set_title('Matplotlib OO Example')
ax.legend()
plt.show()

2. 与DataFrame的集成度

Pandas 绘图接口(高度集成):

1
2
3
4
5
6
7
8
# 直接使用列名
df.plot(x='A', y='B', kind='scatter') # 使用列名指定x和y

# 自动处理索引
df.set_index('A').plot() # 自动使用索引作为x轴

# 分组绘图
df.groupby('Category')['Value'].plot(kind='hist', alpha=0.5, legend=True)

Matplotlib 面向对象接口(需要显式提取):

1
2
3
4
5
6
# 需要显式提取数据
fig, ax = plt.subplots()
ax.scatter(df['A'], df['B']) # 需要显式指定列

# 需要手动处理索引
ax.plot(df.index, df['Value'])

3. 定制化能力

Pandas 绘图接口(有限定制):

1
2
3
4
5
6
7
8
# 通过参数定制
df.plot(kind='line',
figsize=(10, 6),
title='Customized Pandas Plot',
color=['red', 'blue', 'green'],
style=['-', '--', '-.'],
linewidth=2,
grid=True)

Matplotlib 面向对象接口(完全定制):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 完全控制每个元素
fig, ax = plt.subplots(figsize=(10, 6))

# 精细控制每条线
line1 = ax.plot(df.index, df['A'], color='red', linestyle='-', linewidth=2, marker='o')
line2 = ax.plot(df.index, df['B'], color='blue', linestyle='--', linewidth=2, marker='s')

# 精细控制每个图表元素
ax.set_title('Fully Customized Plot', fontsize=16, fontweight='bold')
ax.set_xlabel('Index', fontsize=12)
ax.set_ylabel('Value', fontsize=12)
ax.grid(True, linestyle=':', alpha=0.7)
ax.legend(['Series A', 'Series B'], loc='upper left')

# 添加辅助元素
ax.axhline(y=15, color='gray', linestyle='--', alpha=0.5)
ax.text(5, 15.5, 'Reference Line', fontsize=10)

# 设置刻度格式
ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, pos: f'Day {int(x)}'))

4. 子图与布局控制

Pandas 绘图接口(简单子图):

1
2
3
4
5
6
# 自动创建子图
df.plot(subplots=True,
layout=(2, 2),
figsize=(12, 8),
sharex=True,
title='Pandas Subplots')

Matplotlib 面向对象接口(复杂布局):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 创建复杂网格布局
fig = plt.figure(figsize=(12, 8))
gs = fig.add_gridspec(3, 3) # 3x3网格

# 创建不同大小的子图
ax1 = fig.add_subplot(gs[0, :]) # 第一行全宽
ax2 = fig.add_subplot(gs[1, :-1]) # 第二行除最后一列
ax3 = fig.add_subplot(gs[1:, -1]) # 从第二行开始,最后一列
ax4 = fig.add_subplot(gs[2, 0]) # 第三行第一列
ax5 = fig.add_subplot(gs[2, 1]) # 第三行第二列

# 在每个子图上绘制不同内容
ax1.plot(df.index, df['A'])
ax2.scatter(df['A'], df['B'])
ax3.hist(df['C'])
ax4.boxplot(df['A'])
ax5.pie([1, 2, 3], labels=['A', 'B', 'C'])

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
# 使用Pandas快速创建基础图表
ax = df.plot(kind='line',
figsize=(10, 6),
title='Hybrid Approach',
alpha=0.7)

# 使用Matplotlib进行精细定制
ax.annotate('Important Point',
xy=(5, df.loc[5, 'A']),
xytext=(3, df['A'].max()),
arrowprops=dict(facecolor='black', shrink=0.05))

ax.axvspan(3, 7, alpha=0.2, color='gray') # 添加阴影区域

# 添加额外数据(Pandas无法直接实现)
extra_data = [x**0.5 for x in range(10)]
ax.plot(range(10), extra_data, 'ro--', label='Extra Data')

ax.legend()
plt.show()

性能考虑

对于大数据集,两种方法的性能差异很小,因为Pandas绘图接口底层也是调用Matplotlib。但在极端情况下:

1
2
3
4
5
6
7
8
9
10
11
12
# 大数据集示例
large_df = pd.DataFrame(np.random.randn(10000, 5))

# Pandas接口
%timeit large_df.plot() # 通常稍快,因为优化了数据传递

# Matplotlib接口
%timeit
fig, ax = plt.subplots()
for col in large_df.columns:
ax.plot(large_df.index, large_df[col])
plt.close()

最佳实践建议

  1. 数据探索阶段:使用Pandas绘图接口快速可视化数据
  2. 报告和演示:使用Matplotlib面向对象接口创建精美、定制化的图表
  3. 混合使用:用Pandas创建基础图表,然后用Matplotlib进行精细调整
  4. 团队协作:根据团队熟悉程度选择,Pandas更适合数据分析师,Matplotlib更适合有编程背景的数据科学家

选择指南

  • 选择Pandas绘图接口当

    • 你需要快速探索数据
    • 你主要使用DataFrame/Series对象
    • 你对图表定制要求不高
    • 你想用最少的代码获得可视化结果
  • 选择Matplotlib面向对象接口当

    • 你需要高度定制化的图表
    • 你需要创建复杂的多子图布局
    • 你要出版或展示专业级图表
    • 你需要精细控制每个图表元素