第十三章

Matplotlib 库

Python数据可视化的基石

欢迎关注微信公众号

coder程 查令十街84号

目录

环境配置与基础概念

# 安装
pip install matplotlib numpy pandas

# Jupyter 中显示图形
import matplotlib.pyplot as plt
%matplotlib inline       # Jupyter Notebook
%matplotlib widget       # JupyterLab(交互式)

# 脚本中显示
plt.show()               # 显示图形窗口

Matplotlib 架构层次

两种编程风格: pyplot (MATLAB风格,快速绘图)和 面向对象 (显式控制Figure/Axes,推荐用于复杂图形)。

Matplotlib 基础 — 折线图

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

# ========== pyplot 风格 ==========
plt.plot(x, y1, label='sin(x)', color='blue', linestyle='-')
plt.plot(x, y2, label='cos(x)', color='red', linestyle='--')
plt.xlabel('X轴')
plt.ylabel('Y轴')
plt.title('正弦与余弦函数')
plt.legend()           # 显示图例
plt.grid(True)       # 显示网格
plt.show()

# ========== 面向对象风格(推荐) ==========
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, y1, label='sin(x)', color='blue')
ax.plot(x, y2, label='cos(x)', color='red')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_title('正弦与余弦函数')
ax.legend()
ax.grid(True)
plt.show()

常用图表类型(一)

散点图 scatter

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
x = np.random.rand(50)
y = np.random.rand(50)
colors = np.random.rand(50)
sizes = 1000 * np.random.rand(50)

fig, ax = plt.subplots()
ax.scatter(x, y, c=colors, s=sizes,
           alpha=0.5, cmap='viridis')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_title('散点图')
plt.show()

柱状图 bar

categories = ['A', 'B', 'C', 'D']
values = [23, 45, 56, 78]

fig, ax = plt.subplots()
bars = ax.bar(categories, values,
              color=['red', 'green', 'blue', 'orange'],
              edgecolor='black')

# 在柱子上添加数值标签
for bar in bars:
    height = bar.get_height()
    ax.annotate(f'{height}',
        xy=(bar.get_x() + bar.get_width() / 2, height),
        xytext=(0, 3), textcoords="offset points",
        ha='center', va='bottom')

ax.set_ylabel('数值')
ax.set_title('柱状图')
plt.show()

常用图表类型(二)

直方图 hist

import matplotlib.pyplot as plt
import numpy as np

data = np.random.randn(1000)

fig, ax = plt.subplots()
ax.hist(data, bins=30, color='skyblue',
        edgecolor='black', alpha=0.7)
ax.set_xlabel('数值')
ax.set_ylabel('频数')
ax.set_title('直方图')

# 添加密度曲线
from scipy import stats
xmin, xmax = ax.get_xlim()
x = np.linspace(xmin, xmax, 100)
p = stats.norm.pdf(x, 0, 1)
ax.plot(x, p * 1000 * 30 / (2*xmax), 'r-')
plt.show()

饼图 pie

sizes = [30, 25, 20, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
explode = (0.1, 0, 0, 0, 0)

fig, ax = plt.subplots()
ax.pie(sizes, explode=explode, labels=labels,
       autopct='%1.1f%%', startangle=90,
       shadow=True)
ax.set_title('饼图')
plt.show()

# 箱线图 boxplot
data = [np.random.normal(0, std, 100)
        for std in range(1, 5)]
fig, ax = plt.subplots()
ax.boxplot(data)
ax.set_title('箱线图')
plt.show()

子图与布局

import matplotlib.pyplot as plt
import numpy as np

# ========== 方式1:subplots 创建多子图 ==========
fig, axes = plt.subplots(2, 2, figsize=(10, 8))   # 2行2列

x = np.linspace(0, 10, 100)
axes[0, 0].plot(x, np.sin(x))
axes[0, 0].set_title('sin(x)')

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

axes[1, 0].plot(x, np.tan(x))
axes[1, 0].set_title('tan(x)')

axes[1, 1].plot(x, np.exp(-x))
axes[1, 1].set_title('exp(-x)')

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

# ========== 方式2:subplot 逐个添加 ==========
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)       # 1行2列,第1个
plt.plot(x, np.sin(x))
plt.subplot(1, 2, 2)       # 1行2列,第2个
plt.plot(x, np.cos(x))
plt.show()

图表美化进阶

import matplotlib.pyplot as plt
import matplotlib as mpl

# 全局样式设置
plt.style.use('seaborn-v0_8-whitegrid')   # 内置样式
mpl.rcParams['font.family'] = 'SimHei'     # 中文字体
mpl.rcParams['axes.unicode_minus'] = False  # 负号正常显示

