KF-gins输出结果绘图指南:从k-mer频谱到热图
2026/9/16 10:48:25 网站建设 项目流程

我之前处理一批细菌基因组测序数据时,跑完KF-gins流程后生成了几十个结果文件,包括k-mer频数表、样本聚类结果、序列注释信息等。真正耗时不是跑分析,而是把这些结果整理成答辩PPT里的图。如果你也卡在这一步,这篇文章应该能帮你省下不少时间。

不管你是第一次接触KF-gins的输出文件,还是已经跑过很多次但每次画图都很痛苦,这篇文章都适用。我会从输出格式讲起,分析每类文件适合的可视化类型,再给出具体的绘图步骤和代码,最后分享几个科研绘图容易翻车的细节。KF-gins作为以k-mer频率分析为核心的基因组评估工具,它的输出结果绘图是分析流程中承上启下的关键一环——数据算完只是第一步,把结果变成让人一眼看懂的图,才算真正闭环。

1. KF-gins输出的文件长什么样:每种结果对应的图表类型

1.1 从分析流程到输出文件:先弄清楚手里有什么数据

KF-gins这个名字拆开看,核心是围绕k-mer频率做统计和评估。实际跑完一次分析后,工作目录下会多出几类文件,我按用途把它们分成四组:

文件/文件组数据格式包含内容典型用途
kmer_freq.txt两列数值(深度、频数)k-mer深度与对应频数的分布关系判断基因组大小、杂合度、测序深度是否正常
summary.txt指标名+数值基因组大小估计、杂合度、重复序列比例等多样本对比、方法学评估、写入论文表格
distance_matrix.txt矩阵样本间的距离/相似度数值聚类分析、样本关系探究
classification.txt序列名+分类标签每条代表性序列的物种/组别归属计算各分类的占比,绘制构成图

这四类文件看起来都是平平无奇的文本表格,但它们的可视化路径完全不同。kmer_freq.txt是典型的坐标型数据,天然适合折线图;distance_matrix.txt是矩阵型数据,热图是最直观的表达;summary.txt是指标型数据,条形图、箱线图、雷达图都能用;classification.txt则是计数型数据,堆积柱状图或饼图是常规选择。

说一个我自己的经验:拿到输出文件第一件事不是急着画图,而是先用head看一眼文件结构和规模。KF-gins生成的kmer_freq.txt可能会导致行数特别多,尤其当测序深度高时,深度值的跨度可能到几百甚至上千。提前确认数据规模,后面选择绘图策略才不会踩坑。

1.2 输出文件与可视化形式的匹配关系

先放一张映射表,后面每个场景分别展开:

输出文件推荐图表为什么是它慎用图表
kmer_freq.txt折线图/面积图,必要时双对数坐标连续坐标型数据,折线能直观展示分布形状柱状图(低频端太密集,高频端太稀疏)
summary.txt条形图、箱线图、表格离散指标对比,柱形高度差一眼可见折线图(指标间没有连续关系)
distance_matrix.txt热图+层次聚类树矩阵数值用颜色映射最直观,聚类树展示层级关系散点图(丢失了矩阵的结构信息)
classification.txt堆积柱状图、百分比堆叠柱状图展示各组构成及比例变化三维饼图(视觉误导严重,专业场合不推荐)

这里单独提醒一句:饼图能不用就不用,尤其是分类超过5类时,人的视觉很难比较相近角度的扇形大小。KF-gins输出的序列分类结果往往有十几个甚至几十个分类,堆积柱状图或百分比堆叠柱状图明显更适合,还方便在柱子上标注具体数量。

2. 绘图工具怎么选:脚本、点鼠标和自带脚本的取舍

2.1 为什么我不建议直接用KF-gins自带绘图

KF-gins或类似工具通常自带一些绘图脚本或辅助命令,能够快速渲染出结果图。这种图用来做什么?用我的话说是"跑完流程瞄一眼,确认分析没崩"。

但我不建议把自带图直接搬进论文或汇报。原因很现实:

  • 自带脚本的参数被写死在代码里,字体、字号、配色、坐标轴标签往往用的是默认风格,和期刊/答辩模板很难匹配;
  • 分辨率不足,导出图片格式也经常是png或jpg,放大后边缘模糊,达不到投稿的300dpi要求;
  • 无法批量定制。多个样本的summary比较、距离矩阵的聚类树,自带脚本通常只能单文件出图,手工工作量巨大。

