Back to index

python-biopython  1.60
Functions | Variables
Bio.Phylo._utils Namespace Reference

Functions

def to_networkx
def draw_graphviz
def draw_ascii
def draw

Variables

string __docformat__ = "restructuredtext en"

Function Documentation

def Bio.Phylo._utils.draw (   tree,
  label_func = str,
  do_show = True,
  show_confidence = True,
  axes = None,
  branch_labels = None 
)
Plot the given tree using matplotlib (or pylab).

The graphic is a rooted tree, drawn with roughly the same algorithm as
draw_ascii.

Visual aspects of the plot can be modified using pyplot's own functions and
objects (via pylab or matplotlib). In particular, the pyplot.rcParams
object can be used to scale the font size (rcParams["font.size"]) and line
width (rcParams["lines.linewidth"]).

:Parameters:
    label_func : callable
        A function to extract a label from a node. By default this is str(),
        but you can use a different function to select another string
        associated with each node. If this function returns None for a node,
        no label will be shown for that node.
    do_show : bool
        Whether to show() the plot automatically.
    show_confidence : bool
        Whether to display confidence values, if present on the tree.
    axes : matplotlib/pylab axes
        If a valid matplotlib.axes.Axes instance, the phylogram is plotted
        in that Axes. By default (None), a new figure is created.
    branch_labels : dict or callable
        A mapping of each clade to the label that will be shown along the
        branch leading to it. By default this is the confidence value(s) of
        the clade, taken from the ``confidence`` attribute, and can be
        easily toggled off with this function's ``show_confidence`` option.
        But if you would like to alter the formatting of confidence values,
        or label the branches with something other than confidence, then use
        this option.

Definition at line 258 of file _utils.py.

