如何在Python中绘制Y轴为线性刻度、条形填充按10的量级分组的对数堆叠柱状图
如何用Python复现按克隆频率量级分组的堆叠柱状图?
我来帮你搞定这个堆叠柱状图的复现问题——从你描述的需求来看,核心是要按样本独立划分克隆频率的量级组,再绘制堆叠占比图,这和你之前尝试的直接分组统计确实有区别。咱们先理清楚问题,再一步步给出解决方案。
需求回顾
你需要实现的堆叠柱状图满足以下要求:
- Y轴采用线性刻度(0-100%),展示克隆频率的占比总和
- 每个样本的堆叠条内部按克隆频率的10量级分组:前10个最高频率克隆为一组,接下来100个为一组,再接下来1000个为一组,以此类推
- 不同组用不同颜色区分(比如前10组用红色),用来直观判断样本是否存在大规模克隆扩增
数据说明
你拥有包含数千条克隆细胞信息的数据集,核心字段包括:
Strain、Sample、cloneID:标识符字段cloneFraction:每个克隆的频率值(最终要转化为占比)
已尝试的代码及问题
你之前写的代码如下:
import matplotlib import matplotlib.pyplot as plt import matplotlib.ticker as mtick %matplotlib inline MYDATAFRAME.groupby(['Sample','cloneFraction']).size().groupby(level=0).apply(lambda x: 100 * x / x.sum()).unstack().plot(kind='bar',stacked=True, legend=None) plt.yscale('log') plt.gca().yaxis.set_major_formatter(mtick.PercentFormatter()) plt.show()
但遇到了三个关键问题:
- 堆叠顺序不符合要求:条形按数据集条目顺序堆叠,未按频率从高到低排列
- 对数刻度下Y轴无法正确显示百分比格式(次要问题,其实你需求是线性刻度,这个可以直接调整)
- 核心问题:无法按样本独立划分10/100/1000的量级分组,只能全局筛选,而非每个样本各自分组
解决方案思路及代码示例
咱们分两步走:先处理数据,按样本分组并划分频率量级;再绘制堆叠柱状图。
步骤1:数据预处理(核心)
我们需要对每个样本单独处理:
- 按
Sample分组,对每个样本的cloneFraction降序排序 - 为每个克隆分配所属的量级组(比如"Top 10"、"11-110"、"111-1110"等)
- 计算每个样本内,各量级组的总频率占比
代码如下:
import pandas as pd import matplotlib.pyplot as plt import matplotlib.ticker as mtick # 假设你的数据集叫df,先确保cloneFraction是数值类型 df = MYDATAFRAME.copy() df['cloneFraction'] = pd.to_numeric(df['cloneFraction']) # 定义分组函数:对单个样本的克隆按频率降序后,划分量级组 def assign_group(clone_series): # 按频率降序排序 sorted_clones = clone_series.sort_values(ascending=False).reset_index(drop=True) # 为每个克隆分配组标签 groups = [] for idx in sorted_clones.index: if idx < 10: groups.append('Top 10') elif idx < 10+100: groups.append('11-110') elif idx < 10+100+1000: groups.append('111-1110') else: groups.append('>1110') # 剩下的克隆归为一组 sorted_clones = sorted_clones.to_frame('cloneFraction') sorted_clones['group'] = groups # 计算每组的总占比(转化为百分比) group_sum = sorted_clones.groupby('group')['cloneFraction'].sum() * 100 return group_sum # 按Sample分组应用函数,得到每个样本的各组占比 grouped_data = df.groupby('Sample').apply(assign_group).unstack(fill_value=0) # 调整列的顺序,确保堆叠顺序是从高量级到低量级(Top10在最上面) grouped_data = grouped_data[['Top 10', '11-110', '111-1110', '>1110']]
步骤2:绘制堆叠柱状图
现在用处理好的数据绘图,设置颜色、Y轴格式等:
# 设置颜色,比如Top10用红色,其他组用深浅不同的灰色 colors = ['#e74c3c', '#95a5a6', '#bdc3c7', '#ecf0f1'] # 绘制堆叠柱状图 ax = grouped_data.plot(kind='bar', stacked=True, color=colors, figsize=(12, 6), legend=True) # 设置Y轴为线性刻度,显示百分比 ax.yaxis.set_major_formatter(mtick.PercentFormatter()) ax.set_ylim(0, 100) # 固定Y轴范围0-100% # 添加标题和标签 plt.title('Clone Expansion by Frequency Groups per Sample', fontsize=14) plt.xlabel('Sample', fontsize=12) plt.ylabel('Total Clone Fraction (%)', fontsize=12) plt.legend(title='Clone Frequency Groups', bbox_to_anchor=(1.05, 1), loc='upper left') # 调整布局,防止图例被截断 plt.tight_layout() plt.show()
关键问题的解决说明
- 堆叠顺序问题:通过
grouped_data的列顺序指定,确保"Top 10"组在最上方(堆叠顺序是列的顺序,先出现的列在最下面,后出现的在上面,如果你想Top10在最下面,调整列顺序即可) - Y轴百分比格式:用线性刻度直接配合
mtick.PercentFormatter(),完美解决之前对数刻度的问题 - 按样本独立分组:通过
groupby('Sample').apply(assign_group)实现每个样本单独排序、分组,完全满足你“每个样本各自的前10个及后续量级分组”的需求
内容的提问来源于stack exchange,提问作者Kroky
相关产品推荐
相关产品推荐

