You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ggplot2:如何绘制嵌套结构的拆分小提琴图?

实现拆分小提琴图的颜色配对调整

我明白你的需求啦——要在A、B两组的拆分1/拆分2下,把浅蓝色+深蓝色做成一个拆分小提琴的左右半区,浅绿色+深绿色做成另一个拆分小提琴,同时保留嵌套的分组结构。下面我用Python的Seaborn库给你写一套可直接复用的代码,一步步帮你实现:

第一步:准备数据集(模拟你的真实数据结构)

首先假设你的数据集有这几列:Group(A/B)、Split(拆分1/拆分2)、SubGroup(四个颜色分组)、Count(数值)。我先构造一个模拟数据集,你直接替换成自己的数据就行:

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

# 构造模拟数据(替换成你的真实数据集)
np.random.seed(42)
groups = ['A', 'B']
splits = ['拆分1', '拆分2']
subgroups = ['浅蓝色', '深蓝色', '浅绿色', '深绿色']

data = []
for group in groups:
    for split in splits:
        for sub in subgroups:
            # 生成模拟Count值(如果要对数刻度,后面可以直接设置y轴为log)
            count = np.random.lognormal(mean=3, sigma=0.5, size=50)
            data.extend([{'Group': group, 'Split': split, 'SubGroup': sub, 'Count': c} for c in count])

df = pd.DataFrame(data)

第二步:添加辅助分组列

为了让Seaborn识别出哪两个颜色属于同一个拆分小提琴,我们需要新增两个辅助列:

  • Pair:把四个颜色分成两对(蓝组/绿组)
  • Half:标记每对里的颜色是左半区还是右半区
# 配对分组:浅蓝+深蓝=蓝组,浅绿+深绿=绿组
df['Pair'] = df['SubGroup'].map({
    '浅蓝色': '蓝组',
    '深蓝色': '蓝组',
    '浅绿色': '绿组',
    '深绿色': '绿组'
})

# 标记半区:浅蓝/浅绿是左,深蓝/深绿是右
df['Half'] = df['SubGroup'].map({
    '浅蓝色': '左',
    '深蓝色': '右',
    '浅绿色': '左',
    '深绿色': '右'
})

第三步:绘制拆分小提琴图(两种布局可选)

布局1:按Group分栏,按Pair分行

这种布局会把A、B组放在左右两个子图,蓝组、绿组放在上下两个子图,结构清晰:

sns.set_style("whitegrid")

# 创建绘图网格
g = sns.catplot(
    data=df,
    x="Split",          # x轴是拆分1/拆分2
    y="Count",          # y轴是Count值
    hue="Half",         # 按半区分颜色
    split=True,         # 启用拆分小提琴模式
    col="Group",        # 按A/B组分栏
    row="Pair",         # 按蓝组/绿组分行
    kind="violin",
    # 先设置蓝组的颜色
    palette={'左': '#87CEEB', '右': '#1E90FF'}
)

# 手动修改绿组的颜色(因为默认palette会统一应用,单独调整第二行)
for ax in g.axes[1]:
    for patch in ax.collections:
        if patch.get_label() == '左':
            patch.set_facecolor('#90EE90')  # 浅绿色
        elif patch.get_label() == '右':
            patch.set_facecolor('#228B22')  # 深绿色

# 设置标签和标题
g.set_axis_labels("拆分类型", "Count(对数刻度可自行开启)")
g.set_titles(col_template="组 {col_name}", row_template="{row_name}")

# 如果需要对数刻度,取消下面的注释
# for ax in g.axes.flat:
#     ax.set_yscale('log')

plt.tight_layout()
plt.show()

布局2:同一子图内展示所有拆分组合

如果你想把同一个Group下的拆分1/拆分2和蓝组/绿组都放在同一个子图里,可以把SplitPair合并成x轴:

# 合并拆分类型和配对组作为x轴
df['Split_Pair'] = df['Split'] + '_' + df['Pair']

g = sns.catplot(
    data=df,
    x="Split_Pair",
    y="Count",
    hue="Half",
    split=True,
    col="Group",
    kind="violin",
    palette={'左': '#87CEEB', '右': '#1E90FF'}
)

# 调整绿组的颜色(每个子图里的第2、4个小提琴是绿组)
for ax in g.axes.flat:
    for i, patch in enumerate(ax.collections):
        if i in [1, 3]:
            if patch.get_label() == '左':
                patch.set_facecolor('#90EE90')
            elif patch.get_label() == '右':
                patch.set_facecolor('#228B22')

g.set_axis_labels("拆分类型_配对组", "Count")
plt.tight_layout()
plt.show()

关键说明

  • 颜色代码你可以根据自己的需求替换成更精准的色值
  • 对数刻度只需要取消代码里的注释,设置ax.set_yscale('log')即可
  • 如果你的真实数据结构和模拟数据有差异,只需要调整辅助列的映射关系就行

内容的提问来源于stack exchange,提问作者user3236841

火山引擎 最新活动