ETE 4 系统发育树可视化实战:SmartView 交互探索与 Qt 矢量渲染全指南
2026/9/11 18:48:32 网站建设 项目流程

ETE 4 系统发育树可视化实战:SmartView 交互探索与 Qt 矢量渲染全指南

【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills

本指南基于 scientific-agent-skills 仓库中 etetoolkit 技能 的 visualization.md 文档展开,系统讲解 ETE 4.4.0 的两套绘图系统——面向交互探索的SmartView与面向出版级矢量输出的Qt treeview。读完本文,你将掌握渲染器选型决策、SmartView 布局与 Faces 的编写方法、静态 PNG 截图、Qt 引擎输出 PNG/PDF/SVG 的完整流程,以及配套脚本 quick_visualize.py 的一键可视化用法。

两套绘图系统:SmartView 与 Qt treeview

ETE 4 提供了两套彼此独立的绘图系统,它们的定位、类层次与输出能力完全不同:

  • SmartView:基于 Web 的当前交互式浏览器与自适应渲染器,最适合交互式工作与超大型树的探索。相关类全部位于ete4.smartview命名空间下。
  • Qt treeview:保留的可选 Qt 渲染器,用于静态 PNG、PDF 与 SVG 输出。相关类位于ete4.treeview命名空间下。

关键约束:两套系统不能混用其布局(Layout)类与 Face 类——ete4.smartview下的类只供 SmartView 使用,ete4.treeview下的类只供 Qt 渲染使用。混用会导致ImportError或渲染异常。这一隔离也与仓库 quick_visualize.py 中 SmartView 布局与 Qt 样式构建函数 各自独立实现的源码结构一一对应。

渲染器决策:什么时候用哪一套?

文档给出了一条清晰的选型分界线,实际选择时按以下场景判断:

优先使用 SmartView,当你需要:

  • 交互式地探索、搜索、折叠或编辑树;
  • 在本机或通过 SSH 隧道服务一棵树;
  • 在长期存活的 Jupyter 内核中通过浏览器探索;
  • 生成光栅 PNG 截图;
  • 手动从浏览器下载当前视图为 SVG 或 PNG;
  • 处理一棵大到无法完全展开绘制的树。

使用 Qt treeview,当你要:

  • 以程序化或无头(headless)方式输出PDF 或 SVG矢量图;
  • 精确控制物理尺寸或 DPI;
  • 维护已有的 ETE treeview 布局代码。

这一决策在仓库测试中被固化下来:EngineChoiceTests验证了「无输出文件时选 SmartView、.png后缀走 SmartView、.pdf/.svg后缀走 treeview、无法识别的后缀直接报错」的完整行为(见 tests/etetoolkit/test_scripts.py)。也就是说,矢量 PDF/SVG 必须走 Qt treeview,SmartView 的静态输出只有 PNG 截图这一种形式。

安装:按渲染需求选择 extras

ETE 4.4.0 的安装粒度很细,交互式 SmartView 已包含在基础包中,静态截图与 Qt 渲染则需要额外的 extras:

# 基础包:包含交互式 SmartView uv pip install "ete4==4.4.0" # 静态 SmartView 截图(需要 Selenium 驱动浏览器) uv pip install "ete4[render-sm]==4.4.0" # Qt 渲染(PNG/PDF/SVG) uv pip install "ete4[treeview]==4.4.0"

SKILL.md 强调「只安装工作流所需的那一个 extra」:render-sm只为render_sm()的静态 PNG 截图服务,treeview只为 Qt 的矢量输出服务(见 SKILL.md)。安装后可用一条命令确认环境:

uv run --with "ete4==4.4.0" python -c "import ete4; print(ete4.__version__)"

注意运行环境前提:仓库技能声明内置脚本需要 Python 3.10+ 与 ete4 4.4.0(上游 ete4 支持 Python >= 3.7);SmartView 探索需要网络访问,静态 PNG 渲染需要ete4[render-sm],Qt PDF/SVG 渲染需要ete4[treeview](见 SKILL.md)。

交互式 SmartView

从 Python 启动

SmartView 的核心入口是Tree.explore()

from pathlib import Path from ete4 import Tree with Path("tree.nw").open(encoding="utf-8") as handle: tree = Tree(handle, parser=1) tree.explore()