00258 
00259         axes=None, branch_labels=None):
00260     """Plot the given tree using matplotlib (or pylab).
00261 
00262     The graphic is a rooted tree, drawn with roughly the same algorithm as
00263     draw_ascii.
00264 
00265     Visual aspects of the plot can be modified using pyplot's own functions and
00266     objects (via pylab or matplotlib). In particular, the pyplot.rcParams
00267     object can be used to scale the font size (rcParams["font.size"]) and line
00268     width (rcParams["lines.linewidth"]).
00269 
00270     :Parameters:
00271         label_func : callable
00272             A function to extract a label from a node. By default this is str(),
00273             but you can use a different function to select another string
00274             associated with each node. If this function returns None for a node,
00275             no label will be shown for that node.
00276         do_show : bool
00277             Whether to show() the plot automatically.
00278         show_confidence : bool
00279             Whether to display confidence values, if present on the tree.
00280         axes : matplotlib/pylab axes
00281             If a valid matplotlib.axes.Axes instance, the phylogram is plotted
00282             in that Axes. By default (None), a new figure is created.
00283         branch_labels : dict or callable
00284             A mapping of each clade to the label that will be shown along the
00285             branch leading to it. By default this is the confidence value(s) of
00286             the clade, taken from the ``confidence`` attribute, and can be
00287             easily toggled off with this function's ``show_confidence`` option.
00288             But if you would like to alter the formatting of confidence values,
00289             or label the branches with something other than confidence, then use
00290             this option.
00291     """
00292     try:
00293         import matplotlib.pyplot as plt
00294     except ImportError:
00295         try:
00296             import pylab as plt
00297         except ImportError:
00298             from Bio import MissingPythonDependencyError
00299             raise MissingPythonDependencyError(
00300                     "Install matplotlib or pylab if you want to use draw.")
00301 
00302     # Options for displaying branch labels / confidence
00303     def conf2str(conf):
00304         if int(conf) == conf:
00305             return str(int(conf))
00306         return str(conf)
00307     if not branch_labels:
00308         if show_confidence:
00309             def format_branch_label(clade):
00310                 if hasattr(clade, 'confidences'):
00311                     # phyloXML supports multiple confidences
00312                     return '/'.join(conf2str(cnf.value)
00313                                     for cnf in clade.confidences)
00314                 if clade.confidence:
00315                     return conf2str(clade.confidence)
00316                 return None
00317         else:
00318             def format_branch_label(clade):
00319                 return None
00320     elif isinstance(branch_labels, dict):
00321         def format_branch_label(clade):
00322             return branch_labels.get(clade)
00323     else:
00324         assert callable(branch_labels), \
00325                 "branch_labels must be either a dict or a callable (function)"
00326         format_branch_label = branch_labels
00327 
00328     # Layout
00329 
00330     def get_x_positions(tree):
00331         """Create a mapping of each clade to its horizontal position.
00332 
00333         Dict of {clade: x-coord}
00334         """
00335         depths = tree.depths()
00336         # If there are no branch lengths, assume unit branch lengths
00337         if not max(depths.itervalues()):
00338             depths = tree.depths(unit_branch_lengths=True)
00339         return depths
00340 
00341     def get_y_positions(tree):
00342         """Create a mapping of each clade to its vertical position.
00343 
00344         Dict of {clade: y-coord}.
00345         Coordinates are negative, and integers for tips.
00346         """
00347         maxheight = tree.count_terminals()
00348         # Rows are defined by the tips
00349         heights = dict((tip, maxheight - i)
00350                 for i, tip in enumerate(reversed(tree.get_terminals())))
00351         # Internal nodes: place at midpoint of children
00352         def calc_row(clade):
00353             for subclade in clade:
00354                 if subclade not in heights:
00355                     calc_row(subclade)
00356             # Closure over heights
00357             heights[clade] = (heights[clade.clades[0]] +
00358                                 heights[clade.clades[-1]]) / 2.0
00359 
00360         if tree.root.clades:
00361             calc_row(tree.root)
00362         return heights
00363 
00364     x_posns = get_x_positions(tree)
00365     y_posns = get_y_positions(tree)
00366     # The function draw_clade closes over the axes object
00367     if axes is None:
00368         fig = plt.figure()
00369         axes = fig.add_subplot(1, 1, 1)
00370     elif not isinstance(axes, plt.matplotlib.axes.Axes):
00371         raise ValueError("Invalid argument for axes: %s" % axes)
00372 
00373     def draw_clade(clade, x_start, color, lw):
00374         """Recursively draw a tree, down from the given clade."""
00375         x_here = x_posns[clade]
00376         y_here = y_posns[clade]
00377         # phyloXML-only graphics annotations
00378         if hasattr(clade, 'color') and clade.color is not None:
00379             color = clade.color.to_hex()
00380         if hasattr(clade, 'width') and clade.width is not None:
00381             lw = clade.width * plt.rcParams['lines.linewidth']
00382         # Draw a horizontal line from start to here
00383         axes.hlines(y_here, x_start, x_here, color=color, lw=lw)
00384         # Add node/taxon labels
00385         label = label_func(clade)
00386         if label not in (None, clade.__class__.__name__):
00387             axes.text(x_here, y_here, ' %s' % label, verticalalignment='center')
00388         # Add label above the branch (optional)
00389         conf_label = format_branch_label(clade)
00390         if conf_label:
00391             axes.text(0.5*(x_start + x_here), y_here, conf_label,
00392                     fontsize='small', horizontalalignment='center')
00393         if clade.clades:
00394             # Draw a vertical line connecting all children
00395             y_top = y_posns[clade.clades[0]]
00396             y_bot = y_posns[clade.clades[-1]]
00397             # Only apply widths to horizontal lines, like Archaeopteryx
00398             axes.vlines(x_here, y_bot, y_top, color=color)
00399             # Draw descendents
00400             for child in clade:
00401                 draw_clade(child, x_here, color, lw)
00402 
00403     draw_clade(tree.root, 0, 'k', plt.rcParams['lines.linewidth'])
00404 
00405     # Aesthetics
00406 
00407     if hasattr(tree, 'name') and tree.name:
00408         axes.set_title(tree.name)
00409     axes.set_xlabel('branch length')
00410     axes.set_ylabel('taxa')
00411     # Add margins around the tree to prevent overlapping the axes
00412     xmax = max(x_posns.itervalues())
00413     axes.set_xlim(-0.05 * xmax, 1.25 * xmax)
00414     # Also invert the y-axis (origin at the top)
00415     # Add a small vertical margin, but avoid including 0 and N+1 on the y axis
00416     axes.set_ylim(max(y_posns.itervalues()) + 0.8, 0.2)
00417     if do_show:
00418         plt.show()
00419 

Here is the caller graph for this function:

def Bio.Phylo._utils.draw_ascii (   tree,
  file = sys.stdout,
  column_width = 80 
)
Draw an ascii-art phylogram of the given tree.

The printed result looks like::

                                    _________ Orange
                     ______________|
                    |              |______________ Tangerine
      ______________|
     |              |          _________________________ Grapefruit
    _|              |_________|
     |                        |______________ Pummelo
     |
     |__________________________________ Apple


