生信绘图-Matplotlib绘制云雨图(小提琴图+箱线图+散点)
本文介绍了使用Python的Matplotlib库绘制云雨图(Raincloud Plot)的方法。云雨图结合了半小提琴图(展示数据分布)、箱线图(显示统计摘要)和抖动散点图(呈现原始数据),能全面展示数据的分布特征、集中趋势和离散程度。文章详细讲解了环境准备、数据生成、图形绘制(包括配色、透明度设置和布局调整)等步骤,并提供了完整代码示例。该可视化方法克服了传统箱线图和小提琴图的局限性,适用于需
引言
在数据可视化中,如何全面展示一组数据的分布特征、集中趋势、离散程度以及原始数据点,往往是分析人员面临的挑战。传统的箱线图可以展示五数概括(最小值、下四分位数、中位数、上四分位数、最大值)和异常值,但它会隐藏数据的多峰分布等细节。小提琴图结合了箱线图和核密度估计,能展示分布的形态,但有时也会掩盖原始数据点的位置。
云雨图(Raincloud Plot) 应运而生,它通过组合半小提琴图(分布)、箱线图(统计摘要)和散点图(原始数据),在一张图中同时呈现数据的全面信息。本文将手把手教你使用 Python 的 Matplotlib 库,绘制一张美观且信息量丰富的云雨图。
1. 环境准备
首先需要安装必要的库:
pip install numpy pandas matplotlib
若需要使用中文字体,请确保系统中存在相应字体(如“Heiti TC”),或替换为其他中文字体。
2. 代码结构与核心思路
我们最终要实现的效果如下:
- 小提琴图:半透明显示数据的分布形状(完整小提琴,但通过低透明度避免遮挡)。
- 箱线图:展示中位数、四分位数、均值等统计量,并添加缺口(notch)以比较中位数差异。
- 散点图:将所有数据点以抖动的方式绘制在箱线图左侧,避免重叠。
下面分步解析代码。
3. 完整代码及详解
3.1 导入库与用户配置
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# ======================
# 用户配置
# ======================
read_custom_data = False # True=读取本地 data.csv;False=生成示例随机数据
# 配色(线色与填充色一一对应)
colors = ["#4f7942", "#c65f0a", "#a03530", "#5e4c8c", "#20648a"]
fill_colors = ["#b0d1a6", "#f5c5a0", "#e7a39a", "#b1a5c9", "#a0d8ef"]
# 设置中文字体,防止乱码
plt.rcParams['font.sans-serif'] = ['Heiti TC']
plt.rcParams['axes.unicode_minus'] = False
- read_custom_data 控制数据来源:True 时从本地 data.csv 读取,False 时生成示例随机数据。
- colors 和 fill_colors 分别定义了每个类别的线条颜色和填充颜色,两者一一对应,确保配色协调。
- 字体设置是为了正确显示中文标签,您可根据操作系统修改字体名(如 ‘SimHei’、‘Microsoft YaHei’)。
3.2 数据准备
if read_custom_data:
data_df = pd.read_csv("data.csv")
else:
np.random.seed(42)
data = {
'A': np.random.normal(10, 2, 100),
'B': np.random.normal(15, 3, 100),
'C': np.random.normal(8, 1.5, 100),
'D': np.random.normal(12, 2.5, 100),
'E': np.random.normal(20, 4, 100)
}
data_df = pd.DataFrame(data)
# 防御:颜色数要与列数匹配
if len(colors) < data_df.shape[1] or len(fill_colors) < data_df.shape[1]:
raise ValueError("颜色数量与数据列数量不匹配,请补齐 colors / fill_colors。")
这里生成了五组正态分布数据,分别标记为 A~E。实际使用时,只需将 CSV 文件放置在相同目录下,文件格式为:第一行列名,后续行数值(允许不同列长度不一致,空值会被自动忽略)。
3.3 创建画布与循环绘图
fig, ax = plt.subplots(figsize=(10, 6))
x_labels = list(data_df.columns)
n_groups = len(x_labels)
for i, col in enumerate(x_labels):
values = data_df[col].dropna().values # 移除缺失值
pos = i + 1 # 每组的位置
- figsize=(10,6) 设置画布大小。
- x_labels 为列名列表,用作横轴标签。
- 循环遍历每一列数据,pos 决定该组在横轴上的位置(从 1 开始)。
3.3.1 绘制小提琴图
vp = ax.violinplot(values, positions=[pos], vert=True, widths=0.7,
showmeans=False, showmedians=False, points=100)
body = vp['bodies'][0]
body.set_facecolor(fill_colors[i])
body.set_edgecolor(colors[i])
body.set_alpha(0.2)
body.set_linewidth(2)
- violinplot 绘制完整小提琴,widths=0.7 控制宽度,points=100 提高密度曲线的平滑度。
- 通过 set_facecolor 和 set_edgecolor 应用自定义颜色,set_alpha(0.2) 设置透明度,使背后的箱线和散点清晰可见。
3.3.2 绘制箱线图
box = ax.boxplot(values, positions=[pos], vert=True, widths=0.2,
patch_artist=True, showmeans=True, meanline=True,
notch=True,
medianprops=dict(color=colors[i], linewidth=2),
whiskerprops=dict(color=colors[i], linewidth=1.5),
capprops=dict(color=colors[i], linewidth=1.5),
boxprops=dict(facecolor=fill_colors[i], edgecolor=colors[i], linewidth=2),
meanprops=dict(color=colors[i], linewidth=2),
flierprops=dict(marker='None')) # 不显示自动离群点
- widths=0.2 让箱线图比小提琴窄,避免视觉混乱。
- patch_artist=True 使箱体可填充颜色;showmeans=True 显示均值线;notch=True 添加缺口,用于比较中位数。
- 各 props 参数分别设置中位数线、须线、箱体边框、均值线等的颜色与线宽。
- flierprops=dict(marker=‘None’) 隐藏自动离群点,因为我们会手动绘制所有点。
3.3.3 绘制散点图(抖动)
jitter_strength = 0.1
base_x = pos - 0.2 # 向左偏移
x_jitter = base_x + np.random.uniform(-jitter_strength, jitter_strength, size=len(values))
ax.scatter(x_jitter, values,
s=30, # 点大小
c=fill_colors[i], edgecolors=colors[i], linewidth=1.5,
alpha=0.8, zorder=3)
- 为了模拟 Plotly 中 pointpos=-2.0 的效果,我们将散点的基准位置向左偏移 0.2(base_x = pos - 0.2)。
- 添加均匀随机抖动(jitter_strength=0.1),避免点重叠。
点的填充色使用 fill_colors,边框色使用 colors,并设置透明度 alpha=0.8 和图层顺序 zorder=3 确保点在箱线图之上。
3.4 布局美化
ax.set_xticks(range(1, n_groups + 1))
ax.set_xticklabels(x_labels, fontsize=12)
ax.set_ylabel("Y值", fontsize=12)
ax.grid(axis='y', linestyle='--', alpha=0.6)
ax.set_xlim(0.5, n_groups + 0.5)
ax.set_title("云雨图", fontsize=14)
plt.tight_layout()
- 设置横轴刻度与标签,纵轴标签。
- 添加水平虚线网格,便于阅读数值。
- set_xlim 适当扩展横轴范围,使图形不紧贴边界。
- tight_layout() 自动调整布局,防止标签被裁剪。
3.5 保存与显示
plt.savefig("云雨图.png", dpi=300, bbox_inches='tight')
plt.savefig('云雨图.pdf', bbox_inches='tight') # 矢量图格式
plt.show()
- 同时输出高分辨率 PNG 和矢量 PDF 格式,方便后续使用。
4. 效果展示
运行上述代码(read_custom_data=False),将生成如下图所示的云雨图:
图中每组数据包含:
- 半透明小提琴:直观显示数据分布形态,可观察到是否多峰、偏态等。
- 箱线图:箱体代表 IQR,中线为中位数,缺口表示中位数的置信区间,绿色菱形为均值(均值线)。
- 散点:所有原始数据点以抖动方式分布在左侧,既保留了个案信息,又避免了重叠。
结语
本文详细介绍了如何使用 Matplotlib 绘制包含小提琴图、箱线图和散点图的云雨图。通过组合这三种图形,我们能够在一张图中同时呈现数据的分布、统计摘要和原始观测值,是探索性数据分析的有力工具。您可以根据自己的数据调整颜色、尺寸等参数,打造个性化的图表。
更多推荐
所有评论(0)