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和蓝组/绿组都放在同一个子图里,可以把Split和Pair合并成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




