87

I want to plot trees using Python. Decision trees, Organizational charts, etc. Any library that helps me with that?

6 Answers 6

112

I develop ETE, which is a python package intended, among other stuff, for programmatic tree rendering and visualization. You can create your own layout functions and produce custom tree images: enter image description here

It has a focus on phylogenetics, but it can actually deal with any type of hierarchical tree (clustering, decision trees, etc.)

Sign up to request clarification or add additional context in comments.

7 Comments

@Fxs7576 There is a working branch that will be merged soon that adds Qt5 support. github.com/etetoolkit/ete/pull/284
Is it not available for Windows? Your install guide doesn't have a windows section and if I run the conda install line, it doesn't find the package.
For windows, it looks like you can install using pip install ete3.
Literally the only package I found that could be pip installed and it would run out of the box.
I installed ete3 (released in 2020), but since I have Qt5 installed, it throws an error. When will ete4 be avilable as pip installable package?
|
52

For basic visualization I would consider using treelib,

It is very straightforward and easy to use:

 from treelib import Node, Tree

 tree = Tree()

 tree.create_node("Harry", "harry")  # No parent means its the root node
 tree.create_node("Jane",  "jane"   , parent="harry")
 tree.create_node("Bill",  "bill"   , parent="harry")
 tree.create_node("Diane", "diane"  , parent="jane")
 tree.create_node("Mary",  "mary"   , parent="diane")
 tree.create_node("Mark",  "mark"   , parent="jane")

 tree.show()

Output:

Harry
├── Bill
└── Jane
    ├── Diane
    │   └── Mary
    └── Mark 

4 Comments

Highly appreciate your input, easy to use indeed. Also, there is a nice method once you've built a tree to generate graphviz format of the tree: tree.to_graphviz(). So you can use it then in any online or offline tool.
The anytree library (anytree.readthedocs.io/en/latest) is another option.
Using Jupyter Notebook, I found this other post useful as the output is unreadable: stackoverflow.com/q/46345677/10966677
When you use tree.to_graphviz() to generate the resulting file, you can paste the contents of the generated file here edotor.net and get to see and download different sorts of visualizations based on the generated file.
41

There's graphviz - http://www.graphviz.org/. It uses the "DOT" language to plot graphs. You can either generate the DOT code yourself, or use pydot - https://github.com/pydot/pydot. You could also use networkx - http://networkx.lanl.gov/tutorial/tutorial.html#drawing-graphs, which make it easy to draw to either graphviz or matplotlib.

networkx + matplotlib + graphviz gives you the most flexibility and power, but you need to install a lot.

If you want a quick solution, try:

Install Graphviz.

open('hello.dot','w').write("digraph G {Hello->World}")
import subprocess
subprocess.call(["path/to/dot.exe","-Tpng","hello.dot","-o","graph1.png"]) 
# I think this is right - try it form the command line to debug

Then you install pydot, because pydot already does this for you. Then you can use networkx to "drive" pydot.

5 Comments

NetworX looks pretty good. The only thing is that I require an external library to generate image files. Can I generate an arc between nodes?
Which library? NetworkX can handle a few different ones. They seem to like Matplotlib, which has an install guide here: matplotlib.sourceforge.net/users/installing.html.
Matplotlib doesn't support graphs, standalone at least.
NetworkX. Graphviz is famous historically for reading the "DOT" files, but IMO NetworkX, Ete, and iGraph produce far better results by modern standards, and don't require mixing another language with Python.
Link to NetworkX website is broken. New link: networkx.org/documentation/stable/tutorial.html#drawing-graphs
7

Plotly can plot tree diagrams using igraph. You can use it offline these days too. The example below is intended to be run in a Jupyter notebook

import plotly.plotly as py
import plotly.graph_objs as go

import igraph
from igraph import *
# I do not endorse importing * like this

#Set Up Tree with igraph

nr_vertices = 25
v_label = map(str, range(nr_vertices))
G = Graph.Tree(nr_vertices, 2) # 2 stands for children number
lay = G.layout('rt')

position = {k: lay[k] for k in range(nr_vertices)}
Y = [lay[k][1] for k in range(nr_vertices)]
M = max(Y)

es = EdgeSeq(G) # sequence of edges
E = [e.tuple for e in G.es] # list of edges

