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面向对象接口当

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