Python中DataFrame差异基因高亮及Excel样式保存问题咨询
问题说明
我的DataFrame包含19列,以下仅保留关键列说明需求:
Gene_name:存储大肠杆菌的基因列表Genes_in_same_transcription_unit:存储同启动子下的基因,条目以逗号+空格分隔(示例:pphA, sdsR)
需要找出Genes_in_same_transcription_unit中未出现在Gene_name里的基因,将其设置为红色字体高亮,以此快速判断操纵子受影响的位置(首基因、中间或末尾)。
目前代码能在Jupyter Notebook中生成带高亮效果的Highlighted_Genes列,但保存为Excel时样式丢失,现有代码如下:
# Convert Gene_name column to a set for quick lookup gene_set = set(df['Gene_name'].dropna()) # Drop NaNs from Gene_name to avoid issues # Function to highlight genes def highlight_genes(row): genes_str = row['Genes_in_same_transcription_unit'] # Handle NaN or missing values if pd.isna(genes_str): return None # Keep NaNs as is genes_list = genes_str.split(', ') # Split into list # Add asterisks to genes NOT in the Gene_name column highlighted_list = [f"*{gene}*" if gene not in gene_set else gene for gene in genes_list] return ', '.join(highlighted_list) # Join back into string # Apply function df['Highlighted_Genes'] = df.apply(highlight_genes, axis=1) # Function to highlight words inside asterisks def highlight_genes(val): if not isinstance(val, str): # Ensure it's a string return val # Return as is (preserves NaN or other values) def replace_func(match): return f'<span style="color: red;">{match.group(1)}</span>' # Replace text between * * with a red-colored span tag highlighted_text = re.sub(r'\*(.*?)\*', replace_func, val) return highlighted_text # Apply the function using Styler df_styled = df.style.format({'Highlighted_Genes': lambda x: highlight_genes(x)}) # Display in Jupyter Notebook df_styled df_styled.to_excel('highlighted_genes.xlsx')
问题原因
Pandas的Styler.to_excel()不支持HTML格式的样式渲染,只会把<span>这类标签当作普通文本写入Excel,导致样式丢失。要在Excel中实现单元格内部分文本的高亮,需要直接操作Excel的富文本格式,而非依赖HTML。
解决方案
使用openpyxl库直接生成带富文本格式的Excel文件,以下是两种实现方式:
方式1:基于预处理标记列生成高亮
先标记需要高亮的基因,再写入Excel时设置对应字体颜色:
import pandas as pd import openpyxl from openpyxl.styles import Font from openpyxl.utils.dataframe import dataframe_to_rows from openpyxl.cell.text import InlinePatternedText, TextBlock # 初始化基因集合用于快速查询 gene_set = set(df['Gene_name'].dropna()) # 生成标记列,存储(基因名, 是否需要高亮)的列表 def mark_target_genes(row): genes_str = row['Genes_in_same_transcription_unit'] if pd.isna(genes_str): return None genes_list = genes_str.split(', ') return [(gene, gene not in gene_set) for gene in genes_list] df['Highlighted_Genes'] = df.apply(mark_target_genes, axis=1) # 创建Excel工作簿 wb = openpyxl.Workbook() ws = wb.active # 写入表头和数据行 for r_idx, row in enumerate(dataframe_to_rows(df, index=False, header=True), 1): for c_idx, val in enumerate(row, 1): cell = ws.cell(row=r_idx, column=c_idx, value=val) # 跳过表头,只处理Highlighted_Genes列 if r_idx == 1 or c_idx != df.columns.get_loc('Highlighted_Genes') + 1: continue if val is None: continue # 清空单元格默认值,准备写入富文本 cell.value = None parts = [] for i, (gene, need_highlight) in enumerate(val): if i > 0: # 添加分隔符 parts.append(InlinePatternedText(text=', ', font=Font())) # 设置字体颜色:红色高亮/默认黑色 font = Font(color="FF0000") if need_highlight else Font() parts.append(InlinePatternedText(text=gene, font=font)) cell._value = TextBlock(parts=parts) # 保存文件 wb.save('highlighted_genes.xlsx')
方式2:直接处理原始列(无需额外标记列)
直接读取原始列数据,写入Excel时动态判断并设置高亮:
import pandas as pd import openpyxl from openpyxl.styles import Font from openpyxl.cell.text import InlinePatternedText, TextBlock # 初始化基因集合 gene_set = set(df['Gene_name'].dropna()) # 创建Excel工作簿 wb = openpyxl.Workbook() ws = wb.active # 写入表头 ws.append(df.columns.tolist()) # 写入数据行并设置高亮 for _, row in df.iterrows(): ws.append(row.tolist()) current_row = ws.max_row # 获取目标列的单元格索引(根据你的列位置调整) target_col_idx = df.columns.get_loc('Genes_in_same_transcription_unit') + 1 cell = ws.cell(row=current_row, column=target_col_idx) genes_str = cell.value if pd.isna(genes_str): continue # 清空单元格默认值 cell.value = None parts = [] genes_list = genes_str.split(', ') for i, gene in enumerate(genes_list): if i > 0: parts.append(InlinePatternedText(text=', ', font=Font())) # 判断是否需要高亮 font = Font(color="FF0000") if gene not in gene_set else Font() parts.append(InlinePatternedText(text=gene, font=font)) cell._value = TextBlock(parts=parts) # 保存文件 wb.save('highlighted_genes.xlsx')
运行上述代码后,Excel文件中目标列内不在Gene_name中的基因会显示为红色,样式完全保留。
内容的提问来源于stack exchange,提问作者Melissa Arroyo-Mendoza
相关产品推荐
相关产品推荐