L = len(position)
Xn = [position[k][0] for k in range(L)]
Yn = [2*M-position[k][1] for k in range(L)]
Xe = []
Ye = []
for edge in E:
    Xe+=[position[edge[0]][0],position[edge[1]][0], None]
    Ye+=[2*M-position[edge[0]][1],2*M-position[edge[1]][1], None] 

labels = v_label

#Create Plotly Traces

lines = go.Scatter(x=Xe,
                   y=Ye,
                   mode='lines',
                   line=dict(color='rgb(210,210,210)', width=1),
                   hoverinfo='none'
                   )
dots = go.Scatter(x=Xn,
                  y=Yn,
                  mode='markers',
                  name='',
                  marker=dict(symbol='dot',
                                size=18, 
                                color='#6175c1',    #'#DB4551', 
                                line=dict(color='rgb(50,50,50)', width=1)
                                ),
                  text=labels,
                  hoverinfo='text',
                  opacity=0.8
                  )

# Create Text Inside the Circle via Annotations

def make_annotations(pos, text, font_size=10, 
                     font_color='rgb(250,250,250)'):
    L=len(pos)
    if len(text)!=L:
        raise ValueError('The lists pos and text must have the same len')
    annotations = go.Annotations()
    for k in range(L):
        annotations.append(
            go.Annotation(
                text=labels[k], # or replace labels with a different list 
                                # for the text within the circle  
                x=pos[k][0], y=2*M-position[k][1],
                xref='x1', yref='y1',
                font=dict(color=font_color, size=font_size),
                showarrow=False)
        )
    return annotations  

# Add Axis Specifications and Create the Layout

axis = dict(showline=False, # hide axis line, grid, ticklabels and  title
            zeroline=False,
            showgrid=False,
            showticklabels=False,
            )

layout = dict(title= 'Tree with Reingold-Tilford Layout',  
              annotations=make_annotations(position, v_label),
              font=dict(size=12),
              showlegend=False,
              xaxis=go.XAxis(axis),
              yaxis=go.YAxis(axis),          
              margin=dict(l=40, r=40, b=85, t=100),
              hovermode='closest',
              plot_bgcolor='rgb(248,248,248)'          
              )

# Plot

data=go.Data([lines, dots])
fig=dict(data=data, layout=layout)
fig['layout'].update(annotations=make_annotations(position, v_label))
py.iplot(fig, filename='Tree-Reingold-Tilf')
# use py.plot instead of py.iplot if you're not using a Jupyter notebook

Output

4 Comments

I get an incomprehensible error message from this: DeprecationWarning Traceback (most recent call last) <ipython-input-44-cfbb1d309447> in <module>() ----> 4 import igraph DeprecationWarning: To avoid name collision with the igraph project, this visualization library has been renamed to 'jgraph'. Please upgrade when convenient. I do not know what to upgrade: igraph, jgraph, or something else. I have the latest versions of everything. Rewriting your code to refer to jgraph didn't work. pip install jgraph didn't work: jgraph has no Graph member. etc. :(
I got this to work, but it required setting up an account with plotly, so I looked for free alternatives. python-igraph (NOT the same as igraph) has some plotting capability in it igraph.org/python/doc/tutorial/tutorial.html. It's hard to install; on Mac OS X, after a painful trip down the rabbit hole, "brew install cairo" turned out to be necessary and sufficient.
why am I getting TypeError: object of type 'map' has no len()
3

For a 2021 solution, I wrote a Python wrapper of the TreantJS library. The package creates an HTML file with a tree visualization. The user can optionally invoke R's webshot library to render high-res screenshots of the trees. The package is quite new, so any PRs, bug reports, or feature requests in the issues would be much appreciated! See: https://github.com/Luke-Poeppel/treeplotter.

The package has some annoying installation requirements (see Installation.md), so I wrote a MacOS installation helper (tested on Catalina and Big Sur). Any tips on reducing these constraints would also be welcome.

enter image description here

enter image description here

Comments

2

It's expirmental, but Google has a GraphViz api. It's convenient if you just want to quickly visualize a graph, but don't want to install any software.

2 Comments

This API is deprecated and turned off
13 years later, this helped me a lot! It's now : developers.google.com/chart?csw=1

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.