Pandas 图形绘制详解
引言
Pandas 不仅是一个强大的数据处理库,还提供了便捷的数据可视化功能。虽然 Pandas 的绘图功能基于 Matplotlib,但它提供了更简洁、更直观的接口,让你能够快速创建各种图表。本教程将系统地讲解 Pandas 的图形绘制功能,每个概念都配有可直接运行的代码示例。
学习建议:
- 阅读每个示例代码
- 复制代码到 Python 解释器或 IDE 中运行
- 尝试修改代码,观察结果变化
- 完成每个部分的练习
前置要求:
- 基本了解 Pandas 的 DataFrame 和 Series
- 安装了 pandas、matplotlib 库
安装依赖:
pip install pandas matplotlib
第一部分:Pandas 绘图基础
1. 为什么使用 Pandas 绘图?
Pandas 绘图的主要优势:
- 简洁的语法:一行代码即可生成图表
- 自动处理索引:自动使用 DataFrame/Series 的索引作为 x 轴
- 集成度高:与 Pandas 数据结构无缝集成
- 快速探索:适合数据探索和快速可视化
2. 基本绘图设置
在开始之前,我们需要导入必要的库并进行基本配置。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # Mac
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 设置图表样式
plt.style.use('default') # 可以使用 'ggplot', 'seaborn' 等
# 创建示例数据
dates = pd.date_range('2024-01-01', periods=30, freq='D')
df = pd.DataFrame({
'销售额': np.random.randint(1000, 5000, 30),
'访问量': np.random.randint(100, 500, 30),
'转化率': np.random.uniform(0.01, 0.05, 30)
}, index=dates)
print(df.head())
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建简单的测试数据
data = {
'A': [1, 2, 3, 4, 5],
'B': [2, 4, 6, 8, 10],
'C': [3, 6, 9, 12, 15]
}
df = pd.DataFrame(data)
print(df)
3. Series 绘图
Series 对象可以直接调用 .plot() 方法进行绘图。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建 Series
s = pd.Series([1, 3, 2, 4, 5, 6, 7, 8, 9, 10])
# 绘制线图(默认)
s.plot()
plt.title('Series 线图')
plt.xlabel('索引')
plt.ylabel('值')
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建示例 Series
s = pd.Series(np.random.randn(20).cumsum(),
index=pd.date_range('2024-01-01', periods=20))
# 绘制图表
s.plot(title='随机数据累积和', figsize=(10, 6))
plt.xlabel('日期')
plt.ylabel('累积值')
plt.grid(True)
plt.show()
4. DataFrame 绘图
DataFrame 可以同时绘制多列数据。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建示例 DataFrame
df = pd.DataFrame({
'A': np.random.randn(20).cumsum(),
'B': np.random.randn(20).cumsum(),
'C': np.random.randn(20).cumsum()
}, index=pd.date_range('2024-01-01', periods=20))
# 绘制所有列
df.plot(figsize=(10, 6))
plt.title('多列数据线图')
plt.xlabel('日期')
plt.ylabel('值')
plt.legend()
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建销售数据
dates = pd.date_range('2024-01-01', periods=12, freq='M')
df = pd.DataFrame({
'产品A': np.random.randint(100, 500, 12),
'产品B': np.random.randint(150, 600, 12),
'产品C': np.random.randint(80, 400, 12)
}, index=dates)
df.plot(figsize=(12, 6), title='月度销售数据对比')
plt.xlabel('月份')
plt.ylabel('销售额(元)')
plt.legend(loc='best')
plt.grid(True, alpha=0.3)
plt.show()
第二部分:常用图表类型
1. 线图(Line Plot)
线图是最常用的图表类型,适合展示数据随时间的变化趋势。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建时间序列数据
dates = pd.date_range('2024-01-01', periods=30, freq='D')
df = pd.DataFrame({
'温度': np.random.normal(20, 5, 30),
'湿度': np.random.normal(60, 10, 30)
}, index=dates)
# 绘制线图
df.plot(kind='line', figsize=(12, 6))
plt.title('30天温度和湿度变化')
plt.xlabel('日期')
plt.ylabel('值')
plt.legend(['温度(°C)', '湿度(%)'])
plt.grid(True, alpha=0.3)
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建股票价格模拟数据
dates = pd.date_range('2024-01-01', periods=50, freq='D')
prices = 100 + np.cumsum(np.random.randn(50) * 2)
df = pd.DataFrame({'股价': prices}, index=dates)
# 绘制线图
df.plot(kind='line', figsize=(12, 6), color='blue', linewidth=2)
plt.title('股票价格走势图', fontsize=16)
plt.xlabel('日期', fontsize=12)
plt.ylabel('价格(元)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.show()
自定义线图样式:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
x = np.linspace(0, 10, 100)
df = pd.DataFrame({
'sin': np.sin(x),
'cos': np.cos(x),
'tan': np.tan(x) / 10 # 缩小 tan 值以便显示
}, index=x)
# 自定义样式绘制
ax = df.plot(kind='line', figsize=(12, 6),
style=['-', '--', ':'], # 线型
linewidth=2, # 线宽
color=['red', 'blue', 'green'], # 颜色
alpha=0.8) # 透明度
plt.title('三角函数图像', fontsize=16)
plt.xlabel('x', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.legend(['sin(x)', 'cos(x)', 'tan(x)/10'])
plt.grid(True, alpha=0.3)
plt.axhline(y=0, color='black', linewidth=0.5)
plt.axvline(x=0, color='black', linewidth=0.5)
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建多系列数据
dates = pd.date_range('2024-01-01', periods=20, freq='D')
df = pd.DataFrame({
'销售额': np.random.randint(1000, 5000, 20),
'成本': np.random.randint(500, 2000, 20),
'利润': lambda x: x['销售额'] - x['成本']
}, index=dates)
df['利润'] = df['销售额'] - df['成本']
# 绘制多条线
ax = df.plot(kind='line', figsize=(12, 6),
marker='o', # 标记点
markersize=4, # 标记大小
linewidth=1.5) # 线宽
plt.title('销售数据分析', fontsize=16, fontweight='bold')
plt.xlabel('日期', fontsize=12)
plt.ylabel('金额(元)', fontsize=12)
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3, linestyle='--')
plt.tight_layout()
plt.show()
2. 柱状图(Bar Plot)
柱状图适合比较不同类别的数据。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建分类数据
categories = ['产品A', '产品B', '产品C', '产品D', '产品E']
sales = [1200, 1500, 800, 2000, 1100]
df = pd.DataFrame({'销售额': sales}, index=categories)
# 绘制垂直柱状图
df.plot(kind='bar', figsize=(10, 6), color='steelblue')
plt.title('各产品销售额对比', fontsize=16)
plt.xlabel('产品', fontsize=12)
plt.ylabel('销售额(元)', fontsize=12)
plt.xticks(rotation=0)
plt.legend()
plt.grid(True, alpha=0.3, axis='y')
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建多系列柱状图数据
months = ['1月', '2月', '3月', '4月', '5月', '6月']
df = pd.DataFrame({
'产品A': [1200, 1500, 1300, 1800, 1600, 2000],
'产品B': [800, 900, 1000, 1100, 1200, 1300],
'产品C': [600, 700, 750, 800, 850, 900]
}, index=months)
# 绘制分组柱状图
df.plot(kind='bar', figsize=(12, 6), width=0.8)
plt.title('上半年各产品月度销售额', fontsize=16)
plt.xlabel('月份', fontsize=12)
plt.ylabel('销售额(元)', fontsize=12)
plt.xticks(rotation=0)
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.show()
水平柱状图:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
regions = ['华北', '华东', '华南', '西南', '西北']
revenue = [5000, 8000, 6000, 4000, 3000]
df = pd.DataFrame({'营收': revenue}, index=regions)
# 绘制水平柱状图
df.plot(kind='barh', figsize=(10, 6), color='coral')
plt.title('各地区营收对比', fontsize=16)
plt.xlabel('营收(万元)', fontsize=12)
plt.ylabel('地区', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3, axis='x')
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建堆叠柱状图数据
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
df = pd.DataFrame({
'线上': [3000, 3500, 4000, 4500],
'线下': [2000, 2200, 2500, 2800],
'其他': [500, 600, 700, 800]
}, index=quarters)
# 绘制堆叠柱状图
df.plot(kind='bar', stacked=True, figsize=(10, 6))
plt.title('各季度销售渠道分布', fontsize=16)
plt.xlabel('季度', fontsize=12)
plt.ylabel('销售额(元)', fontsize=12)
plt.xticks(rotation=0)
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3, axis='y')
plt.show()
3. 直方图(Histogram)
直方图用于展示数据的分布情况。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建随机数据
np.random.seed(42)
data = np.random.normal(100, 15, 1000)
df = pd.DataFrame({'数值': data})
# 绘制直方图
df.plot(kind='hist', bins=30, figsize=(10, 6), color='skyblue', edgecolor='black')
plt.title('数据分布直方图', fontsize=16)
plt.xlabel('数值', fontsize=12)
plt.ylabel('频数', fontsize=12)
plt.grid(True, alpha=0.3, axis='y')
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建多个分布的数据
np.random.seed(42)
df = pd.DataFrame({
'组A': np.random.normal(50, 10, 1000),
'组B': np.random.normal(60, 15, 1000),
'组C': np.random.normal(55, 12, 1000)
})
# 绘制重叠直方图
df.plot(kind='hist', bins=30, figsize=(12, 6), alpha=0.7, edgecolor='black')
plt.title('多组数据分布对比', fontsize=16)
plt.xlabel('数值', fontsize=12)
plt.ylabel('频数', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3, axis='y')
plt.show()
密度图(KDE):
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
np.random.seed(42)
df = pd.DataFrame({
'分布1': np.random.normal(0, 1, 1000),
'分布2': np.random.normal(2, 1.5, 1000)
})
# 绘制密度图
df.plot(kind='density', figsize=(12, 6), linewidth=2)
plt.title('概率密度分布图', fontsize=16)
plt.xlabel('值', fontsize=12)
plt.ylabel('密度', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建学生成绩数据
np.random.seed(42)
scores = np.random.normal(75, 10, 500)
df = pd.DataFrame({'成绩': scores})
# 同时绘制直方图和密度图
ax = df['成绩'].plot(kind='hist', bins=30, figsize=(10, 6),
color='lightblue', edgecolor='black', alpha=0.7, density=True)
df['成绩'].plot(kind='density', ax=ax, color='red', linewidth=2)
plt.title('学生成绩分布', fontsize=16)
plt.xlabel('成绩', fontsize=12)
plt.ylabel('密度', fontsize=12)
plt.legend(['直方图', '密度曲线'])
plt.grid(True, alpha=0.3, axis='y')
plt.show()
4. 箱线图(Box Plot)
箱线图用于展示数据的分布、中位数、四分位数和异常值。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建多组数据
np.random.seed(42)
df = pd.DataFrame({
'组A': np.random.normal(50, 10, 100),
'组B': np.random.normal(60, 15, 100),
'组C': np.random.normal(55, 12, 100),
'组D': np.random.normal(65, 8, 100)
})
# 绘制箱线图
df.plot(kind='box', figsize=(10, 6))
plt.title('多组数据箱线图对比', fontsize=16)
plt.ylabel('数值', fontsize=12)
plt.grid(True, alpha=0.3, axis='y')
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建不同月份的数据
np.random.seed(42)
months = ['1月', '2月', '3月', '4月', '5月', '6月']
data = {}
for month in months:
data[month] = np.random.normal(100, 20, 50)
df = pd.DataFrame(data)
# 绘制箱线图
ax = df.plot(kind='box', figsize=(12, 6), patch_artist=True)
plt.title('各月份数据分布箱线图', fontsize=16)
plt.xlabel('月份', fontsize=12)
plt.ylabel('数值', fontsize=12)
plt.grid(True, alpha=0.3, axis='y')
plt.show()
5. 散点图(Scatter Plot)
散点图用于展示两个变量之间的关系。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建相关数据
np.random.seed(42)
x = np.random.randn(100)
y = 2 * x + np.random.randn(100) * 0.5
df = pd.DataFrame({'X': x, 'Y': y})
# 绘制散点图
df.plot(kind='scatter', x='X', y='Y', figsize=(10, 6), alpha=0.6)
plt.title('X 与 Y 的关系散点图', fontsize=16)
plt.xlabel('X', fontsize=12)
plt.ylabel('Y', fontsize=12)
plt.grid(True, alpha=0.3)
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建多组散点数据
np.random.seed(42)
n = 50
df = pd.DataFrame({
'广告投入': np.random.uniform(1000, 10000, n),
'销售额': np.random.uniform(5000, 50000, n),
'类别': np.random.choice(['A', 'B', 'C'], n)
})
# 按类别绘制不同颜色的散点
for category in df['类别'].unique():
data = df[df['类别'] == category]
plt.scatter(data['广告投入'], data['销售额'],
label=category, alpha=0.6, s=50)
plt.title('广告投入与销售额关系', fontsize=16)
plt.xlabel('广告投入(元)', fontsize=12)
plt.ylabel('销售额(元)', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
6. 饼图(Pie Chart)
饼图用于展示各部分占整体的比例。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建分类数据
categories = ['产品A', '产品B', '产品C', '产品D', '其他']
sales = [3500, 2800, 2100, 1500, 1000]
df = pd.DataFrame({'销售额': sales}, index=categories)
# 绘制饼图
df.plot(kind='pie', y='销售额', figsize=(10, 8), autopct='%1.1f%%', startangle=90)
plt.title('销售额占比分布', fontsize=16)
plt.ylabel('') # 移除默认的 y 轴标签
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建地区销售数据
regions = ['华北', '华东', '华南', '西南', '西北', '东北']
revenue = [25, 30, 20, 10, 8, 7]
df = pd.DataFrame({'营收占比': revenue}, index=regions)
# 绘制饼图,自定义颜色和样式
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc', '#c2c2f0']
df.plot(kind='pie', y='营收占比', figsize=(10, 8),
autopct='%1.1f%%',
startangle=90,
colors=colors,
explode=(0.05, 0.05, 0, 0, 0, 0), # 突出显示前两个
shadow=True)
plt.title('各地区营收占比', fontsize=16, fontweight='bold')
plt.ylabel('')
plt.show()
7. 面积图(Area Plot)
面积图是填充的线图,适合展示累积数据。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建时间序列数据
dates = pd.date_range('2024-01-01', periods=12, freq='M')
df = pd.DataFrame({
'产品A': np.random.randint(1000, 3000, 12),
'产品B': np.random.randint(800, 2500, 12),
'产品C': np.random.randint(600, 2000, 12)
}, index=dates)
# 绘制堆叠面积图
df.plot(kind='area', figsize=(12, 6), alpha=0.7)
plt.title('各产品月度销售额堆叠面积图', fontsize=16)
plt.xlabel('日期', fontsize=12)
plt.ylabel('销售额(元)', fontsize=12)
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3)
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建累积数据
dates = pd.date_range('2024-01-01', periods=20, freq='D')
df = pd.DataFrame({
'新用户': np.random.randint(50, 200, 20),
'活跃用户': np.random.randint(100, 300, 20),
'流失用户': np.random.randint(10, 50, 20)
}, index=dates)
# 绘制未堆叠的面积图
df.plot(kind='area', figsize=(12, 6), alpha=0.6, stacked=False)
plt.title('用户数据趋势', fontsize=16)
plt.xlabel('日期', fontsize=12)
plt.ylabel('用户数', fontsize=12)
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3)
plt.show()
第三部分:高级绘图技巧
1. 子图(Subplots)
在一个图中创建多个子图。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
dates = pd.date_range('2024-01-01', periods=30, freq='D')
df = pd.DataFrame({
'销售额': np.random.randint(1000, 5000, 30),
'访问量': np.random.randint(100, 500, 30),
'转化率': np.random.uniform(0.01, 0.05, 30)
}, index=dates)
# 创建子图
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
# 子图1:线图
df['销售额'].plot(ax=axes[0, 0], kind='line', color='blue')
axes[0, 0].set_title('销售额趋势')
axes[0, 0].set_ylabel('销售额(元)')
axes[0, 0].grid(True, alpha=0.3)
# 子图2:柱状图
df['访问量'].plot(ax=axes[0, 1], kind='bar', color='green')
axes[0, 1].set_title('访问量')
axes[0, 1].set_ylabel('访问量')
axes[0, 1].tick_params(axis='x', rotation=45)
# 子图3:直方图
df['转化率'].plot(ax=axes[1, 0], kind='hist', color='red', bins=20)
axes[1, 0].set_title('转化率分布')
axes[1, 0].set_xlabel('转化率')
axes[1, 0].set_ylabel('频数')
# 子图4:散点图
df.plot(ax=axes[1, 1], kind='scatter', x='访问量', y='销售额', alpha=0.6)
axes[1, 1].set_title('访问量与销售额关系')
axes[1, 1].set_xlabel('访问量')
axes[1, 1].set_ylabel('销售额(元)')
axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建示例数据
np.random.seed(42)
df = pd.DataFrame({
'A': np.random.randn(100).cumsum(),
'B': np.random.randn(100).cumsum(),
'C': np.random.randn(100)
})
# 使用 DataFrame.plot 的 subplots 参数
df.plot(subplots=True, figsize=(12, 8), layout=(3, 1), sharex=True)
plt.suptitle('多系列数据子图', fontsize=16, y=1.02)
plt.tight_layout()
plt.show()
2. 图表自定义和美化
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
dates = pd.date_range('2024-01-01', periods=12, freq='M')
df = pd.DataFrame({
'销售额': np.random.randint(10000, 50000, 12),
'成本': np.random.randint(5000, 25000, 12)
}, index=dates)
# 自定义样式绘制
ax = df.plot(kind='line', figsize=(12, 6),
style=['-o', '--s'], # 线型和标记
linewidth=2.5, # 线宽
markersize=8, # 标记大小
color=['#2E86AB', '#A23B72'], # 自定义颜色
alpha=0.8) # 透明度
# 自定义标题和标签
plt.title('月度销售数据分析', fontsize=18, fontweight='bold', pad=20)
plt.xlabel('月份', fontsize=14, fontweight='bold')
plt.ylabel('金额(元)', fontsize=14, fontweight='bold')
# 自定义图例
plt.legend(['销售额', '成本'], loc='upper left', fontsize=12,
frameon=True, fancybox=True, shadow=True)
# 添加网格
plt.grid(True, alpha=0.3, linestyle='--', linewidth=0.5)
# 设置背景色
ax.set_facecolor('#f8f9fa')
# 格式化 y 轴标签(添加千位分隔符)
ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{int(x):,}'))
plt.tight_layout()
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
categories = ['Q1', 'Q2', 'Q3', 'Q4']
df = pd.DataFrame({
'线上': [3000, 3500, 4000, 4500],
'线下': [2000, 2200, 2500, 2800]
}, index=categories)
# 美化柱状图
ax = df.plot(kind='bar', figsize=(10, 6),
color=['#4A90E2', '#50C878'],
width=0.7,
edgecolor='black',
linewidth=1.2)
plt.title('各季度销售渠道对比', fontsize=16, fontweight='bold', pad=15)
plt.xlabel('季度', fontsize=12, fontweight='bold')
plt.ylabel('销售额(元)', fontsize=12, fontweight='bold')
plt.xticks(rotation=0)
plt.legend(loc='upper left', frameon=True, fancybox=True, shadow=True)
# 在柱子上添加数值标签
for container in ax.containers:
ax.bar_label(container, fmt='%d', padding=3, fontsize=10)
plt.grid(True, alpha=0.3, axis='y', linestyle='--')
ax.set_facecolor('#fafafa')
plt.tight_layout()
plt.show()
3. 使用 plot() 方法的参数
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
df = pd.DataFrame({
'A': np.random.randn(20).cumsum(),
'B': np.random.randn(20).cumsum(),
'C': np.random.randn(20).cumsum()
})
# 使用各种参数
ax = df.plot(figsize=(12, 6),
kind='line', # 图表类型
xlabel='索引', # x 轴标签
ylabel='值', # y 轴标签
title='多系列数据图', # 标题
legend=True, # 显示图例
grid=True, # 显示网格
style=['-', '--', ':'], # 线型
color=['red', 'blue', 'green'], # 颜色
linewidth=2, # 线宽
alpha=0.8, # 透明度
rot=0) # x 轴标签旋转角度
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
dates = pd.date_range('2024-01-01', periods=10, freq='D')
df = pd.DataFrame({
'温度': np.random.normal(20, 5, 10),
'湿度': np.random.normal(60, 10, 10)
}, index=dates)
# 一次性设置所有参数
df.plot(figsize=(12, 6),
kind='line',
title='温度和湿度变化',
xlabel='日期',
ylabel='值',
legend=True,
grid=True,
marker='o',
markersize=6,
linewidth=2,
colormap='viridis') # 使用颜色映射
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
第四部分:实际应用案例
案例 1:销售数据分析可视化
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建销售数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=12, freq='M')
sales_data = {
'产品A': np.random.randint(10000, 30000, 12),
'产品B': np.random.randint(8000, 25000, 12),
'产品C': np.random.randint(5000, 20000, 12),
'总成本': np.random.randint(15000, 40000, 12)
}
df = pd.DataFrame(sales_data, index=dates)
df['总利润'] = df['产品A'] + df['产品B'] + df['产品C'] - df['总成本']
# 创建综合图表
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
# 1. 各产品销售额趋势
df[['产品A', '产品B', '产品C']].plot(ax=axes[0, 0], kind='line', marker='o')
axes[0, 0].set_title('各产品月度销售额趋势', fontsize=14, fontweight='bold')
axes[0, 0].set_ylabel('销售额(元)')
axes[0, 0].grid(True, alpha=0.3)
axes[0, 0].legend()
# 2. 总利润柱状图
df['总利润'].plot(ax=axes[0, 1], kind='bar', color='green', alpha=0.7)
axes[0, 1].set_title('月度总利润', fontsize=14, fontweight='bold')
axes[0, 1].set_ylabel('利润(元)')
axes[0, 1].tick_params(axis='x', rotation=45)
axes[0, 1].grid(True, alpha=0.3, axis='y')
axes[0, 1].axhline(y=0, color='red', linestyle='--', linewidth=1)
# 3. 产品销售额占比(饼图)
total_sales = df[['产品A', '产品B', '产品C']].sum()
total_sales.plot(ax=axes[1, 0], kind='pie', autopct='%1.1f%%', startangle=90)
axes[1, 0].set_title('产品销售额占比', fontsize=14, fontweight='bold')
axes[1, 0].set_ylabel('')
# 4. 利润分布直方图
df['总利润'].plot(ax=axes[1, 1], kind='hist', bins=10, color='orange', alpha=0.7, edgecolor='black')
axes[1, 1].set_title('利润分布', fontsize=14, fontweight='bold')
axes[1, 1].set_xlabel('利润(元)')
axes[1, 1].set_ylabel('频数')
axes[1, 1].grid(True, alpha=0.3, axis='y')
plt.suptitle('2024年度销售数据分析报告', fontsize=18, fontweight='bold', y=0.995)
plt.tight_layout()
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 简化的销售数据分析
np.random.seed(42)
months = ['1月', '2月', '3月', '4月', '5月', '6月']
df = pd.DataFrame({
'销售额': np.random.randint(50000, 100000, 6),
'成本': np.random.randint(30000, 60000, 6)
}, index=months)
df['利润'] = df['销售额'] - df['成本']
# 绘制对比图
ax = df.plot(kind='bar', figsize=(12, 6), width=0.8)
plt.title('上半年销售数据分析', fontsize=16, fontweight='bold')
plt.xlabel('月份', fontsize=12)
plt.ylabel('金额(元)', fontsize=12)
plt.xticks(rotation=0)
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3, axis='y')
# 添加数值标签
for container in ax.containers:
ax.bar_label(container, fmt='%d', padding=3)
plt.tight_layout()
plt.show()
案例 2:股票价格分析
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 模拟股票价格数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=60, freq='D')
base_price = 100
price_changes = np.random.randn(60).cumsum() * 2
prices = base_price + price_changes
df = pd.DataFrame({
'收盘价': prices,
'成交量': np.random.randint(1000000, 5000000, 60)
}, index=dates)
# 计算移动平均线
df['MA5'] = df['收盘价'].rolling(window=5).mean()
df['MA20'] = df['收盘价'].rolling(window=20).mean()
# 创建图表
fig, axes = plt.subplots(2, 1, figsize=(14, 10), sharex=True)
# 价格和移动平均线
axes[0].plot(df.index, df['收盘价'], label='收盘价', linewidth=2, color='black')
axes[0].plot(df.index, df['MA5'], label='5日均线', linewidth=1.5, linestyle='--', color='blue')
axes[0].plot(df.index, df['MA20'], label='20日均线', linewidth=1.5, linestyle='--', color='red')
axes[0].set_title('股票价格走势及移动平均线', fontsize=14, fontweight='bold')
axes[0].set_ylabel('价格(元)', fontsize=12)
axes[0].legend(loc='best')
axes[0].grid(True, alpha=0.3)
# 成交量
axes[1].bar(df.index, df['成交量'], alpha=0.6, color='green', width=0.8)
axes[1].set_title('成交量', fontsize=14, fontweight='bold')
axes[1].set_ylabel('成交量', fontsize=12)
axes[1].set_xlabel('日期', fontsize=12)
axes[1].grid(True, alpha=0.3, axis='y')
plt.xticks(rotation=45)
plt.suptitle('股票技术分析图表', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 简化的股票数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=30, freq='D')
prices = 100 + np.cumsum(np.random.randn(30) * 2)
df = pd.DataFrame({'价格': prices}, index=dates)
# 计算移动平均
df['MA10'] = df['价格'].rolling(window=10).mean()
# 绘制图表
ax = df[['价格', 'MA10']].plot(figsize=(12, 6), linewidth=2)
plt.title('股票价格与10日均线', fontsize=16, fontweight='bold')
plt.xlabel('日期', fontsize=12)
plt.ylabel('价格(元)', fontsize=12)
plt.legend(['收盘价', '10日均线'])
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
案例 3:用户行为分析
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建用户行为数据
np.random.seed(42)
hours = list(range(24))
df = pd.DataFrame({
'访问量': np.random.randint(100, 1000, 24),
'注册数': np.random.randint(10, 100, 24),
'购买数': np.random.randint(5, 50, 24)
}, index=hours)
# 计算转化率
df['注册转化率'] = (df['注册数'] / df['访问量'] * 100).round(2)
df['购买转化率'] = (df['购买数'] / df['访问量'] * 100).round(2)
# 创建综合图表
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
# 1. 访问量趋势
df['访问量'].plot(ax=axes[0, 0], kind='line', marker='o', color='blue', linewidth=2)
axes[0, 0].set_title('24小时访问量趋势', fontsize=14, fontweight='bold')
axes[0, 0].set_xlabel('小时')
axes[0, 0].set_ylabel('访问量')
axes[0, 0].grid(True, alpha=0.3)
axes[0, 0].set_xticks(range(0, 24, 2))
# 2. 注册和购买数对比
df[['注册数', '购买数']].plot(ax=axes[0, 1], kind='bar', width=0.8, alpha=0.7)
axes[0, 1].set_title('注册数与购买数对比', fontsize=14, fontweight='bold')
axes[0, 1].set_xlabel('小时')
axes[0, 1].set_ylabel('数量')
axes[0, 1].legend()
axes[0, 1].tick_params(axis='x', rotation=0)
axes[0, 1].set_xticks(range(0, 24, 4))
axes[0, 1].grid(True, alpha=0.3, axis='y')
# 3. 转化率对比
df[['注册转化率', '购买转化率']].plot(ax=axes[1, 0], kind='line', marker='s', linewidth=2)
axes[1, 0].set_title('转化率趋势', fontsize=14, fontweight='bold')
axes[1, 0].set_xlabel('小时')
axes[1, 0].set_ylabel('转化率(%)')
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)
axes[1, 0].set_xticks(range(0, 24, 2))
# 4. 访问量分布
df['访问量'].plot(ax=axes[1, 1], kind='hist', bins=15, color='green', alpha=0.7, edgecolor='black')
axes[1, 1].set_title('访问量分布', fontsize=14, fontweight='bold')
axes[1, 1].set_xlabel('访问量')
axes[1, 1].set_ylabel('频数')
axes[1, 1].grid(True, alpha=0.3, axis='y')
plt.suptitle('用户行为数据分析', fontsize=18, fontweight='bold')
plt.tight_layout()
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 简化的用户数据
np.random.seed(42)
days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
df = pd.DataFrame({
'访问量': np.random.randint(1000, 5000, 7),
'注册数': np.random.randint(100, 500, 7)
}, index=days)
# 绘制对比图
ax = df.plot(kind='bar', figsize=(10, 6), width=0.7)
plt.title('一周用户数据', fontsize=16, fontweight='bold')
plt.xlabel('星期', fontsize=12)
plt.ylabel('数量', fontsize=12)
plt.xticks(rotation=0)
plt.legend()
plt.grid(True, alpha=0.3, axis='y')
# 添加数值标签
for container in ax.containers:
ax.bar_label(container, fmt='%d', padding=3)
plt.tight_layout()
plt.show()
第五部分:常见问题和技巧
1. 处理中文显示问题
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# Windows 系统
plt.rcParams['font.sans-serif'] = ['SimHei'] # 黑体
# 或者
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 微软雅黑
# Mac 系统
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
# Linux 系统
# plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei']
# 解决负号显示问题
plt.rcParams['axes.unicode_minus'] = False
# 测试中文显示
df = pd.DataFrame({'销售额': [1000, 2000, 3000]}, index=['产品A', '产品B', '产品C'])
df.plot(kind='bar', title='中文标题测试')
plt.xlabel('产品类别')
plt.ylabel('销售额(元)')
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows
plt.rcParams['axes.unicode_minus'] = False
# 创建中文数据
df = pd.DataFrame({
'销售额': [12000, 15000, 18000, 20000],
'利润': [3000, 4000, 5000, 6000]
}, index=['第一季度', '第二季度', '第三季度', '第四季度'])
df.plot(kind='bar', figsize=(10, 6))
plt.title('季度销售数据', fontsize=16)
plt.xlabel('季度', fontsize=12)
plt.ylabel('金额(元)', fontsize=12)
plt.xticks(rotation=0)
plt.legend()
plt.show()
2. 保存图表
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据并绘图
df = pd.DataFrame({'值': np.random.randn(100).cumsum()})
ax = df.plot(figsize=(10, 6), title='示例图表')
# 保存为不同格式
plt.savefig('chart.png', dpi=300, bbox_inches='tight') # PNG 格式
plt.savefig('chart.pdf', bbox_inches='tight') # PDF 格式
plt.savefig('chart.jpg', dpi=300, bbox_inches='tight') # JPG 格式
plt.savefig('chart.svg', bbox_inches='tight') # SVG 格式
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建简单图表
df = pd.DataFrame({'数据': [1, 2, 3, 4, 5]})
df.plot(kind='bar', figsize=(8, 6), title='测试图表')
# 保存图表(取消注释以保存)
# plt.savefig('my_chart.png', dpi=300, bbox_inches='tight')
# print('图表已保存为 my_chart.png')
plt.show()
3. 自定义颜色和样式
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
df = pd.DataFrame({
'系列1': np.random.randn(10),
'系列2': np.random.randn(10),
'系列3': np.random.randn(10)
})
# 使用预定义颜色映射
df.plot(kind='bar', figsize=(10, 6), colormap='viridis')
plt.title('使用颜色映射')
plt.show()
# 使用自定义颜色列表
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
df.plot(kind='bar', figsize=(10, 6), color=colors)
plt.title('自定义颜色')
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
categories = ['A', 'B', 'C', 'D']
df = pd.DataFrame({
'值1': [10, 20, 15, 25],
'值2': [15, 25, 20, 30]
}, index=categories)
# 使用不同颜色方案
color_schemes = {
'方案1': ['#FF6B6B', '#4ECDC4'],
'方案2': ['#95E1D3', '#F38181'],
'方案3': ['#AA96DA', '#FCBAD3']
}
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
for idx, (name, colors) in enumerate(color_schemes.items()):
df.plot(kind='bar', ax=axes[idx], color=colors, title=name)
axes[idx].legend()
axes[idx].tick_params(axis='x', rotation=0)
plt.tight_layout()
plt.show()
4. 处理大数据集
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建大数据集
np.random.seed(42)
large_df = pd.DataFrame({
'x': np.random.randn(10000),
'y': np.random.randn(10000)
})
# 对于大数据集,使用采样或聚合
# 方法1:随机采样
sample_df = large_df.sample(n=1000)
sample_df.plot(kind='scatter', x='x', y='y', alpha=0.5, figsize=(10, 6))
plt.title('采样后的散点图(1000个点)')
plt.show()
# 方法2:使用直方图2D
plt.hist2d(large_df['x'], large_df['y'], bins=50, cmap='Blues')
plt.colorbar()
plt.title('大数据集2D直方图')
plt.xlabel('x')
plt.ylabel('y')
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 创建较大数据集
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=365, freq='D')
df = pd.DataFrame({
'值': np.random.randn(365).cumsum()
}, index=dates)
# 按月聚合
monthly = df.resample('M').mean()
# 绘制聚合后的数据
monthly.plot(kind='line', figsize=(12, 6), marker='o')
plt.title('月度平均值趋势')
plt.xlabel('月份')
plt.ylabel('平均值')
plt.grid(True, alpha=0.3)
plt.show()
第六部分:综合练习
练习 1:创建完整的数据分析报告
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建模拟的电商数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=90, freq='D')
df = pd.DataFrame({
'订单数': np.random.randint(100, 500, 90),
'销售额': np.random.randint(10000, 50000, 90),
'访客数': np.random.randint(1000, 5000, 90),
'转化率': np.random.uniform(0.02, 0.08, 90)
}, index=dates)
# 计算衍生指标
df['客单价'] = df['销售额'] / df['订单数']
df['日均销售额'] = df['销售额'].rolling(window=7).mean()
# 创建综合报告
fig = plt.figure(figsize=(18, 12))
gs = fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3)
# 1. 销售额趋势(大图)
ax1 = fig.add_subplot(gs[0, :2])
df['销售额'].plot(ax=ax1, kind='line', color='#2E86AB', linewidth=2)
df['日均销售额'].plot(ax=ax1, kind='line', color='#A23B72', linewidth=2, linestyle='--')
ax1.set_title('销售额趋势分析', fontsize=14, fontweight='bold')
ax1.set_ylabel('销售额(元)')
ax1.legend(['日销售额', '7日均线'])
ax1.grid(True, alpha=0.3)
# 2. 订单数分布
ax2 = fig.add_subplot(gs[0, 2])
df['订单数'].plot(ax=ax2, kind='hist', bins=20, color='#06A77D', alpha=0.7, edgecolor='black')
ax2.set_title('订单数分布', fontsize=14, fontweight='bold')
ax2.set_xlabel('订单数')
ax2.set_ylabel('频数')
ax2.grid(True, alpha=0.3, axis='y')
# 3. 转化率趋势
ax3 = fig.add_subplot(gs[1, 0])
df['转化率'].plot(ax=ax3, kind='line', color='#F18F01', linewidth=2)
ax3.set_title('转化率趋势', fontsize=14, fontweight='bold')
ax3.set_ylabel('转化率')
ax3.grid(True, alpha=0.3)
# 4. 客单价分析
ax4 = fig.add_subplot(gs[1, 1])
df['客单价'].plot(ax=ax4, kind='box', color='#C73E1D')
ax4.set_title('客单价分布', fontsize=14, fontweight='bold')
ax4.set_ylabel('客单价(元)')
ax4.grid(True, alpha=0.3, axis='y')
# 5. 访客数与销售额关系
ax5 = fig.add_subplot(gs[1, 2])
df.plot(ax=ax5, kind='scatter', x='访客数', y='销售额', alpha=0.6, color='#6A4C93')
ax5.set_title('访客数与销售额关系', fontsize=14, fontweight='bold')
ax5.set_xlabel('访客数')
ax5.set_ylabel('销售额(元)')
ax5.grid(True, alpha=0.3)
# 6. 周汇总数据
ax6 = fig.add_subplot(gs[2, :])
weekly = df.resample('W').agg({
'订单数': 'sum',
'销售额': 'sum',
'访客数': 'sum'
})
weekly['转化率'] = (weekly['订单数'] / weekly['访客数'] * 100).round(2)
weekly[['订单数', '销售额', '访客数']].plot(ax=ax6, kind='bar', width=0.8)
ax6.set_title('周汇总数据', fontsize=14, fontweight='bold')
ax6.set_xlabel('周')
ax6.set_ylabel('数值')
ax6.legend(loc='upper left')
ax6.tick_params(axis='x', rotation=45)
ax6.grid(True, alpha=0.3, axis='y')
plt.suptitle('电商数据分析综合报告', fontsize=20, fontweight='bold', y=0.995)
plt.show()
运行测试:
# 复制以下代码到 Python 解释器运行
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建简单示例数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=30, freq='D')
df = pd.DataFrame({
'销售额': np.random.randint(10000, 50000, 30),
'订单数': np.random.randint(50, 200, 30)
}, index=dates)
# 创建子图
fig, axes = plt.subplots(2, 1, figsize=(12, 10))
# 销售额趋势
df['销售额'].plot(ax=axes[0], kind='line', color='blue', linewidth=2, marker='o')
axes[0].set_title('销售额趋势', fontsize=14, fontweight='bold')
axes[0].set_ylabel('销售额(元)')
axes[0].grid(True, alpha=0.3)
# 订单数柱状图
df['订单数'].plot(ax=axes[1], kind='bar', color='green', alpha=0.7)
axes[1].set_title('订单数', fontsize=14, fontweight='bold')
axes[1].set_ylabel('订单数')
axes[1].tick_params(axis='x', rotation=45)
axes[1].grid(True, alpha=0.3, axis='y')
plt.suptitle('销售数据分析', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
总结
通过本教程,我们系统地学习了 Pandas 图形绘制的各个方面:
- 基础绘图:Series 和 DataFrame 的基本绘图方法
- 常用图表类型:线图、柱状图、直方图、箱线图、散点图、饼图、面积图
- 高级技巧:子图、图表美化、自定义样式
- 实际应用:销售数据分析、股票分析、用户行为分析
- 常见问题:中文显示、图表保存、颜色自定义、大数据处理
关键要点:
- Pandas 绘图基于 Matplotlib,但提供了更简洁的接口
plot()方法是核心,通过kind参数选择图表类型- DataFrame 可以同时绘制多列数据
- 合理使用子图可以创建综合的数据分析报告
下一步学习:
- Matplotlib 高级功能:更精细的图表控制
- Seaborn:基于 Matplotlib 的统计可视化库
- Plotly:交互式图表库
- Bokeh:Web 交互式可视化
记住:数据可视化是数据分析的重要工具,多实践才能掌握!