0

I want to generate a long hierarchy chart of number, but the chart coming out is pixelated and cannot be zoomed to reveal its details. I'm using networkx and matplotlib to generate this chart. This is the array that I want to generate hierarchy of.

tree = [(1, 2), (2, 4), (4, 8), (8, 16), (16, 5), (5, 10), (10, 3), (3, 6), (10, 20), (20, 40), (40, 13), (13, 26), (26, 52), (52, 17), (17, 34), (34, 11), (11, 22), (22, 7), (7, 14), (14, 28), (28, 9), (6, 12), (40, 80), (80, 160), (160, 53), (53, 106), (106, 35), (35, 70), (70, 23), (23, 46), (46, 15), (9, 18), (22, 44), (44, 88), (88, 29), (29, 58), (58, 19), (16, 32), (32, 64), (64, 21), (12, 24), (19, 38), (38, 76), (76, 25), (46, 92), (92, 184), (184, 61), (61, 122), (122, 244), (244, 488), (488, 976), (976, 325), (325, 650), (650, 1300), (1300, 433), (433, 866), (866, 1732), (1732, 577), (577, 1154), (1154, 2308), (2308, 4616), (4616, 9232), (9232, 3077), (3077, 6154), (6154, 2051), (2051, 4102), (4102, 1367), (1367, 2734), (2734, 911), (911, 1822), (1822, 3644), (3644, 7288), (7288, 2429), (2429, 4858), (4858, 1619), (1619, 3238), (3238, 1079), (1079, 2158), (2158, 719), (719, 1438), (1438, 479), (479, 958), (958, 319), (319, 638), (638, 1276), (1276, 425), (425, 850), (850, 283), (283, 566), (566, 1132), (1132, 377), (377, 754), (754, 251), (251, 502), (502, 167), (167, 334), (334, 668), (668, 1336), (1336, 445), (445, 890), (890, 1780), (1780, 593), (593, 1186), (1186, 395), (395, 790), (790, 263), (263, 526), (526, 175), (175, 350), (350, 700), (700, 233), (233, 466), (466, 155), (155, 310), (310, 103), (103, 206), (206, 412), (412, 137), (137, 274), (274, 91), (91, 182), (182, 364), (364, 121), (121, 242), (242, 484), (484, 161), (161, 322), (322, 107), (107, 214), (214, 71), (71, 142), (142, 47), (47, 94), (94, 31), (31, 62), (62, 124), (124, 41), (41, 82), (82, 27), (15, 30), (25, 50), (50, 100), (100, 33)]

graph is generated as follows:

G=nx.Graph()
G.add_edges_from(tree)
pos = tg.hierarchy_pos(G,1)    
nx.draw(G, pos=pos, with_labels=True)

The resulting hierarchy looks like this:enter image description here As seen, the graph is a pixelated image and cannot be zoomed to reveal the details. How can I generate a vectorized version of this graph.

The hierarchy_pos function is taken from Can one get hierarchical graphs from networkx with python 3?

Frodnar
  • 2,129
  • 2
  • 6
  • 20

1 Answers1

0

There are actually two separate problems:

  1. The position of the nodes/labels are overlapping because the figure is not large enough at the default node/text size.
  2. The image needs to be saved in a vectorized format.

The snippet below adjusts the plot size and saves a vectorized image, but the full code including the definition of hierarchy_pos is copied way down at the bottom of the post for posterity.

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(20, 50)) # increase figsize
nx.draw(G, pos=pos, with_labels=True)
fig.savefig('filename.eps', format='eps') #save vectorized image