不是说自带脚本一无是处。它在流程跑完时快速验证结果是否合理的场景下非常有用。我的习惯是:跑完KF-gins先看自带图,确认数据和预期一致,再进入正式绘图环节。

2.2 Python、R、Origin三条路线的横向对比

抛开自带工具,我身边做生信和基因组研究的人,绘图基本集中在三条路线:Python系、R系、Origin/GraphPad系。我列一个实际对比:

对比维度Python(matplotlib/seaborn)R(ggplot2/pheatmap)Origin / GraphPad
上手难度中等,需写代码但生态完善中等,统计功能强低,交互点击即可
热图绘制seaborn一行调用,灵活度高pheatmap/ComplexHeatmap功能细需手动配置矩阵,较繁琐
批量处理多组输出脚本循环一次搞定脚本循环一次搞定手工操作为主,效率低
图表定制程度极高,几乎可改任意元素极高一般
输出格式PDF/SVG/TIFF/PNGPDF/SVG/TIFF/PNG常见格式都有,但部分功能收费

我的选择建议很直接:

  • 已经有R/Python基础的,直接用你熟悉的语言,不用折腾新工具;
  • 完全不写代码、只偶尔画图的,Origin可以,但要能接受后期手动调整;
  • 需要一次性处理几十个样本的KF-gins结果、还要复现的,老老实实用脚本。

个人经验是Python路线最顺。pandas读表格几乎是全自动的,KF-gins输出的tab分隔文件直接read_csv就能变成DataFrame,再交给matplotlib绘图,数据清洗和可视化是一条流水线。R的ggplot2渲染图形更精美,但如果你对R不熟,临时学数据操作的语法反而是额外负担。

还有人提到用Qt或Canvas画布做自定义可视化界面,这个方向适合要做成一个可交互软件工具的情况。如果只是给自己的分析结果出图,没必要绕这么大一圈——脚本出图是最高效的路径。

3. 三类核心输出的绘图实操:从数据到成图

3.1 k-mer频数分布曲线:一张图看出基因组特征

k-mer频数分布曲线是KF-gins最经典的可视化结果。横坐标是k-mer深度,纵坐标是该深度下出现的k-mer种类数(频数)。通过曲线的峰值位置和形状,可以初步判断基因组大小、杂合度以及是否存在重复序列。

第一步是读取数据并观察基本情况:

import pandas as pd df = pd.read_csv("kmer_freq.txt", sep="\t", header=None, names=["depth", "count"]) df = df[(df["depth"] > 0) & (df["count"] > 0)] print(df.head()) print(df.describe())

这里我做了两项过滤:去掉深度为0的行,去掉频数为0的行。深度为0没有生物学意义,频数为0的深度区间是数据稀疏区,直接把行删掉可以让后续分布曲线更干净。

第二步就是画主图。KF-gins的k-mer深度跨度通常很大,从1到几百甚至上千,直接线性的横轴会让低频端挤成一团。我建议用双对数坐标:

import matplotlib.pyplot as plt import numpy as np fig, ax = plt.subplots(figsize=(8, 5)) ax.plot(df["depth"], df["count"], lw=1.5, color="#2b6ea2", label="K-mer spectrum") ax.set_xscale("log") ax.set_yscale("log") ax.set_xlabel("K-mer depth (log)") ax.set_ylabel("Frequency (log)") ax.legend(frameon=False) fig.tight_layout() fig.savefig("kmer_spectrum.pdf", dpi=300)

画出来后,你会看到两种典型形状:

  • 单峰曲线:基因组比较纯合,只有一个明显的主峰;
  • 双峰曲线:在较浅深度位置出现一个副峰,在较深位置出现主峰,这是杂合基因组的典型信号。副峰对应的k-mer来自杂合位点的两条不同等位基因,主峰则来自纯合区段。

如果你想把summary.txt里估计的基因组大小直接标注在图上,可以加一行文本注释:

ax.text(0.6, 0.9, f"Genome size: {genome_size:.1f} Mb", transform=ax.transAxes, ha="center")

这里的transform=ax.transAxes让文字位置相对于坐标轴比例,而不是数据坐标,这样不管横纵轴范围怎么变,注释都固定在图右上方,不会跑出绘图区域。

