如何在循环绘制饼图时为相同类别指定固定颜色?
问题描述
需要针对不同条件(按qseqid分组)下的同一类别绘制饼图,要求同一类别在所有饼图中颜色保持一致(例如rhinovirus在所有饼图中颜色相同)。现有Python代码如下,如何实现该需求?
#!/usr/bin/env python3 import pandas as pd import numpy as np import matplotlib.pyplot as plt df = pd.read_csv('blast_results', sep='\t', names=['qseqid','sseqid','staxid','salltitles','length','pident','qstart','qend','sstart','send','qcovhsp','evalue','bitscore','qseq','sseq']) #divide column df[['sseqid', 'organism']] = df['sseqid'].str.split('|', 1, expand=True) df['organism'] = df['organism'].str.split(':').str.get(1).astype(str).str.lower() #add to salltitles the organism where not present df['salltitles'] = np.where(df['organism']!='human', df['organism'] + ' ' + df['salltitles'], df['salltitles']) # divide column df[['salltitles', 'strain','segment','host']] = df['salltitles'].str.split('|', 3, expand=True) # remove unused column df.drop(['organism','segment', 'staxid'], inplace=True, axis=1) primers = df['qseqid'].unique() for i in primers: print(i) subset = df[df['qseqid'] == i] subset[['salltitles', 'subtype']] = subset['salltitles'].str.split(' ', 1, expand=True) results = pd.DataFrame(subset.groupby('salltitles')['qseqid'].count()) results.reset_index(inplace=True) results.sort_values('salltitles', inplace=True) x = [0.05 for i in range(0, results.shape[0])] explode = tuple(x) plt.figure() plt.pie(results['qseqid'], labels=results['salltitles'], autopct='%.1f%%', colors = ['#98F5FF', 'coral','#A2CD5A','#FF1493','#FF6EB4'], explode=explode) plt.title(i)
解决方案
核心是创建固定的类别-颜色映射字典,让每个类别对应唯一颜色,绘制饼图时根据当前子集的类别从字典中提取对应颜色,步骤如下:
1. 提前生成全局类别-颜色映射
先处理所有数据,得到所有可能的salltitles类别,给每个分配固定颜色。可以用自定义颜色列表,也可以用matplotlib内置颜色循环:
# 先处理全量数据,提取所有唯一类别 df_full = df.copy() df_full[['salltitles', 'subtype']] = df_full['salltitles'].str.split(' ', 1, expand=True) all_categories = df_full['salltitles'].unique() # 自定义颜色列表(可根据实际类别数量补充) color_list = ['#98F5FF', 'coral','#A2CD5A','#FF1493','#FF6EB4', '#FFD700', '#8B4513', '#4169E1'] # 创建类别-颜色映射字典,类别数量超出自定义颜色时循环复用 category_color_map = {cat: color_list[i % len(color_list)] for i, cat in enumerate(all_categories)}
2. 修改循环内的饼图颜色调用
在循环绘制饼图时,根据当前results中的salltitles从映射字典中获取对应颜色,替换原代码中固定的colors参数:
plt.pie(results['qseqid'], labels=results['salltitles'], autopct='%.1f%%', colors=[category_color_map[cat] for cat in results['salltitles']], explode=explode)
完整修改后的代码
#!/usr/bin/env python3 import pandas as pd import numpy as np import matplotlib.pyplot as plt df = pd.read_csv('blast_results', sep='\t', names=['qseqid','sseqid','staxid','salltitles','length','pident','qstart','qend','sstart','send','qcovhsp','evalue','bitscore','qseq','sseq']) # 分割列 df[['sseqid', 'organism']] = df['sseqid'].str.split('|', 1, expand=True) df['organism'] = df['organism'].str.split(':').str.get(1).astype(str).str.lower() # 给非人类的salltitles添加organism前缀 df['salltitles'] = np.where(df['organism']!='human', df['organism'] + ' ' + df['salltitles'], df['salltitles']) # 分割列 df[['salltitles', 'strain','segment','host']] = df['salltitles'].str.split('|', 3, expand=True) # 删除无用列 df.drop(['organism','segment', 'staxid'], inplace=True, axis=1) # 提前生成全局类别-颜色映射 df_full = df.copy() df_full[['salltitles', 'subtype']] = df_full['salltitles'].str.split(' ', 1, expand=True) all_categories = df_full['salltitles'].unique() # 自定义颜色列表(可根据实际类别数量补充) color_list = ['#98F5FF', 'coral','#A2CD5A','#FF1493','#FF6EB4', '#FFD700', '#8B4513', '#4169E1'] category_color_map = {cat: color_list[i % len(color_list)] for i, cat in enumerate(all_categories)} primers = df['qseqid'].unique() for i in primers: print(i) subset = df[df['qseqid'] == i] subset[['salltitles', 'subtype']] = subset['salltitles'].str.split(' ', 1, expand=True) results = pd.DataFrame(subset.groupby('salltitles')['qseqid'].count()) results.reset_index(inplace=True) results.sort_values('salltitles', inplace=True) x = [0.05 for i in range(0, results.shape[0])] explode = tuple(x) plt.figure() plt.pie(results['qseqid'], labels=results['salltitles'], autopct='%.1f%%', colors=[category_color_map[cat] for cat in results['salltitles']], explode=explode) plt.title(i) plt.show()
说明
- 无论哪个
qseqid对应的饼图,同一个salltitles类别都会使用映射字典里的固定颜色 - 如果类别数量超过自定义颜色列表长度,会通过
i % len(color_list)循环复用颜色,也可以直接扩展color_list添加更多颜色
内容的提问来源于stack exchange,提问作者Denise Lavezzari
相关产品推荐
相关产品推荐