:Parameters:
    file : file-like object
        File handle opened for writing the output drawing.
    column_width : int
        Total number of text columns used by the drawing.

Definition at line 169 of file _utils.py.

00169 
00170 def draw_ascii(tree, file=sys.stdout, column_width=80):
00171     """Draw an ascii-art phylogram of the given tree.
00172 
00173     The printed result looks like::
00174 
00175                                         _________ Orange
00176                          ______________|
00177                         |              |______________ Tangerine
00178           ______________|
00179          |              |          _________________________ Grapefruit
00180         _|              |_________|
00181          |                        |______________ Pummelo
00182          |
00183          |__________________________________ Apple
00184 
00185 
00186     :Parameters:
00187         file : file-like object
00188             File handle opened for writing the output drawing.
00189         column_width : int
00190             Total number of text columns used by the drawing.
00191     """
00192     taxa = tree.get_terminals()
00193     # Some constants for the drawing calculations
00194     max_label_width = max(len(str(taxon)) for taxon in taxa)
00195     drawing_width = column_width - max_label_width - 1
00196     drawing_height = 2 * len(taxa) - 1
00197 
00198     def get_col_positions(tree):
00199         """Create a mapping of each clade to its column position."""
00200         depths = tree.depths()
00201         # If there are no branch lengths, assume unit branch lengths
00202         if not max(depths.itervalues()):
00203             depths = tree.depths(unit_branch_lengths=True)
00204         # Potential drawing overflow due to rounding -- 1 char per tree layer
00205         fudge_margin = int(math.ceil(math.log(len(taxa), 2)))
00206         cols_per_branch_unit = ((drawing_width - fudge_margin)
00207                                 / float(max(depths.itervalues())))
00208         return dict((clade, int(round(blen*cols_per_branch_unit + 0.5)))
00209                     for clade, blen in depths.iteritems())
00210 
00211     def get_row_positions(tree):
00212         positions = dict((taxon, 2*idx) for idx, taxon in enumerate(taxa))
00213         def calc_row(clade):
00214             for subclade in clade:
00215                 if subclade not in positions:
00216                     calc_row(subclade)
00217             positions[clade] = (positions[clade.clades[0]] +
00218                                 positions[clade.clades[-1]]) / 2
00219         calc_row(tree.root)
00220         return positions
00221 
00222     col_positions = get_col_positions(tree)
00223     row_positions = get_row_positions(tree)
00224     char_matrix = [[' ' for x in range(drawing_width)]
00225                     for y in range(drawing_height)]
00226 
00227     def draw_clade(clade, startcol):
00228         thiscol = col_positions[clade]
00229         thisrow = row_positions[clade]
00230         # Draw a horizontal line
00231         for col in range(startcol, thiscol):
00232             char_matrix[thisrow][col] = '_'
00233         if clade.clades:
00234             # Draw a vertical line
00235             toprow = row_positions[clade.clades[0]]
00236             botrow = row_positions[clade.clades[-1]]
00237             for row in range(toprow+1, botrow+1):
00238                 char_matrix[row][thiscol] = '|'
00239             # NB: Short terminal branches need something to stop rstrip()
00240             if (col_positions[clade.clades[0]] - thiscol) < 2:
00241                 char_matrix[toprow][thiscol] = ','
00242             # Draw descendents
00243             for child in clade:
00244                 draw_clade(child, thiscol+1)
00245 
00246     draw_clade(tree.root, 0)
00247     # Print the complete drawing
00248     for idx, row in enumerate(char_matrix):
00249         line = ''.join(row).rstrip()
00250         # Add labels for terminal taxa in the right margin
00251         if idx % 2 == 0:
00252             line += ' ' + str(taxa[idx/2])
00253         file.write(line + '\n')
00254     file.write('\n')
00255 

Here is the call graph for this function:

def Bio.Phylo._utils.draw_graphviz (   tree,
  label_func = str,
  prog = 'twopi',
  args = '',
  node_color = '#c0deff',
  kwargs 
)
Display a tree or clade as a graph, using the graphviz engine.

Requires NetworkX, matplotlib, Graphviz and either PyGraphviz or pydot.

The third and fourth parameters apply to Graphviz, and the remaining
arbitrary keyword arguments are passed directly to networkx.draw(), which
in turn mostly wraps matplotlib/pylab.  See the documentation for Graphviz
and networkx for detailed explanations.