细节要点:

  • 不传layouts参数时,ETE 应用默认的BASIC_LAYOUT,展示叶名、分支长度与支持值。
  • explore()立即返回。独立脚本必须让进程保持存活——例如调用input()等待回车,或使用keep_server=True。仓库自带的可视化辅助脚本正是通过「input()阻塞 +finally中调用explorer.stop_server()」来干净地关闭服务(见 quick_visualize.py)。
  • 在 Jupyter/IPython 中,SmartView 依然是基于浏览器的,当前文档没有提供内联 SmartView widget;保持内核存活并打开服务返回的 URL 即可。

从命令行启动

ete4 explore -t tree.nw --src_tree_format 1

用以下命令查看当前发行版支持的完整选项:

ete4 explore --help

需要留意的是:CLI 只支持基础的源树选择与解析器选项。虽然 ETE 4.4.0 的帮助文本暴露了--face参数,但其 handler 并不实际应用该参数——定制外观必须使用 Python 的Layout对象。

控制服务端与安全绑定

可以通过参数精确控制服务端行为:

tree.explore( host="127.0.0.1", port=5000, open_browser=False, )

安全方面的要求非常明确:

  • 保持默认的 loopback(127.0.0.1)绑定,除非远程访问经过了有意的安全加固;
  • 远程访问时,通过 SSH 隧道转发 loopback 端口,然后在本地打开浏览器:
ssh -L 5000:localhost:5000 user@remote-host

打开http://localhost:5000即可。不要把未经认证的 explorer 绑定到0.0.0.0暴露给不受信任的网络。

仓库对这一安全边界有完整的测试覆盖:BindAddressTests逐一验证了127.0.0.1127.0.0.2::1localhost等 loopback 拼写无需显式授权即可绑定;而0.0.0.0192.168.1.10example.com等一切非 loopback 地址都必须显式传入--allow-remote-bind才被接受(见 tests/etetoolkit/test_scripts.py)。测试注释也点明了原因:SmartView 服务的是一个未经认证的交互式查看器,绑定地址因此是安全闸门

SmartView 布局(Layout)

SmartView 的Layout由四部分组成:

  • draw_tree(tree):树级样式,以及头部/图例 Faces;
  • draw_node(node[, collapsed]):单个节点的样式与 Faces;
  • name:GUI 中的布局标识符;
  • cache_size:节点绘制结果的记忆化(memoization)控制。

draw_treedraw_node都是生成器,通过yield产出字典(样式)或 Face 对象。

环形树:标签与支持值标注

from ete4 import Tree from ete4.smartview import Layout, PropFace, TextFace tree = Tree("((A:1,B:1)95:0.2,C:1);", parser="support") def draw_tree(_tree): yield { "shape": "circular", "node-height-min": 8, "content-height-min": 4, } yield TextFace( "Example phylogeny", fs_min=8, fs_max=22, position="header", ) def draw_node(node): if node.is_leaf: yield PropFace( "name", fs_min=4, fs_max=16, position="right", ) return if node.support is not None: yield TextFace( f"{node.support:g}", fs_min=3, fs_max=12, style={"fill": "#555"}, position="top", ) layout = Layout( "circular labels and support", draw_tree=draw_tree, draw_node=draw_node, ) tree.explore(layouts=[layout])

注意这里用parser="support"(等价于数字parser=0)读取 Newick,内部节点字段被解释为支持值;而「环形」由draw_tree产出的"shape": "circular"决定。从 api_reference.md 可以查到常用 parser 映射:parser="support"/0将内部字段读为支持值,parser="name"/1将内部字段读为名称,parser=8为全节点命名、parser=9仅叶命名、parser=100仅拓扑。

条件节点样式:按支持值着色

支持值可能是分数(0~1)也可能是百分比(0~100),只有在确认来源文件的约定之后才能归一化

from ete4 import Tree from ete4.smartview import Layout, PropFace tree = Tree("((A:1,B:1)95:0.2,C:1);", parser="support") def support_fraction(value): if value is None: return None return value / 100 if value > 1 else value def draw_node(node): if node.is_leaf: yield PropFace("name", position="right") support = support_fraction(node.support) if support is None: color = "#888" elif support >= 0.9: color = "#1b7837" elif support >= 0.7: color = "#e08214" else: color = "#b2182b" yield { "dot": { "shape": "circle", "radius": 5, "fill": color, } } layout = Layout("support colors", draw_node=draw_node) tree.explore(layouts=[layout])