# 颜色与标记
fig, ax = plt.subplots()
ax.plot(x, y1, color='#FF6B6B', linewidth=2,
        marker='o', markersize=6, markerfacecolor='white')

# 自定义刻度
ax.set_xticks([0, np.pi, 2*np.pi])
ax.set_xticklabels(['0', r'$\pi$', r'$2\pi$'])

# 添加注释
ax.annotate('最大值', xy=(np.pi/2, 1),
            xytext=(np.pi/2 + 1, 0.5),
            arrowprops=dict(arrowstyle='->', color='red'))

# 设置坐标轴范围
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1.5, 1.5)

# 保存图片
fig.savefig('plot.png', dpi=300, bbox_inches='tight')
plt.show()

Seaborn 库

Seaborn 是基于 Matplotlib 的高级统计可视化库,内置美观的默认样式,一行代码即可生成复杂统计图。

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# 设置主题
sns.set_theme(style='whitegrid')   # darkgrid, white, ticks

# 示例数据
df = pd.DataFrame({
    'x': np.random.randn(100),
    'y': np.random.randn(100),
    'category': np.random.choice(['A', 'B', 'C'], 100),
    'size': np.random.rand(100)
})

# 快速统计图
sns.scatterplot(data=df, x='x', y='y', hue='category', size='size')
plt.show()

# 箱线图
sns.boxplot(data=df, x='category', y='y', palette='Set2')
plt.show()

# 热力图
corr = df[['x', 'y', 'size']].corr()
sns.heatmap(corr, annot=True, cmap='coolwarm', fmt='.2f')
plt.show()

Seaborn 高级图表

分布图

# 核密度估计图
sns.kdeplot(data=df, x='x', hue='category')

# 直方图+密度
sns.histplot(data=df, x='x', kde=True)

# 小提琴图
sns.violinplot(data=df, x='category', y='y')

# 配对图(多变量关系)
sns.pairplot(df, hue='category')

关系图与回归

# 带回归线的散点图
sns.regplot(data=df, x='x', y='y')

# 分面网格
g = sns.FacetGrid(df, col='category')
g.map(sns.histplot, 'x')

# 联合分布图
sns.jointplot(data=df, x='x', y='y', kind='scatter')
# kind: scatter, kde, hex, reg, resid

# 条形图(带误差线)
sns.barplot(data=df, x='category', y='y')
Seaborn 精髓: 几乎所有函数都支持 data + 列名参数,自动处理数据框; hue 参数按类别分组着色,是Seaborn最强大的特性。

Pandas 绘图 API

Pandas DataFrame/Series 内置了 .plot() 方法,底层调用 Matplotlib,实现「数据→图形」的一步直达。

import pandas as pd
import numpy as np

# 创建时间序列数据
dates = pd.date_range('2024-01-01', periods=100)
df = pd.DataFrame({
    'A': np.cumsum(np.random.randn(100)),
    'B': np.cumsum(np.random.randn(100)),
    'C': np.random.rand(100) * 100
}, index=dates)

# 1. DataFrame.plot() — 折线图(默认)
df.plot(figsize=(10, 5), title='时间序列')

# 2. 指定图表类型
df.plot(kind='bar')       # 柱状图
df.plot(kind='hist')      # 直方图
df.plot(kind='scatter', x='A', y='B')   # 散点图
df.plot(kind='box')       # 箱线图
df.plot(kind='pie', y='C')  # 饼图

# 3. 子图布局
df.plot(subplots=True, layout=(3, 1), figsize=(10, 10))

# 4. Series 直接绘图
df['A'].plot(kind='area', alpha=0.5)

综合绘图示例

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

# 准备数据
np.random.seed(42)
df = pd.DataFrame({
    'month': pd.date_range('2024-01', periods=12, freq='M'),
    'sales': np.random.randint(100, 500, 12),
    'profit': np.random.randint(20, 100, 12),
    'region': ['North', 'South', 'East', 'West'] * 3
})

# 组合图:折线+柱状
fig, ax1 = plt.subplots(figsize=(10, 5))
ax1.bar(df['month'].dt.month, df['sales'],
        color='skyblue', label='Sales')
ax1.set_xlabel('Month')
ax1.set_ylabel('Sales', color='blue')

ax2 = ax1.twinx()   # 共享X轴
ax2.plot(df['month'].dt.month, df['profit'],
         color='red', marker='o', label='Profit')
ax2.set_ylabel('Profit', color='red')

fig.legend(loc='upper left')
plt.title('月度销售与利润')
plt.show()

本章总结

可视化是数据科学最后也是最关键的一步——让数据开口说话。

下一章 ▶