Back to Claude Scientific Skills

ETE 4 Visualization

skills/etetoolkit/references/visualization.md

2.55.011.7 KB
Original Source

ETE 4 Visualization

ETE 4 has two drawing systems:

  • SmartView: current web-based explorer and adaptive renderer; best for interactive work and very large trees
  • Treeview: optional Qt renderer retained for static PNG, PDF, and SVG

Do not mix their layout or face classes. SmartView classes live under ete4.smartview; Qt classes live under ete4.treeview.

Renderer Decision

Use SmartView when:

  • Exploring, searching, collapsing, or editing interactively
  • Serving a tree locally or through an SSH tunnel
  • Exploring from a long-lived Jupyter kernel through the browser
  • Creating a raster PNG screenshot
  • Manually downloading the current browser view as SVG or PNG
  • Working with a tree too large to draw fully expanded

Use Qt treeview when:

  • Programmatic or headless output must be PDF or SVG
  • Exact physical dimensions or DPI matter
  • Maintaining an existing ETE treeview layout

Installation

Interactive SmartView is included in the base package:

bash
uv pip install "ete4==4.4.0"

Static SmartView screenshots use Selenium:

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

Qt rendering uses PyQt6:

bash
uv pip install "ete4[treeview]==4.4.0"

Interactive SmartView

Python

python
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()

With no layouts argument, ETE applies BASIC_LAYOUT, which displays leaf names, branch lengths, and support.

explore() returns immediately. A standalone script must keep the process alive, for example with input(), or use keep_server=True. The bundled visualization helper waits and stops the server cleanly.

In Jupyter/IPython, SmartView is still browser-based; the current documentation does not provide an inline SmartView widget. Keep the kernel alive and open the served URL.

Command line

bash
ete4 explore -t tree.nw --src_tree_format 1

Inspect the active release's full options:

bash
ete4 explore --help

The CLI supports basic source-tree selection and parser options. Although ETE 4.4.0 help exposes --face, its handler does not apply that argument; use Python Layout objects for customization.

Control the server

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

Keep the default loopback binding unless remote access is intentionally secured. For a remote host, tunnel the loopback port:

bash
ssh -L 5000:localhost:5000 user@remote-host

Then open http://localhost:5000 locally. Do not expose an unauthenticated explorer on 0.0.0.0 to an untrusted network.

SmartView Layouts

A SmartView Layout combines:

  • draw_tree(tree): tree-wide style and header/legend faces
  • draw_node(node[, collapsed]): styles and faces for individual nodes
  • name: GUI identifier
  • cache_size: memoization control for node drawing

Circular tree with labels and support

python
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])

Conditional node styling

Support values may be fractions or percentages. Normalize only after checking the source's convention:

python
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])

Tree style keys

Common tree-wide keys:

  • shape: "rectangular" or "circular"
  • radius: circular layout radius
  • angle-start, angle-end, angle-span: circular extent
  • node-height-min: collapse threshold in pixels
  • content-height-min: minimum height before faces appear
  • collapsed: collapsed-node style
  • show-popup-props, hide-popup-props: property disclosure
  • is-leaf-fn: dynamic terminal-node rule
  • box, dot, hz-line, vt-line: default CSS-like styles

Example:

python
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])

Limit popup properties when nodes contain sensitive or irrelevant metadata.

SmartView Faces

Common classes from ete4.smartview:

  • TextFace: literal text
  • PropFace: one node property with optional formatting
  • EvalTextFace: expression-derived text
  • CircleFace, RectFace, BoxFace: shapes
  • ImageFace: image
  • SeqFace: molecular sequence
  • LegendFace: legend

Positions include top, bottom, left, right, and aligned; tree-level text can also use header.

Aligned metadata columns

python
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])

Collapsed-node behavior

For a special collapsed representation, accept a second argument:

python
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])

Use collapse thresholds instead of trying to render every face for tens of thousands of leaves.

SmartView Static PNG

python
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,
)

In ETE 4.4.0, render_sm() captures PNG screenshot data. Give the output a .png suffix. Supplying .svg or .pdf does not convert the screenshot to a vector format.

Static SmartView rendering needs a browser usable by Selenium. If browser discovery fails, install a compatible Chrome/Chromium browser or use Qt treeview.

The interactive SmartView browser can download its current view as SVG or PNG and export Newick. That browser action is distinct from render_sm(), which is PNG-only and has no PDF mode.

Qt Treeview for PNG/PDF/SVG

Treeview classes are not top-level ETE 4 imports.

python
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,
)

Qt treeview still uses TreeStyle, NodeStyle, and Qt face classes, but ETE 4 predicates remain properties:

python
if node.is_leaf:
    ...

not:

python
if node.is_leaf():
    ...

Circular Qt output

python
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)

Headless Qt

On a headless Linux host, a common first attempt is:

bash
QT_QPA_PLATFORM=offscreen python render_tree.py

If the platform plugin or required shared libraries are unavailable, use SmartView PNG, a container with the Qt runtime, or render on a workstation.

Bundled Visualization Script

Interactive SmartView:

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

SmartView PNG:

bash
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 or PDF:

bash
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"

The script's auto engine chooses SmartView for interactive use and PNG, and Qt treeview for PDF/SVG.

Publication Checklist

  • Prefer SVG/PDF for line art that will be resized or edited.
  • Use explicit physical width for journal figures.
  • Check support scale before mapping colors or labels.
  • Use a colorblind-safe palette and do not rely on color alone.
  • Keep tip labels legible at final print size.
  • State rooting, branch-length units, and support statistic in the caption.
  • Export only intended node properties.
  • Test the exact artifact, not just the interactive explorer.

Troubleshooting

ImportError for SmartView static rendering

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

ImportError for Qt classes

Use:

python
from ete4.treeview import NodeStyle, TreeStyle

after:

bash
uv pip install "ete4[treeview]==4.4.0"

Tree renders without expected names or support

The likely cause is the parser. Re-read using parser="name" or parser="support" as appropriate and inspect:

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

Large tree appears collapsed

SmartView adaptively collapses branches below node-height-min. Zoom in or lower the threshold in a layout.

Upstream References