The NetworkX/matplotlib parameters are described in the docstrings for
networkx.draw() and pylab.scatter(), but the most reasonable options to try
are: *alpha, node_color, node_size, node_shape, edge_color, style,
font_size, font_color, font_weight, font_family*

:Parameters:

    label_func : callable
        A function to extract a label from a node. By default this is str(),
        but you can use a different function to select another string
        associated with each node. If this function returns None for a node,
        no label will be shown for that node.

        The label will also be silently skipped if the throws an exception
        related to ordinary attribute access (LookupError, AttributeError,
        ValueError); all other exception types will still be raised. This
        means you can use a lambda expression that simply attempts to look
        up the desired value without checking if the intermediate attributes
        are available:

            >>> Phylo.draw_graphviz(tree, lambda n: n.taxonomies[0].code)

    prog : string
        The Graphviz program to use when rendering the graph. 'twopi'
        behaves the best for large graphs, reliably avoiding crossing edges,
        but for moderate graphs 'neato' looks a bit nicer.  For small
        directed graphs, 'dot' may produce a normal-looking cladogram, but
        will cross and distort edges in larger graphs. (The programs 'circo'
        and 'fdp' are not recommended.)
    args : string
        Options passed to the external graphviz program.  Normally not
        needed, but offered here for completeness.

Example
-------

>>> import pylab
>>> from Bio import Phylo
>>> tree = Phylo.read('ex/apaf.xml', 'phyloxml')
>>> Phylo.draw_graphviz(tree)
>>> pylab.show()
>>> pylab.savefig('apaf.png')

Definition at line 73 of file _utils.py.

00073 
00074         node_color='#c0deff', **kwargs):
00075     """Display a tree or clade as a graph, using the graphviz engine.
00076 
00077     Requires NetworkX, matplotlib, Graphviz and either PyGraphviz or pydot.
00078 
00079     The third and fourth parameters apply to Graphviz, and the remaining
00080     arbitrary keyword arguments are passed directly to networkx.draw(), which
00081     in turn mostly wraps matplotlib/pylab.  See the documentation for Graphviz
00082     and networkx for detailed explanations.
00083 
00084     The NetworkX/matplotlib parameters are described in the docstrings for
00085     networkx.draw() and pylab.scatter(), but the most reasonable options to try
00086     are: *alpha, node_color, node_size, node_shape, edge_color, style,
00087     font_size, font_color, font_weight, font_family*
00088 
00089     :Parameters:
00090 
00091         label_func : callable
00092             A function to extract a label from a node. By default this is str(),
00093             but you can use a different function to select another string
00094             associated with each node. If this function returns None for a node,
00095             no label will be shown for that node.
00096 
00097             The label will also be silently skipped if the throws an exception
00098             related to ordinary attribute access (LookupError, AttributeError,
00099             ValueError); all other exception types will still be raised. This
00100             means you can use a lambda expression that simply attempts to look
00101             up the desired value without checking if the intermediate attributes
00102             are available:
00103 
00104                 >>> Phylo.draw_graphviz(tree, lambda n: n.taxonomies[0].code)
00105 
00106         prog : string
00107             The Graphviz program to use when rendering the graph. 'twopi'
00108             behaves the best for large graphs, reliably avoiding crossing edges,
00109             but for moderate graphs 'neato' looks a bit nicer.  For small
00110             directed graphs, 'dot' may produce a normal-looking cladogram, but
00111             will cross and distort edges in larger graphs. (The programs 'circo'
00112             and 'fdp' are not recommended.)
00113         args : string
00114             Options passed to the external graphviz program.  Normally not
00115             needed, but offered here for completeness.
00116 
00117     Example
00118     -------
00119 
00120     >>> import pylab
00121     >>> from Bio import Phylo
00122     >>> tree = Phylo.read('ex/apaf.xml', 'phyloxml')
00123     >>> Phylo.draw_graphviz(tree)
00124     >>> pylab.show()
00125     >>> pylab.savefig('apaf.png')
00126     """
00127     try:
00128         import networkx
00129     except ImportError:
00130         from Bio import MissingPythonDependencyError
00131         raise MissingPythonDependencyError(
00132                 "Install NetworkX if you want to use to_networkx.")
00133 
00134     G = to_networkx(tree)
00135     Gi = networkx.convert_node_labels_to_integers(G, discard_old_labels=False)
00136     try:
00137         posi = networkx.graphviz_layout(Gi, prog, args=args)
00138     except ImportError:
00139         raise MissingPythonDependencyError(
00140                 "Install PyGraphviz or pydot if you want to use draw_graphviz.")
00141 
00142     def get_label_mapping(G, selection):
00143         for node in G.nodes():
00144             if (selection is None) or (node in selection):
00145                 try:
00146                     label = label_func(node)
00147                     if label not in (None, node.__class__.__name__):
00148                         yield (node, label)
00149                 except (LookupError, AttributeError, ValueError):
00150                     pass
00151 
00152     if 'nodelist' in kwargs:
00153         labels = dict(get_label_mapping(G, set(kwargs['nodelist'])))
00154     else:
00155         labels = dict(get_label_mapping(G, None))
00156     kwargs['nodelist'] = labels.keys()
00157     if 'edge_color' not in kwargs:
00158         kwargs['edge_color'] = [isinstance(e[2], dict) and
00159                                 e[2].get('color', 'k') or 'k'
00160                                 for e in G.edges(data=True)]
00161     if 'width' not in kwargs:
00162         kwargs['width'] = [isinstance(e[2], dict) and
00163                            e[2].get('width', 1.0) or 1.0
00164                            for e in G.edges(data=True)]
00165 
00166     posn = dict((n, posi[Gi.node_labels[n]]) for n in G)
00167     networkx.draw(G, posn, labels=labels, node_color=node_color, **kwargs)
00168 

