Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Graphviz: Make all nodes the same size as the largest

I am trying to configure my Digraph call so that each node uses the largest width and height required. Given the image below, each node would be the width of the first node and the height of the second. I have looked at the fixedsize attribute but it doesn't seem to be a fit. If fixedsize is set to true, the limits must be specified. If possible, I would rather have this automatically determined. The maximum required will depend on the node labels of a given graph and won't always be the same.

enter image description here

Sample setup:

dot = Digraph(comment="Example 1",
          format='png',
          edge_attr={'color':'black', 
                     'style':'filled'},
          graph_attr={'fixedsize':'false', 
                      'bgcolor':'transparent'},
          node_attr={'fontname':'bold',
                     'fontsize':'11', 
                     'shape':'sqaure', 
                     'color':'black', 
                     'style':'filled', 
                     'fillcolor':'lightsteelblue3'})

fixedsize: If false, the size of a node is determined by smallest width and height needed to contain its label and image, if any, with a margin specified by the margin attribute. The width and height must also be at least as large as the sizes specified by the width and height attributes, which specify the minimum values for these parameters. If true, the node size is specified by the values of the width and height attributes only and is not expanded to contain the text label. There will be a warning if the label (with margin) cannot fit within these limits. If the fixedsize attribute is set to shape, the width and height attributes also determine the size of the node shape, but the label can be much larger. Both the label and shape sizes are used when avoiding node overlap, but all edges to the node ignore the label and only contact the node shape. No warning is given if the label is too large.

Edit: A messy example, but an example none the less. I built the graph in 'gv' format, processed heights and widths, and rebuilt the graph.

from graphviz import Digraph

dot = Digraph(comment="Example 1",
              format='gv',
              edge_attr={'color':'brown', 
                         'style':'filled'},
              graph_attr={'rankdir':'LR', 
                          'bgcolor':'transparent'},
              node_attr={'fontsize':'11', 
                         'shape':'sqaure', 
                         'color':'black',
                        'style':'filled',
                        'fillcolor':'antiquewhite'})
# nodes and edges
dot.node('1', 'This is the longest width')
dot.node('2', 'This\nis\nthe\nlargest\nheight')
dot.node('3', 'Small')
dot.edges(['12','23'])

def get_node_max(digraph):
    import re
    heights = [height.split('=')[1] for height in re.findall('height=[0-9.]+', str(digraph))]
    widths = [width.split('=')[1] for width in re.findall('width=[0-9.]+', str(digraph))]
    heights.sort(key=float)
    widths.sort(key=float)  
    return heights[len(heights)-1], widths[len(widths)-1]

params = {'format':'png', 'fixedsize':'false', 'width':'1', 'height':'1'}

params['height'], params['width'] = get_node_max(dot.pipe())


dot = Digraph(comment="Example 1",
              format=params['format'],
              edge_attr={'color':'brown', 
                         'style':'filled'},
              graph_attr={'rankdir':'LR', 
                          'bgcolor':'transparent'},
              node_attr={'fixedsize':params['fixedsize'],
                         'width':params['width'],
                         'height':params['height'],
                         'fontsize':'11', 
                         'shape':'sqaure', 
                         'color':'black',
                        'style':'filled',
                        'fillcolor':'antiquewhite'})
# nodes and edges
dot.node('1', 'This is the longest width')
dot.node('2', 'This\nis\nthe\nlargest\nheight')
dot.node('3', 'Small')
dot.edges(['12','23'])

dot.render('example-graphviz.gv', view=True)

enter image description here

like image 575
10SecTom Avatar asked Feb 20 '18 14:02

10SecTom


1 Answers

You can add explicit fixed width and height node-attributes, e.g.

node_attr={'fixedsize': 'true',
           'width': '2',
           'height': '1.5',
           ...}

This forces all nodes to have the same size.

Of course, you have to manually determine the "right" values for width and height...

like image 124
Flopp Avatar answered Sep 17 '22 12:09

Flopp