有一个细节要注意:如果频数表有几十万行,matplotlib画线时逐点连接会很慢。这时候可以先对深度做聚合,只保留每个整数值对应的最大频数,或者直接折线图不用散点,能大大减少渲染时间。

3.2 样本间距离矩阵热图:关系一眼看清

KF-gins如果做的是多样本模式,会输出一个样本之间的distance_matrix.txt。这个矩阵的行和列都是样本名,数值表示两个样本间的距离或差异程度。可视化的首选方案是热图加层次聚类树。

读取并绘图:

import pandas as pd import seaborn as sns import matplotlib.pyplot as plt dist = pd.read_csv("distance_matrix.txt", sep="\t", index_col=0) g = sns.clustermap(dist, cmap="vlag", method="average", figsize=(8, 8)) g.savefig("sample_distance_heatmap.png", dpi=300)

sns.clustermap做的事情比普通heatmap多一步:它会对行和列分别做层次聚类,并按聚类结果重新排列样本顺序,这样关系近的样本会聚在一起,热图上会自然出现"方块状"结构,比你手动排序直观得多。

色彩映射方面,我推荐vlagRdBu_r这类双色发散型色带。它们用两种对比色表示高低两个方向,适合距离矩阵这种数值有正负或大小两极的数据。慎用jet这类彩虹色带,颜色过渡不自然,且对色盲读者不友好。

使用热图之前,有几点值得检查的:

  • 矩阵是否为对称矩阵?理论上样本i和样本j的距离等于样本j和样本i的距离,如果你发现矩阵明显不对称,说明数据格式可能有问题;
  • 索引列是否正常读入?index_col=0这行参数就是告诉pandas第一列是行名,不加的话样本名称会变成数字序号,整个图会莫名其妙地变成纯数值标签;
  • 样本数量特别多(比如超过50个)时,热图格子会变得非常小,可以适当放宽画布尺寸,或者考虑省略聚类树,改用纯热图配合横纵坐标标签。

3.3 多样本统计摘要的组合图表:汇报和文章都够用

KF-gins的summary.txt在单样本时只是一个文本文件,但当你跑了几十个样本(比如多种处理条件、多个重复),把它们的summary汇总成一张图,才有真正的对比价值。

汇总多个文件:

import glob import pandas as pd frames = [] for f in glob.glob("*/summary.txt"): sample = f.split("/")[0] s = pd.read_csv(f, sep="\t", index_col=0) s.columns = [sample] frames.append(s) summary = pd.concat(frames, axis=1).T

这段代码会把每个子目录下的summary.txt读进来,用目录名作为样本名,最终拼成一个"样本x指标"的宽表。

有了汇总表,画图就有很多选择。如果你关心的是基因组大小估计,直接画条形图:

fig, ax = plt.subplots(figsize=(10, 5)) summary["Genome_size"].plot(kind="bar", ax=ax, color="#4c9caf") ax.set_ylabel("Genome size (Mb)") ax.set_xticklabels(summary.index, rotation=45, ha="right") plt.tight_layout()

如果每个处理组有多个重复,条形图就体现不出组内波动了。这时应该用箱线图加散点叠加:

import seaborn as sns fig, ax = plt.subplots(figsize=(8, 5)) sns.boxplot(data=summary, x="Group", y="Genome_size", ax=ax) sns.stripplot(data=summary, x="Group", y="Genome_size", color="black", size=4, jitter=0.1, ax=ax)

箱线图展示中位数和四分位范围,散点把每个样本的实际数值标上去,组间差异和组内重复性都能看出来。

汇报场景中,我倾向于把多个指标放进同一张图里,用分面或子图排列。比如左边基因组大小,中间杂合度,右边重复序列比例。matplotlib的subplots可以做到:

fig, axes = plt.subplots(1, 3, figsize=(15, 5)) metrics = ["Genome_size", "Heterozygosity", "Repeat_proportion"] for ax, metric in zip(axes, metrics): summary[metric].plot(kind="bar", ax=ax, color="#4c9caf") ax.set_title(metric, fontsize=11) plt.tight_layout()

三个子图用统一风格,看起来整洁,信息密度也高。

4. 科研绘图最容易翻车的几个细节

4.1 中文显示、字体统一与投稿要求

用matplotlib绘图,最经典的问题之一就是中文乱码。默认字体里没有中文字形,你plt.title传入中文标题,出来就是一个个方框。

推荐的做法有两种:

第一种是设置全局字体:

plt.rcParams["font.sans-serif"] = ["SimHei", "Arial", "DejaVu Sans"] plt.rcParams["axes.unicode_minus"] = False

第二种更省事也最保险:图表里全部用英文标签,中文说明放在图注或PPT正文里。这不是偷懒,很多SCI期刊其实明确建议图表使用英文,能避免字体嵌入问题,也能让图片在不同电脑上打开时不会因为缺少字体而显示异常。

如果你在Linux服务器上跑分析,系统没有SimHei、SimSun这类中文字体,就算设置了font.sans-serif也没用。我遇到这种情况时的做法是:字体设置为DejaVu Sans,这个字体在绝大多数Linux环境自带的matplotlib里可用,如果一定要中文,需要自己上传字体文件并手动注册。

4.2 分辨率、尺寸和格式导出

投稿和汇报要求的图格式不同,我一般这样处理:

使用场景推荐格式推荐DPI
期刊投稿PDF/SVG(矢量)或TIFF300~600
答辩PPTPDF转成高清PNG,或直接SVG150~300
内部快速查看PNG100~150

如果用fig.savefig("result.png", dpi=300)保存位图,要注意位图分辨率是固定死的,图片被拉大后会模糊。矢量格式不存在这个问题,建议首选PDF或SVG。很多期刊最终的排版系统其实也接受矢量图,投稿阶段先提交PDF,录用后再按编辑部要求转格式。

图片尺寸方面,期刊通常有单栏和双栏的区分。单栏图宽在8~9cm,双栏图在17~18cm。你可以用fig.set_size_inches(3.5, 2.5)控制宽高,3.5英寸大约就是8.9厘米,对应单栏宽度。

导出的时候加上bbox_inches="tight"

fig.savefig("result.pdf", dpi=300, bbox_inches="tight")

这个参数会自动裁剪图上多余的空白边距,让图片内容撑满画布,不会出现四周大片白边。

4.3 大表格绘图卡顿的应对策略

KF-gins的kmer_freq.txt在深度较大时可能有百万级行数,直接用pandas读取再plot,内存会吃紧,画图也会非常卡。

我的处理方案:

  1. 读取时只取需要的列,用usecols=[0, 1]
  2. 对数据进行降采样,深度列保留整数值,每个深度值取最大频数,或者间隔抽样;
  3. 画图时用linewidth=0.8之类的细线,避免过粗线条掩盖数据密度;
  4. 先画一个低分辨率版本快速看趋势,确认没问题后再出高清PDF。

还要注意,如果深度值本身是浮点数,数据中可能存在微小误差导致同一位点被分到不同深度上。绘图前最好取整:

df["depth"] = df["depth"].round().astype(int) df = df.groupby("depth", as_index=False)["count"].sum()

这样做的原因是k-mer深度理论上应该是整数,取整可以消除误差累积造成的假性波动。合并同一深度的频数后,曲线会显得平滑很多,也更接近真实分布。

4.4 配色与坐标轴细节:让图更专业

配色影响图的观感,也影响信息的准确传达。我常用的几个原则:

  • 同一篇文章里所有图统一配色风格,不要每张图一个色系;
  • 色盲友好:用Okabe-Ito配色或seaborn的colorblind调色板;
  • 热图用双色发散色带,条形图用同色系深浅变化,避免用高饱和的纯红纯绿;
  • 用颜色编码分类时,控制类别数在8个以内,超过8个就换用纹理/形状区分。

坐标轴方面,细节决定专业度。去掉上框线和右框线,图会干净不少:

ax.spines["top"].set_visible(False) ax.spines["right"].set_visible(False)

坐标轴刻度标签如果太密,可以用MaxNLocator控制刻度数量:

import matplotlib.ticker as ticker ax.yaxis.set_major_locator(ticker.MaxNLocator(nbins=5))

这点在k-mer深度轴上特别实用,因为深度跨度大,默认刻度可能挤成一团,限制刻度数量后图面会清爽很多。

最后提醒一句:保存成PDF之前,务必检查图中的文字有没有被截断。matplotlib的tight_layout和bbox_inches="tight"能解决大部分问题,但偶尔还是会出现图例超出画布的情况。养成出图前plt.show()预览一下的习惯,比事后返工省时间。这个习惯在我处理KF-gins大批量样本时特别重要,脚本跑完还要手动核对图的内容和标注位置,确认无误再统一导出,能省下不少修图时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询