How to draw trees left to right

Question:

Consider the tree below.

import matplotlib.pyplot as plt
import networkx as nx
import pydot
from networkx.drawing.nx_pydot import graphviz_layout

T = nx.balanced_tree(2, 5)

for line in nx.generate_adjlist(T):
    print(line)

pos = graphviz_layout(T, prog="dot")
nx.draw(T, pos, node_color="y", edge_color='#909090', node_size=200, with_labels=True)

plt.show()

enter image description here

How can I draw this left to right so that the whole image is rotated by 90 degrees with the root on the right?

Asked By: graffe

||

Answers:

You can do this with the rankdir attribute from graphviz, which can be set on a networkx graph by:

T.graph["graph"] = dict(rankdir="RL")

networkx issue #3547 gives some more info about setting graph attributes.

Answered By: yut23

If you want to have fine-grained control over node positions (which includes rotating the whole graph) you can actually set each node’s position explicitly. Here’s a way to do that that produces a ‘centred’ hierarchy, left to right.

import itertools
import matplotlib.pyplot as plt
import networkx as nx

plt.figure(figsize=(12,8))
subset_sizes = [1, 2, 4, 8, 16, 32]

def multilayered_graph(*subset_sizes):
    extents = nx.utils.pairwise(itertools.accumulate((0,) + subset_sizes))
    layers = [range(start, end) for start, end in extents]
    G = nx.Graph()
    for (i, layer) in enumerate(layers):
      G.add_nodes_from(layer, layer=i)
    for layer1, layer2 in nx.utils.pairwise(layers):
      G.add_edges_from(itertools.product(layer1, layer2))
    return G

# Instantiate the graph
G = multilayered_graph(*subset_sizes)
# use the multipartite layout
pos = nx.multipartite_layout(G, subset_key="layer")
nodes = G.nodes
nodes_0  = set([n for n in nodes if  G.nodes[n]['layer']==0])
nodes_1  = set([n for n in nodes if  G.nodes[n]['layer']==1])
nodes_2  = set([n for n in nodes if  G.nodes[n]['layer']==2])
nodes_3  = set([n for n in nodes if  G.nodes[n]['layer']==3])
nodes_4  = set([n for n in nodes if  G.nodes[n]['layer']==4])
nodes_5  = set([n for n in nodes if  G.nodes[n]['layer']==5])

# setup a position list
pos = dict()
base = 128
thisList = list(range(-int(base/2),int(base/2),1))
# then assign nodes to indices
pos.update( (n, (10, thisList[int(base/2)::int(base/2)][i])) for i, n in enumerate(nodes_0) )
pos.update( (n, (40, thisList[int(base/4)::int(base/2)][i])) for i, n in enumerate(nodes_1) )
pos.update( (n, (60, thisList[int(base/8)::int(base/4)][i])) for i, n in enumerate(nodes_2) )
pos.update( (n, (80, thisList[int(base/16)::int(base/8)][i])) for i, n in enumerate(nodes_3) )
pos.update( (n, (100, thisList[int(base/32)::int(base/16)][i])) for i, n in enumerate(nodes_4) )
pos.update( (n, (120, thisList[int(base/64)::int(base/32)][i])) for i, n in enumerate(nodes_5) )
nx.draw(G, pos, node_color='y', edge_color='grey', with_labels=True)
plt.show()

enter image description here

By using a position list, you can easily transform this graph into any number of alignments or rotations.

Notes

  1. add nodes with a layer key and use multipartite_layout to make the graph layered
  2. setup a "position list" based on the number of nodes in your widest layer (to make the layout centre-aligned, use a zero-centred list)
  3. To assign positions in each layer use basic Python list slice/skip notation to grab the right number of positions, spaced the appropriate amount apart, starting at the right position for the alignment you want
Answered By: James_SO
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.