这个「按支持值分区着色」模式在仓库中被提升为 CLI 一等公民。quick_visualize.py中的support_fraction()使用完全相同的value / 100 if value > 1 else value归一化逻辑(见 quick_visualize.py),并配套--high-support(默认 0.9)、--moderate-support(默认 0.7)等阈值参数与高/中/低/缺失四种颜色(默认#1b7837/#e08214/#b2182b/#999999,见 quick_visualize.py)。测试还验证了边界行为:恰好为 1 的支持值被当作满支持分数而非 1%,None支持值映射为缺失色,阈值可调(见 tests/etetoolkit/test_scripts.py)。

树级样式键速查

常见树级样式键及其含义:

含义
shape"rectangular""circular"
radius环形布局的半径
angle-startangle-endangle-span环形布局的角度范围(度)
node-height-min折叠阈值(像素),节点高度低于此值时折叠
content-height-minFaces 出现所需的最小高度
collapsed折叠节点的样式
show-popup-propshide-popup-props弹窗中展示/隐藏的属性
is-leaf-fn动态终末节点判定规则
boxdothz-linevt-line类 CSS 的默认样式键

示例——半圆布局并限定弹窗属性:

tree_style = { "shape": "circular", "angle-start": -180, "angle-span": 180, "node-height-min": 10, "collapsed": { "shape": "outline", "fill-opacity": 0.6, }, "show-popup-props": ["name", "dist", "support", "group"], } layout = Layout("semicircle", draw_tree=tree_style) tree.explore(layouts=[layout])

当节点携带敏感或不相关的元数据时,应当限制弹窗中展示的属性。仓库脚本默认只弹出["name", "dist", "support"]三个属性(见 quick_visualize.py),正是这一原则的落地。

SmartView Faces

ete4.smartview下常用的 Face 类:

  • TextFace:字面文本;
  • PropFace:节点的某个属性(支持可选格式化);
  • EvalTextFace:表达式求值得到的文本;
  • CircleFaceRectFaceBoxFace:几何形状;
  • ImageFace:图像;
  • SeqFace:分子序列;
  • LegendFace:图例。

Face 的位置(position)包括topbottomleftrightaligned;树级文本还可使用header

对齐的元数据列

利用position="aligned"配合column参数,可以构建基因树/样本树中常见的对齐注释列(如宿主、采样地点等元数据):

from ete4.smartview import Layout, PropFace def draw_node(node): if not node.is_leaf: return yield PropFace("name", position="aligned", column=0) yield PropFace("host", position="aligned", column=1) yield PropFace("location", position="aligned", column=2) layout = Layout("sample metadata", draw_node=draw_node) tree.explore(layouts=[layout])

该示例假设树节点上已通过add_props(host=..., location=...)之类的 API 挂载了属性;属性标注的具体方式见 SKILL.md 与 api_reference.md。

折叠节点的特殊表示

draw_node可以接受第二个参数collapsed,从而为折叠状态提供专属外观:

from ete4.smartview import Layout, TextFace def draw_node(node, collapsed): if node.name != "large_clade": return text = "large_clade (collapsed)" if collapsed else "large_clade" return TextFace(text, position="right") layout = Layout("collapsed label", draw_node=draw_node) tree.explore(layouts=[layout])

面对数万片叶子时,应当依赖折叠阈值而非试图渲染每个节点的每个 Face——这正是node-height-min/content-height-min存在的意义。从源码看,脚本默认将折叠阈值设为--collapse-pixels(默认 8 像素)、内容最小高度设为--content-pixels(默认 4 像素)(见 quick_visualize.py),并测试确认这些阈值会被原样写入 SmartView 样式字典(见 tests/etetoolkit/test_scripts.py)。

SmartView 静态 PNG 渲染

Tree.render_sm()负责将当前布局渲染为 PNG 截图:

from ete4 import Tree from ete4.smartview import Layout, PropFace tree = Tree("((A:1,B:1),C:1);") def draw_node(node): if node.is_leaf: return PropFace("name", position="right") layout = Layout("leaf labels", draw_node=draw_node) tree.render_sm( "tree.png", layouts=[layout], w=1200, h=800, )

三个必须记住的边界条件:

  1. 在 ETE 4.4.0 中,render_sm()只捕获 PNG 截图数据,输出文件必须使用.png后缀;传入.svg.pdf并不会把截图转换为矢量格式。
  2. 静态 SmartView 渲染需要 Selenium 可用的浏览器。如果浏览器发现失败,请安装兼容的 Chrome/Chromium,或改用 Qt treeview。
  3. 交互式 SmartView 浏览器可以将其当前视图下载为 SVG/PNG 并导出 Newick——但那是浏览器行为,render_sm()无关render_sm()仅支持 PNG,没有 PDF 模式。

仓库脚本同样强制执行「PNG 专用」:render_smartview()在输出后缀不是.png时直接报错并提示改用--engine treeview(见 quick_visualize.py),对应的测试test_smartview_refuses_a_non_png_destination也验证了这一点(见 tests/etetoolkit/test_scripts.py)。

Qt Treeview:PNG / PDF / SVG 矢量输出

Treeview 的类不是 ETE 4 的顶层导入,必须从ete4.treeview导入。这是一个与 ETE 3 兼容的 API 面:TreeStyleNodeStyle以及 Qt Face 类仍然沿用,但 ETE 4 的谓词改为属性:

from ete4 import Tree from ete4.treeview import NodeStyle, TextFace, TreeStyle tree = Tree("((A:1,B:1)95:0.2,C:1);", parser="support") for node in tree.traverse(): style = NodeStyle() style["size"] = 6 if node.is_leaf else 4 style["fgcolor"] = "navy" if node.is_leaf else "gray" node.set_style(style) tree_style = TreeStyle() tree_style.show_leaf_name = True tree_style.show_branch_support = True tree_style.show_scale = True tree_style.title.add_face( TextFace("Example phylogeny", fsize=18, bold=True), column=0, ) tree.render( "tree.svg", w=180, units="mm", tree_style=tree_style, ) tree.render( "tree.pdf", w=180, units="mm", tree_style=tree_style, ) tree.render( "tree.png", w=2400, units="px", dpi=300, tree_style=tree_style, )

注意写法差异:ETE 4 中必须写node.is_leaf(属性),不能写 ETE 3 时代的node.is_leaf()(方法)。同一份代码中units可取px/mm/in,这是控制期刊插图物理尺寸的关键手段。

环形 Qt 输出

tree_style = TreeStyle() tree_style.mode = "c" tree_style.arc_start = -180 tree_style.arc_span = 180 tree.render("semicircle.svg", tree_style=tree_style)

Qt 侧用mode = "c"(circular)对应 SmartView 的"shape": "circular",半圆则通过arc_start/arc_span控制角度范围。

无头(Headless)环境下的 Qt

在无显示器的 Linux 主机上,常见的第一种尝试是:

QT_QPA_PLATFORM=offscreen python render_tree.py

如果平台插件或所需共享库不可用,文档给出的替代路径是:改用 SmartView PNG、使用带 Qt 运行时的容器,或在工作站上渲染。仓库脚本的create_treeview_style()同样只依赖 Qt 离屏渲染,并在缺少ete4[treeview]extra 时给出安装提示(见 quick_visualize.py 与对应测试 test_scripts.py)。

仓库配套可视化脚本:quick_visualize.py 实战

仓库为上述全部能力封装了一个命令行入口,脚本位置为 skills/etetoolkit/scripts/quick_visualize.py,通过uv run --with在隔离的固定版本运行时中执行。

交互式 SmartView(不需要任何 extra):

uv run --with "ete4==4.4.0" python scripts/quick_visualize.py \ tree.nw --parser 1

SmartView PNG(需要ete4[render-sm]):

uv run --with "ete4[render-sm]==4.4.0" python scripts/quick_visualize.py \ tree.nw tree.png \ --parser support \ --mode circular \ --show-support \ --color-by-support \ --title "Maximum-likelihood tree"

Qt SVG 或 PDF(需要ete4[treeview]):

uv run --with "ete4[treeview]==4.4.0" python scripts/quick_visualize.py \ tree.nw tree.svg \ --parser 1 \ --engine treeview \ --mode rectangular \ --title "Species tree"

脚本的auto引擎会自动决策:交互式使用与 PNG 走 SmartView,PDF/SVG 走 Qt treeview。这一决策逻辑在 choose_engine() 中实现,并有完整测试覆盖(见 tests/etetoolkit/test_scripts.py)。

脚本还支持一组经过校验的高价值参数(见 quick_visualize.py):

  • 解析器--parser同时接受数字(如01)与命名别名(如supportname);
  • 布局--mode接受rectangular/rcircular/c
  • 显示--show-names(默认开)、--show-support--show-lengths--show-scale--label-size--leaf-size--leaf-color--internal-color
  • 支持值着色--color-by-support--high-support--moderate-support及三种分档颜色;
  • SmartView--collapse-pixels--content-pixels--host--port--no-browser--allow-remote-bind
  • 静态输出--width--height--unitspx/mm/in)、--dpi--arc-start--arc-span