Here is .jpg just to show the layout difference. Imgur (StackOverflow's image hosting provider) doesn't support vectorized images, so I can't upload it here.

Larger_networkx_tree


Full copy-pastable code:

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

    
def hierarchy_pos(G, root=None, width=1., vert_gap = 0.2, vert_loc = 0, xcenter = 0.5):

    '''
    From Joel's answer at https://stackoverflow.com/a/29597209/2966723.  
    Licensed under Creative Commons Attribution-Share Alike 
    
    If the graph is a tree this will return the positions to plot this in a 
    hierarchical layout.
    
    G: the graph (must be a tree)
    
    root: the root node of current branch 
    - if the tree is directed and this is not given, 
      the root will be found and used
    - if the tree is directed and this is given, then 
      the positions will be just for the descendants of this node.
    - if the tree is undirected and not given, 
      then a random choice will be used.
    
    width: horizontal space allocated for this branch - avoids overlap with other branches
    
    vert_gap: gap between levels of hierarchy
    
    vert_loc: vertical location of root
    
    xcenter: horizontal location of root
    '''
    if not nx.is_tree(G):
        raise TypeError('cannot use hierarchy_pos on a graph that is not a tree')

    if root is None:
        if isinstance(G, nx.DiGraph):
            root = next(iter(nx.topological_sort(G)))  #allows back compatibility with nx version 1.11
        else:
            root = random.choice(list(G.nodes))

    def _hierarchy_pos(G, root, width=1., vert_gap = 0.2, vert_loc = 0, xcenter = 0.5, pos = None, parent = None):
        '''
        see hierarchy_pos docstring for most arguments

        pos: a dict saying where all nodes go if they have been assigned
        parent: parent of this branch. - only affects it if non-directed

        '''
    
        if pos is None:
            pos = {root:(xcenter,vert_loc)}
        else:
            pos[root] = (xcenter, vert_loc)
        children = list(G.neighbors(root))
        if not isinstance(G, nx.DiGraph) and parent is not None:
            children.remove(parent)  
        if len(children)!=0:
            dx = width/len(children) 
            nextx = xcenter - width/2 - dx/2
            for child in children:
                nextx += dx
                pos = _hierarchy_pos(G,child, width = dx, vert_gap = vert_gap, 
                                    vert_loc = vert_loc-vert_gap, xcenter=nextx,
                                    pos=pos, parent = root)
        return pos

            
    return _hierarchy_pos(G, root, width, vert_gap, vert_loc, xcenter)
            

tree = [(1, 2), (2, 4), (4, 8), (8, 16), (16, 5), (5, 10), (10, 3), (3, 6), (10, 20), (20, 40), (40, 13), (13, 26), (26, 52), (52, 17), (17, 34), (34, 11), (11, 22), (22, 7), (7, 14), (14, 28), (28, 9), (6, 12), (40, 80), (80, 160), (160, 53), (53, 106), (106, 35), (35, 70), (70, 23), (23, 46), (46, 15), (9, 18), (22, 44), (44, 88), (88, 29), (29, 58), (58, 19), (16, 32), (32, 64), (64, 21), (12, 24), (19, 38), (38, 76), (76, 25), (46, 92), (92, 184), (184, 61), (61, 122), (122, 244), (244, 488), (488, 976), (976, 325), (325, 650), (650, 1300), (1300, 433), (433, 866), (866, 1732), (1732, 577), (577, 1154), (1154, 2308), (2308, 4616), (4616, 9232), (9232, 3077), (3077, 6154), (6154, 2051), (2051, 4102), (4102, 1367), (1367, 2734), (2734, 911), (911, 1822), (1822, 3644), (3644, 7288), (7288, 2429), (2429, 4858), (4858, 1619), (1619, 3238), (3238, 1079), (1079, 2158), (2158, 719), (719, 1438), (1438, 479), (479, 958), (958, 319), (319, 638), (638, 1276), (1276, 425), (425, 850), (850, 283), (283, 566), (566, 1132), (1132, 377), (377, 754), (754, 251), (251, 502), (502, 167), (167, 334), (334, 668), (668, 1336), (1336, 445), (445, 890), (890, 1780), (1780, 593), (593, 1186), (1186, 395), (395, 790), (790, 263), (263, 526), (526, 175), (175, 350), (350, 700), (700, 233), (233, 466), (466, 155), (155, 310), (310, 103), (103, 206), (206, 412), (412, 137), (137, 274), (274, 91), (91, 182), (182, 364), (364, 121), (121, 242), (242, 484), (484, 161), (161, 322), (322, 107), (107, 214), (214, 71), (71, 142), (142, 47), (47, 94), (94, 31), (31, 62), (62, 124), (124, 41), (41, 82), (82, 27), (15, 30), (25, 50), (50, 100), (100, 33)]

G=nx.Graph()
G.add_edges_from(tree)
pos = hierarchy_pos(G,1)

fig = plt.figure(figsize=(20, 50)) # increase figsize
nx.draw(G, pos=pos, with_labels=True)

fig.savefig('filename.eps', format='eps') #save vectorized image
Frodnar
  • 2,129
  • 2
  • 6
  • 20