Plotting#
The phylozoo.viz module provides plotting for phylogenetic networks and graphs.
Plots are rendered using matplotlib and return
matplotlib.axes.Axes objects.
The plot() function accepts any of four object types and dispatches by type to the
appropriate plotter:
How to Plot#
The plot() function has the following parameters:
obj — The object to plot (one of the four supported types).
layout (str, default=’auto’) — Layout algorithm. Use
'auto'for the default per type, or specify a name (e.g.'pz-cladogram','spring','circular'). See the layout section below for more details.style — Style object. See the Styling documentation for more details. Use
Nonefor the default style for the object type.ax — Optional matplotlib axes. Plot on existing axes (e.g. for subplots).
show (bool, default=False) — If
True, display the plot. IfFalse, return the axes for saving or customization.**kwargs — Layout-specific parameters (e.g.
layer_gap=2.0for'pz-cladogram').
For quickly plotting a network, and you don’t need to customize the layout or style, you can use the following simple code to plot the network:
from phylozoo.viz import plot
from phylozoo import DirectedPhyNetwork
dnet = DirectedPhyNetwork.load("network.enewick")
plot(dnet)
Layouts#
A layout algorithm determines where nodes are placed. Pass its name as the layout argument;
layout-specific parameters go in **kwargs:
plot(dnet) # default: pz-cladogram (rectangular)
plot(dnet, layout='pz-cladogram', rectangular=False) # straight edges
plot(dnet, layout='pz-layered', direction='LR')
plot(sdnet) # default: pz-unrooted
plot(sdnet, layout='pz-unrooted', daylight=8, refine=0)
plot(sdnet, layout='pz-radial', root_location=some_node)
PhyloZoo layouts#
Four layouts designed for phylogenetic networks, all deterministic and needing nothing beyond
phylozoo[viz]: two rooted, layered ones for directed networks and two unrooted-style ones available
for both classes. These are the recommended layouts and the defaults. Each is implemented by a
compute_pz_*_layout function (linked below and listed in the viz API reference)
that can also be called directly to obtain node positions and edge routes without drawing.
pz-cladogram (
compute_pz_cladogram_layout();DirectedPhyNetworkonly; default) — Layered drawing with a tree backbone. Every node hangs below its lowest parent; the other parent edges of hybrid nodes are drawn as reticulate edges. Siblings are ordered by a hybrid-aware barycenter heuristic followed by a local search on the exact number of edge crossings, so sibling subtrees stay contiguous and reticulate edges stay short. Arrowheads are drawn on hybrid edges only (seearrows). Parameters:layer_gap(float, default 1.0) — Spacing between layers;leaf_gap(float, default 1.0) — Spacing between consecutive leaves;trials(int, default 10) — Number of ordering attempts (the first from the node order, the rest from random orders of the crossing-relevant nodes; trees need only one);seed(int or None, default 0) — Random seed for the restarts;direction(str, default'LR') —'TD'(root at the top) or'LR'(root on the left);align_leaves(bool, default True) — Put all leaves on the last layer (right, or bottom for'TD');rectangular(bool, default True) — Draw edges as orthogonal elbows (backbone edges along the parent’s layer and then into the child, reticulate edges entering the hybrid sideways along its layer);Falsegives straight lines;horizontal_reticulations(bool or None, default None) — Lower the parent of every reticulate edge onto the hybrid’s layer where the network allows it, so that edge is a single horizontal segment.Nonemeans on forrectangulardrawings and off otherwise;x_scale/y_scale(float, default 1.0) — Scaling factors for the coordinates.
Recommended:
plot(net)for the classic rectangular network drawing,plot(net, rectangular=False)for straight edges,plot(net, direction='TD')for a top-down drawing with the root at the top.pz-layered (
compute_pz_layered_layout();DirectedPhyNetworkonly) — Self-contained layered (Sugiyama) layout in the spirit of Graphvizdot: longest-path layers, edges spanning several layers routed through bend points, layer-by-layer barycenter sweeps with adjacent swaps to reduce crossings, and a coordinate pass that straightens edges. Nodes of a layer are ordered freely (no tree backbone), which gives fewer crossings on heavily reticulate networks thanpz-cladogramat the cost of sibling subtrees not staying together; leaves keep their own depth by default. Parameters:layer_gap(float, default 1.0) — Spacing between layers;node_gap(float, default 1.0) — Minimum spacing between nodes of a layer;sweeps(int, default 8) — Number of down-and-up ordering sweeps;direction(str, default'TD') —'TD'or'LR';align_leaves(bool, default False) — Put all leaves on the last layer (right, or bottom for'TD');rectangular(bool, default False) — Draw every edge segment as an orthogonal elbow; the last segment into a hybrid node arrives sideways;x_scale/y_scale(float, default 1.0) — Scaling factors for the coordinates.
Recommended for networks with many reticulations where
pz-cladogramshows long crossing reticulate edges.pz-radial (
compute_pz_radial_layout()/compute_pz_radial_layout(); both classes) — Circular cladogram, as in the radial network view of Dendroscope: root at the centre, leaves evenly spaced on the outer circle, a node’s radius given by its layer and its angle by the mean of its children. The tree backbone and the leaf order come from thepz-cladogramcomputation, so reticulate edges (straight chords) are kept short. A semi-directed network is rooted first withto_d_network(). Parameters:radius(float, default 1.0) — Radius of the leaf circle;start_angle(float, default 0.0) — Angle of the first leaf, in radians;angle_direction(str, default'clockwise') —'clockwise'or'counterclockwise';root_location(semi-directed only; node or edge, default None) — Where to root the network;trials/seed— Ordering options ofpz-cladogram.
pz-unrooted (
compute_pz_unrooted_layout()/compute_pz_unrooted_layout(); both classes; default forSemiDirectedPhyNetwork) — Unrooted tree-of-blobs layout. The network is decomposed into blobs; the tree obtained by contracting them is drawn with the equal-angle algorithm (rooted at its centroid), and each blob is drawn as a regular polygon whose outer cycle comes from a planar embedding, with interior nodes at the barycentre of their neighbours. Pendant subtrees leave a blob in the cyclic order of their attachment nodes, so cut edges never cross blob edges; for trees this is the classic equal-angle unrooted tree drawing. Two optional finishing steps spread the drawing:daylightrounds rotate the rigid subtrees around every tree node and around every blob until the free angles between them are equal (every edge keeps its exact length), andrefineiterations of stress majorization (theneatoalgorithm, started from this crossing-free drawing) relax the whole picture; the stress step only ever accepts a state with no more edge crossings than the drawing it started from. On a directed network the root is an ordinary node and every edge carries an arrowhead. Parameters:edge_length(float, default 1.0) — Length of cut edges (between blobs and to leaves);node_spacing(float, default 0.7) — Target distance between consecutive nodes on a blob’s circle;inner_scale(float, default 0.6) — Scale of subtrees that hang off interior blob nodes and are drawn inside the blob;start_angle(float, default 0.0) — Rotation of the whole drawing, in radians;daylight(int, default 0) — Equal-daylight rounds, applied first;refine(int, default 50) — Stress-majorization iterations, applied last (0disables it).
Recommended settings: the default (stress only) for a compact
neato-like picture with round blobs;daylight=8, refine=0for the SplitsTree-style unrooted drawing with exact edge lengths;daylight=4together with the defaultrefinewhen the stress step folds subtrees on top of each other;node_spacing=1.0for uniform edge lengths (plainneatolook);refine=0, daylight=0for the raw geometry with blobs as exact polygons.
Other layouts#
The generic graph layouts of NetworkX (spring, kamada_kawai, circular, shell,
spectral, spiral, planar, random, bipartite) can be passed as layout for all four
object types; their keyword arguments (k, iterations, seed, …) go in **kwargs. If
PyGraphviz is installed (see Installation),
the Graphviz programs dot, neato, twopi, fdp, sfdp and circo are available the same
way, with Graphviz attributes passed through args. Several PhyloZoo layouts build on the same ideas
(pz-layered on dot, pz-radial on twopi, the refinement of pz-unrooted on neato) but
are tuned to phylogenetic networks, so for networks the PhyloZoo layouts are the better choice. The generic
layouts are mainly there for plotting DirectedMultiGraph
and MixedMultiGraph, for which they are the only
layouts, with spring as the default. They are computed by the compute_nx_layout function of each
viz subpackage.
Text Drawings#
to_preview_string() (also available as the to_preview_string() and preview() methods of both
network classes) draws a network as text, root on the left and leaves on the right, without matplotlib:
>>> net.preview()
┌───────────────● B
┌───────●
○ └┄┄┄┄┄┄>◆───────● A
│ ^
└───────────────●───────● C
Tree edges are box-drawing lines, hybrid edges dotted lines ending in an arrowhead at the hybrid node ◆;
○ is the root, ● any other node; ┼ marks a hybrid edge crossing a tree edge. The placement is that of
pz-cladogram with rectangular=True, so hybrid edges are horizontal wherever the network allows it and sibling
subtrees stay together. Parallel edges are drawn as a loop (the second copy detours one row). Semi-directed
networks are rooted first (root_location chooses where).
Large networks are compacted automatically (narrower columns down to 3 characters until the drawing fits
max_width, default 120, and no blank rows between leaves above 25 leaves); networks with more than
max_leaves (default 80) leaves are refused, since one row per leaf stops being readable. Use col_width and
rows_per_leaf to override the automatic choices.
Saving a Figure#
The plot() function returns a matplotlib axes object. Set show=False and call
the matplotlib savefig method on the figure:
ax = plot(network, show=False)
ax.figure.savefig("network.png", dpi=300, bbox_inches="tight")
Here, dpi controls the resolution of the saved image and bbox_inches='tight' crops the figure to the smallest bounding box that contains all plot elements, removing excess whitespace and ensuring labels are not cut off.
See Also#
Styling — Colors, sizes, and appearance
viz API reference — Full signatures of
plot(), every layout function and the style classesTutorial: Plotting Networks — End-to-end example with every layout, styling and saving