Here is the call graph for this function:

Here is the caller graph for this function:

Convert a Tree object to a networkx graph.

The result is useful for graph-oriented analysis, and also interactive
plotting with pylab, matplotlib or pygraphviz, though the resulting diagram
is usually not ideal for displaying a phylogeny.

Requires NetworkX version 0.99 or later.

Definition at line 16 of file _utils.py.

00016 
00017 def to_networkx(tree):
00018     """Convert a Tree object to a networkx graph.
00019 
00020     The result is useful for graph-oriented analysis, and also interactive
00021     plotting with pylab, matplotlib or pygraphviz, though the resulting diagram
00022     is usually not ideal for displaying a phylogeny.
00023 
00024     Requires NetworkX version 0.99 or later.
00025     """
00026     try:
00027         import networkx
00028     except ImportError:
00029         from Bio import MissingPythonDependencyError
00030         raise MissingPythonDependencyError(
00031                 "Install NetworkX if you want to use to_networkx.")
00032 
00033     def add_edge(graph, n1, n2):
00034         # NB (1/2010): the networkx API congealed recently
00035         # Ubuntu Lucid uses v0.99, newest is v1.0.1, let's support both
00036         if networkx.__version__ >= '1.0':
00037             graph.add_edge(n1, n2, weight=str(n2.branch_length or 1.0))
00038             # Copy branch color value as hex, if available
00039             if hasattr(n2, 'color') and n2.color is not None:
00040                 graph[n1][n2]['color'] = n2.color.to_hex()
00041             elif hasattr(n1, 'color') and n1.color is not None:
00042                 # Cascading color attributes
00043                 graph[n1][n2]['color'] = n1.color.to_hex()
00044                 n2.color = n1.color
00045             # Copy branch weight value (float) if available
00046             if hasattr(n2, 'width') and n2.width is not None:
00047                 graph[n1][n2]['width'] = n2.width
00048             elif hasattr(n1, 'width') and n1.width is not None:
00049                 # Cascading width attributes
00050                 graph[n1][n2]['width'] = n1.width
00051                 n2.width = n1.width
00052         elif networkx.__version__ >= '0.99':
00053             graph.add_edge(n1, n2, (n2.branch_length or 1.0))
00054         else:
00055             graph.add_edge(n1, n2)
00056 
00057     def build_subgraph(graph, top):
00058         """Walk down the Tree, building graphs, edges and nodes."""
00059         for clade in top:
00060             graph.add_node(clade.root)
00061             add_edge(graph, top.root, clade.root)
00062             build_subgraph(graph, clade)
00063 
00064     if tree.rooted:
00065         G = networkx.DiGraph()
00066     else:
00067         G = networkx.Graph()
00068     G.add_node(tree.root)
00069     build_subgraph(G, tree.root)
00070     return G
00071 

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

string Bio.Phylo._utils.__docformat__ = "restructuredtext en"

Definition at line 10 of file _utils.py.