11.2 Matplotlib 数据可视化教程


文章目录

  • 前言
  • 一、简介与安装
  • [二、 基础绘图框架](#二、 基础绘图框架)
  • [三、 折线图(Line Plot)](#三、 折线图(Line Plot))
    • [3.1 基本折线图](#3.1 基本折线图)
    • [3.2 多线对比折线图](#3.2 多线对比折线图)
    • [3.3 子图布局](#3.3 子图布局)
  • [四、 散点图(Scatter Plot)](#四、 散点图(Scatter Plot))
  • [五、 直方图(Histogram)](#五、 直方图(Histogram))
  • [六、 柱状图(Bar Chart)](#六、 柱状图(Bar Chart))
    • [6.1 分组柱状图](#6.1 分组柱状图)
    • [6.2 堆叠柱状图](#6.2 堆叠柱状图)
  • [七、饼图(Pie Chart)](#七、饼图(Pie Chart))
  • [八、 专业技巧与最佳实践](#八、 专业技巧与最佳实践)
    • [8.1 解决中文显示问题](#8.1 解决中文显示问题)
    • [8.2 图表样式定制](#8.2 图表样式定制)
    • [8.3 保存高质量图表](#8.3 保存高质量图表)
    • [8.4 交互式功能](#8.4 交互式功能)
  • [九、 实用工具函数](#九、 实用工具函数)
  • [十、 学习资源推荐](#十、 学习资源推荐)
  • 总结

前言

本文介绍了Python数据可视化库Matplotlib的基础使用方法。主要内容包括:1) Matplotlib的安装方法及核心特性,支持专业级可视化与高度定制;2) 基础绘图框架,展示如何创建图表、设置属性和添加网格线;3) 折线图的绘制方法,包括单线图、多线对比图和子图布局;4) 散点图的应用,通过示例展示如何可视化变量关系并计算相关系数。文章提供了丰富的代码示例,涵盖图表装饰、多子图布局等实用技巧,适合数据分析人员快速掌握Matplotlib的核心功能。


一、简介与安装

Matplotlib 是 Python 生态系统中功能最全面的绘图库之一,它提供了丰富的绘图工具,能够创建高质量的折线图、散点图、柱状图、饼图等多种统计图表。该库通常与 NumPy 协同工作,构成科学计算和数据分析的核心工具链。

主要特性:

专业级可视化:支持出版物级别的图表输出

高度可定制:从图表样式到元素细节均可精细调整

多平台支持:可在 Jupyter Notebook、独立脚本和 Web 应用中使用

广泛兼容:与 Pandas、Seaborn 等数据分析库无缝集成

安装方法:

python 复制代码
bash
# 基础安装
pip install matplotlib

# 通过科学计算发行版安装(推荐)
conda install matplotlib  # 适用于 Anaconda/Miniconda 用户

二、 基础绘图框架

Matplotlib 采用分层设计,主要包含以下组件:

python 复制代码
python
import matplotlib.pyplot as plt
import numpy as np

# 创建图表和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))

# 设置图表属性
ax.set_title('图表标题', fontsize=16, pad=20)
ax.set_xlabel('X轴标签', fontsize=12)
ax.set_ylabel('Y轴标签', fontsize=12)

# 添加网格线
ax.grid(True, alpha=0.3, linestyle='--')

# 显示图表
plt.tight_layout()
plt.show()

三、 折线图(Line Plot)

折线图适用于展示数据随时间或其他连续变量的变化趋势。

3.1 基本折线图

python 复制代码
python
# 单线折线图示例
x = np.arange(1, 13)  # 1月至12月
y = [23, 25, 22, 28, 30, 32, 35, 33, 29, 26, 24, 22]  # 月平均温度

plt.figure(figsize=(12, 6))

# 创建折线图
plt.plot(x, y, 
         marker='o',           # 数据点标记
         markersize=8,         # 标记大小
         linewidth=2,          # 线宽
         color='#3498db',      # 颜色(十六进制)
         linestyle='-',        # 线型
         label='2023年温度')

# 图表装饰
plt.title('月平均温度变化趋势', fontsize=16, fontweight='bold')
plt.xlabel('月份', fontsize=12)
plt.ylabel('温度 (°C)', fontsize=12)

# 设置刻度
plt.xticks(x, ['1月', '2月', '3月', '4月', '5月', '6月', 
               '7月', '8月', '9月', '10月', '11月', '12月'])
plt.yticks(range(20, 38, 2))

# 添加图例
plt.legend(loc='upper left', fontsize=11)

# 添加数据标签
for xi, yi in zip(x, y):
    plt.text(xi, yi + 0.5, f'{yi}°', ha='center', va='bottom', fontsize=10)

plt.tight_layout()
plt.show()

3.2 多线对比折线图

python 复制代码
python
# 多线对比示例:历年温度对比
years = np.arange(2020, 2024)
months = np.arange(1, 13)

# 生成示例数据
np.random.seed(42)
temperatures = {
    2020: np.random.normal(25, 5, 12),
    2021: np.random.normal(26, 4, 12),
    2022: np.random.normal(27, 3, 12),
    2023: np.random.normal(26.5, 3.5, 12)
}

plt.figure(figsize=(14, 8))

# 定义颜色和线型
colors = ['#e74c3c', '#3498db', '#2ecc71', '#9b59b6']
linestyles = ['-', '--', '-.', ':']

# 绘制多条折线
for i, (year, temps) in enumerate(temperatures.items()):
    plt.plot(months, temps, 
             marker='o',
             markersize=6,
             linewidth=2,
             color=colors[i],
             linestyle=linestyles[i],
             label=f'{year}年',
             alpha=0.8)

# 图表设置
plt.title('历年月平均温度对比', fontsize=18, fontweight='bold', pad=20)
plt.xlabel('月份', fontsize=14)
plt.ylabel('平均温度 (°C)', fontsize=14)

# 月份标签
month_labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 
                'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
plt.xticks(months, month_labels, rotation=45)

# 添加网格和图例
plt.grid(True, alpha=0.2, linestyle='--')
plt.legend(loc='upper left', fontsize=12, framealpha=0.9)

plt.tight_layout()
plt.show()

3.3 子图布局

python 复制代码
python
# 多子图示例
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle('数据可视化子图示例', fontsize=20, fontweight='bold', y=1.02)

# 生成数据
x = np.linspace(0, 10, 100)

# 子图1:线性关系
axes[0, 0].plot(x, 2*x + 3, 'b-', linewidth=2)
axes[0, 0].set_title('线性函数', fontsize=14)
axes[0, 0].set_xlabel('x')
axes[0, 0].set_ylabel('y = 2x + 3')
axes[0, 0].grid(True, alpha=0.3)

# 子图2:正弦函数
axes[0, 1].plot(x, np.sin(x), 'r--', linewidth=2)
axes[0, 1].set_title('正弦函数', fontsize=14)
axes[0, 1].set_xlabel('x')
axes[0, 1].set_ylabel('sin(x)')
axes[0, 1].grid(True, alpha=0.3)

# 子图3:指数函数
axes[1, 0].plot(x, np.exp(x/3), 'g-.', linewidth=2)
axes[1, 0].set_title('指数函数', fontsize=14)
axes[1, 0].set_xlabel('x')
axes[1, 0].set_ylabel('exp(x/3)')
axes[1, 0].set_yscale('log')
axes[1, 0].grid(True, alpha=0.3)

# 子图4:二次函数
axes[1, 1].plot(x, x**2 - 5*x + 6, 'm:', linewidth=2)
axes[1, 1].set_title('二次函数', fontsize=14)
axes[1, 1].set_xlabel('x')
axes[1, 1].set_ylabel('x² - 5x + 6')
axes[1, 1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

四、 散点图(Scatter Plot)

散点图用于展示两个变量之间的关系,常用于发现数据中的模式、异常值或相关性。

python 复制代码
python
# 散点图高级示例
np.random.seed(42)

# 生成模拟数据
n_points = 200
x1 = np.random.normal(50, 15, n_points)
y1 = 2 * x1 + np.random.normal(0, 20, n_points) + 30

x2 = np.random.normal(80, 12, n_points)
y2 = -1.5 * x2 + np.random.normal(0, 15, n_points) + 200

# 计算相关系数
corr1 = np.corrcoef(x1, y1)[0, 1]
corr2 = np.corrcoef(x2, y2)[0, 1]

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))

# 第一个散点图
scatter1 = ax1.scatter(x1, y1, 
                      c=y1,           # 颜色映射
                      cmap='viridis', # 色谱
                      s=80,           # 点大小
                      alpha=0.7,      # 透明度
                      edgecolors='w', # 边缘颜色
                      linewidth=0.5)

ax1.set_title(f'正相关数据集 (r = {corr1:.2f})', fontsize=14)
ax1.set_xlabel('变量 X', fontsize=12)
ax1.set_ylabel('变量 Y', fontsize=12)

# 添加颜色条
cbar1 = plt.colorbar(scatter1, ax=ax1)
cbar1.set_label('Y 值大小', fontsize=10)

# 第二个散点图
scatter2 = ax2.scatter(x2, y2, 
                      c=x2,           # 根据 x 值着色
                      cmap='plasma',
                      s=80,
                      alpha=0.7,
                      edgecolors='w',
                      linewidth=0.5)

ax2.set_title(f'负相关数据集 (r = {corr2:.2f})', fontsize=14)
ax2.set_xlabel('变量 X', fontsize=12)
ax2.set_ylabel('变量 Y', fontsize=12)

# 添加颜色条
cbar2 = plt.colorbar(scatter2, ax=ax2)
cbar2.set_label('X 值大小', fontsize=10)

# 添加趋势线
for ax, x_data, y_data in [(ax1, x1, y1), (ax2, x2, y2)]:
    z = np.polyfit(x_data, y_data, 1)
    p = np.poly1d(z)
    ax.plot(x_data, p(x_data), "r--", alpha=0.8, linewidth=2)

plt.tight_layout()
plt.show()

五、 直方图(Histogram)

直方图用于展示数据的分布情况,特别适合分析连续变量的频率分布。

python 复制代码
python
# 直方图高级示例
np.random.seed(42)

# 生成多组数据
data1 = np.random.normal(75, 10, 5000)  # 正态分布
data2 = np.random.exponential(20, 3000) + 50  # 指数分布
data3 = np.random.uniform(40, 100, 4000)  # 均匀分布

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 10))

# 子图1:叠加直方图
ax1.hist([data1, data2, data3],
         bins=50,
         color=['#3498db', '#e74c3c', '#2ecc71'],
         alpha=0.7,
         edgecolor='black',
         linewidth=0.5,
         label=['正态分布', '指数分布', '均匀分布'],
         density=True)  # 归一化为概率密度

ax1.set_title('不同分布数据对比', fontsize=16, fontweight='bold')
ax1.set_xlabel('数值', fontsize=12)
ax1.set_ylabel('概率密度', fontsize=12)
ax1.legend(fontsize=11)
ax1.grid(True, alpha=0.2)

# 添加统计信息
stats_text = f'''数据统计:
正态分布: μ={data1.mean():.1f}, σ={data1.std():.1f}
指数分布: λ={1/(data2.mean()-50):.3f}
均匀分布: [{data3.min():.1f}, {data3.max():.1f}]'''

ax1.text(0.02, 0.98, stats_text,
         transform=ax1.transAxes,
         fontsize=10,
         verticalalignment='top',
         bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))

# 子图2:累计分布直方图
counts1, bins1, patches1 = ax2.hist(data1,
                                   bins=50,
                                   color='skyblue',
                                   alpha=0.7,
                                   edgecolor='black',
                                   linewidth=0.5,
                                   cumulative=True,
                                   density=True,
                                   label='累计分布')

ax2.set_title('累计分布函数 (CDF)', fontsize=16, fontweight='bold')
ax2.set_xlabel('数值', fontsize=12)
ax2.set_ylabel('累计概率', fontsize=12)
ax2.grid(True, alpha=0.2)

# 添加分位数线
percentiles = [25, 50, 75, 95]
colors = ['red', 'orange', 'green', 'purple']

for p, color in zip(percentiles, colors):
    value = np.percentile(data1, p)
    ax2.axvline(x=value, color=color, linestyle='--', alpha=0.7, linewidth=1.5)
    ax2.text(value, 0.9, f'{p}%: {value:.1f}',
             rotation=90, fontsize=9, color=color,
             ha='right', va='top')

ax2.legend(fontsize=11)

plt.tight_layout()
plt.show()

六、 柱状图(Bar Chart)

柱状图用于比较不同类别之间的数值差异,特别适合展示离散数据。

6.1 分组柱状图

python 复制代码
python
# 分组柱状图示例:学生成绩对比
students = ['张三', '李四', '王五', '赵六', '孙七']
subjects = ['语文', '数学', '英语', '物理', '化学']

# 生成模拟成绩数据
np.random.seed(42)
scores = np.random.randint(60, 101, size=(len(students), len(subjects)))

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

# 设置柱状图参数
bar_width = 0.15
x_pos = np.arange(len(students))

# 不同颜色表示不同科目
colors = ['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6']

# 绘制分组柱状图
for i, (subject, color) in enumerate(zip(subjects, colors)):
    ax.bar(x_pos + i * bar_width,
           scores[:, i],
           width=bar_width,
           color=color,
           alpha=0.8,
           edgecolor='black',
           linewidth=0.5,
           label=subject)

# 图表设置
ax.set_title('学生各科成绩对比', fontsize=18, fontweight='bold', pad=20)
ax.set_xlabel('学生姓名', fontsize=14)
ax.set_ylabel('成绩', fontsize=14)
ax.set_xticks(x_pos + bar_width * (len(subjects) - 1) / 2)
ax.set_xticklabels(students, fontsize=12)
ax.set_ylim([50, 105])

# 添加网格和背景色
ax.grid(True, alpha=0.2, axis='y')
ax.set_axisbelow(True)  # 网格线在柱子下方

# 添加数据标签
for i in range(len(students)):
    for j in range(len(subjects)):
        height = scores[i, j]
        ax.text(x_pos[i] + j * bar_width,
                height + 0.5,
                str(height),
                ha='center',
                va='bottom',
                fontsize=10,
                fontweight='bold')

# 添加图例
ax.legend(title='科目', fontsize=11, title_fontsize=12, loc='upper left')

# 添加总分信息
total_scores = scores.sum(axis=1)
for i, total in enumerate(total_scores):
    ax.text(x_pos[i] + bar_width * (len(subjects) - 1) / 2,
            -5,
            f'总分: {total}',
            ha='center',
            va='top',
            fontsize=11,
            fontweight='bold',
            color='darkred')

plt.tight_layout()
plt.show()

6.2 堆叠柱状图

python 复制代码
python
# 堆叠柱状图示例:销售额构成
months = ['1月', '2月', '3月', '4月', '5月', '6月']
products = ['产品A', '产品B', '产品C', '产品D']

# 生成销售数据
np.random.seed(42)
sales_data = np.random.randint(20, 100, size=(len(months), len(products)))

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

# 定义颜色
colors = ['#3498db', '#e74c3c', '#2ecc71', '#f39c12']

# 绘制堆叠柱状图
bottom_values = np.zeros(len(months))

for i, (product, color) in enumerate(zip(products, colors)):
    ax.bar(months, sales_data[:, i],
           bottom=bottom_values,
           color=color,
           alpha=0.8,
           edgecolor='black',
           linewidth=0.5,
           label=product)
    bottom_values += sales_data[:, i]

# 图表设置
ax.set_title('各月销售额构成(堆叠柱状图)', fontsize=18, fontweight='bold', pad=20)
ax.set_xlabel('月份', fontsize=14)
ax.set_ylabel('销售额(万元)', fontsize=14)
ax.set_ylim([0, 320])

# 添加总数标签
for i, month in enumerate(months):
    total = sales_data[i].sum()
    ax.text(i, total + 5,
            f'合计: {total}',
            ha='center',
            va='bottom',
            fontsize=11,
            fontweight='bold')

# 添加百分比标签(可选)
for i, month in enumerate(months):
    current_bottom = 0
    for j in range(len(products)):
        value = sales_data[i, j]
        percentage = value / sales_data[i].sum() * 100
        if percentage > 10:  # 只显示较大的部分
            ax.text(i, current_bottom + value/2,
                    f'{percentage:.0f}%',
                    ha='center',
                    va='center',
                    fontsize=9,
                    fontweight='bold',
                    color='white')
        current_bottom += value

ax.legend(title='产品类别', fontsize=11, title_fontsize=12)
ax.grid(True, alpha=0.2, axis='y')
ax.set_axisbelow(True)

plt.tight_layout()
plt.show()

七、饼图(Pie Chart)

饼图用于展示各部分占整体的比例关系,适合表现百分比数据。

python 复制代码
python
# 饼图高级示例:市场份额分析
companies = ['Apple', 'Samsung', '华为', '小米', 'OPPO', 'Vivo', '其他']
market_share = [25.3, 19.2, 15.8, 12.5, 8.7, 7.9, 10.6]

# 颜色方案
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', 
          '#FFEAA7', '#DDA0DD', '#B2B2B2']

# 突出显示前两名
explode = [0.1 if i < 2 else 0 for i in range(len(companies))]

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8))

# 子图1:基础饼图
wedges1, texts1, autotexts1 = ax1.pie(market_share,
                                      explode=explode,
                                      labels=companies,
                                      colors=colors,
                                      autopct='%1.1f%%',
                                      startangle=90,
                                      shadow=True,
                                      textprops={'fontsize': 11})

# 美化百分比标签
for autotext in autotexts1:
    autotext.set_color('white')
    autotext.set_fontweight('bold')

ax1.set_title('全球智能手机市场份额', fontsize=16, fontweight='bold', pad=20)

# 子图2:环形图
wedges2, texts2, autotexts2 = ax2.pie(market_share,
                                      explode=explode,
                                      labels=companies,
                                      colors=colors,
                                      autopct='%1.1f%%',
                                      startangle=90,
                                      wedgeprops={'width': 0.4, 'edgecolor': 'w'})

# 转换为环形图
centre_circle = plt.Circle((0, 0), 0.25, color='white', linewidth=0)
ax2.add_artist(centre_circle)

# 添加中央文本
ax2.text(0, 0, '2023年\n市场分析',
         horizontalalignment='center',
         verticalalignment='center',
         fontsize=14,
         fontweight='bold')

ax2.set_title('市场份额环形图', fontsize=16, fontweight='bold', pad=20)

# 添加图例
fig.legend(wedges1, companies,
           title="品牌",
           loc="center right",
           fontsize=11,
           title_fontsize=12,
           bbox_to_anchor=(1.15, 0.5))

plt.tight_layout()
plt.show()

八、 专业技巧与最佳实践

8.1 解决中文显示问题

python 复制代码
python
# 方法1:使用系统字体
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']  # 设置中文字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 方法2:指定字体文件
import matplotlib
matplotlib.font_manager.fontManager.addfont('path/to/your/font.ttf')
font_name = matplotlib.font_manager.FontProperties(fname='path/to/your/font.ttf').get_name()
plt.rcParams['font.sans-serif'] = [font_name]

8.2 图表样式定制

python 复制代码
python
# 使用预定义样式
plt.style.use('seaborn-v0_8-darkgrid')  # 内置样式

# 自定义样式
plt.rcParams.update({
    'figure.figsize': (10, 6),
    'axes.titlesize': 16,
    'axes.labelsize': 12,
    'xtick.labelsize': 10,
    'ytick.labelsize': 10,
    'legend.fontsize': 11,
    'grid.alpha': 0.3,
    'lines.linewidth': 2,
    'lines.markersize': 8,
})

8.3 保存高质量图表

python 复制代码
python
# 保存图表
fig.savefig('chart.png', 
            dpi=300,          # 分辨率
            bbox_inches='tight',  # 紧凑布局
            facecolor='white',    # 背景色
            edgecolor='none',     # 边框颜色
            transparent=False)    # 透明度

8.4 交互式功能

python 复制代码
python
# 启用交互模式
plt.ion()  # 交互模式

# 创建可交互图表
fig, ax = plt.subplots()
line, = ax.plot([], [])

# 动态更新数据
def update_data(new_data):
    line.set_data(range(len(new_data)), new_data)
    ax.relim()
    ax.autoscale_view()
    fig.canvas.draw_idle()

# 关闭交互模式
plt.ioff()

九、 实用工具函数

python 复制代码
python
def create_dashboard(data_dict, figsize=(16, 12)):
    """创建综合数据仪表板"""
    fig = plt.figure(figsize=figsize)
    fig.suptitle('数据分析仪表板', fontsize=20, fontweight='bold')
    
    # 创建子图网格
    gs = fig.add_gridspec(3, 3)
    
    # 添加不同类型的图表
    ax1 = fig.add_subplot(gs[0, :2])  # 折线图
    ax2 = fig.add_subplot(gs[0, 2])   # 饼图
    ax3 = fig.add_subplot(gs[1, :])   # 柱状图
    ax4 = fig.add_subplot(gs[2, :])   # 散点图
    
    # 这里添加具体的绘图代码
    # ...
    
    plt.tight_layout()
    return fig

def annotate_chart(ax, annotations):
    """为图表添加批注"""
    for annotation in annotations:
        ax.annotate(annotation['text'],
                   xy=annotation['xy'],
                   xytext=annotation['xytext'],
                   arrowprops=dict(arrowstyle='->', color='gray'),
                   fontsize=10,
                   bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))

十、 学习资源推荐

官方文档:https://matplotlib.org/stable/contents.html

图库示例:https://matplotlib.org/stable/gallery/index.html

交互式教程:Jupyter Notebook + Matplotlib 练习

进阶学习:

Seaborn:基于 Matplotlib 的高级统计绘图

Plotly:交互式可视化

Bokeh:Web 交互式可视化


总结

Matplotlib 是一个功能强大且灵活的可视化工具,通过掌握上述技巧,您将能够创建专业级别的数据可视化图表,有效传达数据分析结果。建议从基础图表开始,逐步探索高级功能,最终形成自己的可视化风格和工作流程。

相关推荐
技术净胜2 小时前
Python 操作 Cookie 完全指南,爬虫与 Web 开发实战
前端·爬虫·python
海棠AI实验室2 小时前
第六章 日志体系:logging 让排错效率翻倍
python·logging
laufing2 小时前
flask_restx 创建restful api
python·flask·restful
程途拾光1582 小时前
中文界面跨职能泳道图制作教程 PC
大数据·论文阅读·人工智能·信息可视化·流程图
毕设源码-郭学长2 小时前
【开题答辩全过程】以 基于python电商商城系统为例,包含答辩的问题和答案
开发语言·python
black0moonlight2 小时前
win11 isaacsim 5.1.0 和lab配置
python
知乎的哥廷根数学学派3 小时前
基于多尺度注意力机制融合连续小波变换与原型网络的滚动轴承小样本故障诊断方法(Pytorch)
网络·人工智能·pytorch·python·深度学习·算法·机器学习
网安CILLE3 小时前
PHP四大输出语句
linux·开发语言·python·web安全·网络安全·系统安全·php