当前位置:首页>python>Python 语言顶刊绘图复现 —— 云雨图

Python 语言顶刊绘图复现 —— 云雨图

  • 2026-09-09 17:54:53
Python 语言顶刊绘图复现 —— 云雨图

本期分享:

云雨图 (RainCloud)

求点赞

求分享

求喜欢

点击关注上方“翔的学术日记”,选择加"星标"置顶重磅干货,第一时间送达!也可后台留言私信我后续希望更新的内容!


绘图结果
代码讲解
1. 数据要求
这里我们需要通过Pandas库读取每组样本数据,如我们有一个Excel表格,那么第一行就是组名,之后每一行代表每个样本值,下面我们用numpy库模拟一个DataFrame数据
import pandas as pdimport numpy as npnp.random.seed(42)group1 = np.random.normal(5, 1.5, 120)group2 = np.random.normal(7, 2.0, 100)group3 = np.random.exponential(2, 140) + 3# 构造 DataFrame(允许不同长度,自动补 NaN)df = pd.concat([    pd.Series(group1, name="Control"),    pd.Series(group2, name="Treatment A"),    pd.Series(group3, name="Treatment B")], axis=1)print(df.shape)  # (140, 3) —— 行数 = 最长数组长度print(df.head())
2. 读取数据并初始化
这里我们将df数据每一列进行展开,展开成为1维向量数据:
  # 标准化输入数据    if isinstance(data, (list, tuple)):        features = [np.asarray(d).ravel() for d in data]    else:        features = [data[col].dropna().values for col in data.columns]    n_groups = len(features)    positions = np.arange(n_groups) * 0.8 + 1.0
3. 创建画布并定义随机数种子
# 创建图形    if ax is None:        if figsize is not None:            fig, ax = plt.subplots(figsize=figsize, dpi=100)        else:            w = width / 100 if width else 6            h = height / 100 if height else 4            fig, ax = plt.subplots(figsize=(w, h), dpi=100)    else:        fig = ax.figure    rng = np.random.default_rng(42)
4. 绘制散点图、箱型图以及小提琴图
  # 存储每组小提琴在Y轴上的最大值(用于显著性线定位)    violin_ymax_list = []    # 绘制每个组    for idx, feat in enumerate(features):        if len(feat) == 0:            violin_ymax_list.append(0)            continue        pos = positions[idx]        color = colors[idx % len(colors)]        current_ymax = feat.max()        # 绘制半小提琴(右侧)        if show_violin:            kde = gaussian_kde(feat)            margin = 0.1 * (feat.max() - feat.min()) if feat.max() != feat.min() else 0.1            x_range = np.linspace(feat.min() - margin, feat.max() + margin, 200)            current_ymax = x_range.max()            y_density = kde(x_range)            y_norm = y_density / y_density.max()            profile = violin_width * y_norm            # 填充右侧半小提琴            ax.fill_betweenx(x_range, pos, pos + profile,                             facecolor=color, alpha=0.24, edgecolor=color, linewidth=1.0)        violin_ymax_list.append(current_ymax)        # 绘制原始点(左侧,带抖动)        if show_points:            jitter = rng.uniform(-points_jitter, points_jitter, len(feat))            scatter_color = mcolors.to_rgba(darken_color(color), alpha=points_alpha)            ax.scatter(pos + point_offset + jitter, feat,                       s=points_size**2, color=scatter_color, marker='o', zorder=3)        # 绘制箱线图(居中)        if show_box:            bp = ax.boxplot([feat], patch_artist=True, widths=0.14, positions=[pos], vert=True)            box = bp["boxes"][0]            box.set_facecolor('white')            box.set_edgecolor('black')            box.set_linewidth(1.0)            for line in bp["whiskers"] + bp["caps"] + bp["medians"]:                line.set_color('black')                line.set_linewidth(1.0)
5. 显著性文字标注
# 显著性标记    if significance_pairs is not None:        line_height = 0.2        delta_h = 0        # 若有小提琴数据,用其最大值;否则回退到原始数据最大值        if violin_ymax_list and max(violin_ymax_list) > 0:            global_violin_ymax = max(violin_ymax_list)        else:            global_violin_ymax = max([max(f) for f in features if len(f) > 0])        for x1, x2, sig_text in significance_pairs:            y_top = global_violin_ymax + line_height * 2 + delta_h            # 绘制横线: ┌───┐            ax.plot([positions[x1], positions[x1], positions[x2], positions[x2]],                    [y_top - line_height, y_top, y_top, y_top - line_height],                    lw=1.5, c='black')            # 添加文本            ax.text((positions[x1] + positions[x2]) / 2, y_top + line_height * 0.2,                    sig_text, ha='center', va='bottom',                    color='black', fontsize=12, fontweight='bold')            delta_h += 0.5    # 设置坐标轴(仅 vertical)    ax.set_xticks(positions)    ax.set_xticklabels(category_names or [f"Group {i+1}" for i in range(n_groups)])    ax.set_xlim(positions[0] - 0.4, positions[-1] + 0.5)    # Y 轴范围:从最小值到显著性线顶部    y_min = min([min(f) for f in features if len(f) > 0])    y_max = (global_violin_ymax + line_height * 2 + delta_h - 0.5 + line_height * 0.2 + 1) \            if significance_pairs else (max(violin_ymax_list) if violin_ymax_list else max([max(f) for f in features if len(f) > 0]))    ax.set_ylim(y_min - 1, y_max + 0.5)    ax.set_ylabel("Value")    ax.set_xlabel("")    if title:        ax.figure.suptitle(title, y=1.06)    ax.grid(True, axis='y', linestyle=':', alpha=0.5)    fig.tight_layout()    return fig
注:上述代码已经全部打包,后期会将集成公众号更多数据分析代码和可视化代码进行整理并进一步更新打包!

求点赞

求分享

求喜欢

商务合作、代码咨询、论文指导请私信联系!

#Python可视化 #云雨图 #统计 #分布图绘制

点“阅读原文”下载文章源代码

最新文章

随机文章