参数的取值约束同样被严格校验并测试:支持阈值必须满足0 <= moderate <= high <= 1、尺寸与 DPI 必须为正、端口必须在 1~65535、角度在合法范围内(见 validate_args() 与 ValidateArgsTests)。

发表级插图检查清单

无论走哪套渲染器,将图片投入正式出版前都应逐项核对:

  • 需要缩放或二次编辑的线条图优先 SVG/PDF矢量格式;
  • 期刊插图使用明确的物理宽度(如units="mm"+ 指定宽度);
  • 上色或标注前先核对支持值的量纲(0~1 还是 0~100);
  • 使用色盲安全调色板,且不要只依赖颜色传递信息;
  • 保证终版印刷尺寸下叶标签可读(注意fs_min/fs_max/label-size的设置);
  • 在图注中说明根的位置、分支长度单位与支持值统计量
  • 只导出预期的节点属性(用show-popup-propsprops白名单控制);
  • 对最终产物本身做测试,而不只是交互式探索器——例如仓库脚本测试会直接检查渲染路径拒绝错误后缀、缺失目录等边界(见 RenderDestinationTests)。

故障排查

SmartView 静态渲染出现ImportError

缺少render-smextra,安装即可:

uv pip install "ete4[render-sm]==4.4.0"

Qt 类导入报错

必须先安装 extra 再正确导入:

uv pip install "ete4[treeview]==4.4.0"
from ete4.treeview import NodeStyle, TreeStyle

树渲染出来却没有预期的名称或支持值

最可能的原因是解析器不匹配。按数据来源重新读取,例如parser="name"parser="support",并用以下命令检查节点属性是否被正确解析:

print(tree.to_str(props=["name", "dist", "support"], compact=True))

这也是 SKILL.md 反复强调的核心点:解析器不匹配是NewickError、内部标签丢失、支持值被当作名称读取的最常见原因。解析器完整对照表见 api_reference.md。

大树的显示呈折叠状态

SmartView 会在分支高度低于node-height-min阈值时自适应折叠。遇到这种情况:在视图中放大,或在布局中调低阈值(脚本对应参数为--collapse-pixels)。从源码看,默认阈值为 8 像素、内容最小高度为 4 像素(见 quick_visualize.py),对包含数万片叶子的大树,可适当下调该值以显示更多细节。

延伸阅读

本技能仓库内还有其他可配合阅读的参考资料与脚本:

  • 技能总览 SKILL.md:完整范围、快速上手、树操作/比较/进化事件/分类学查询工作流与脚本清单;
  • api_reference.md:ETE 4 核心类、解析器、节点属性、遍历与 I/O 的完整参考;
  • workflows.md:完整分析模式、校验、调和、批处理与大树处理;
  • taxonomy.md:NCBI/GTDB 分类学数据集的初始化与查询;
  • migration-ete3-to-ete4.md:ETE 3 到 ETE 4 的破坏性变更与迁移清单;
  • tree_operations.py:统计、ASCII 绘制、转换、重根、剪枝与拓扑比较等树操作脚本;
  • tests/etetoolkit/test_scripts.py:本文所述引擎选择、支持值归一化、绑定地址安全与参数校验逻辑的完整测试证据。

【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询