pretty printing graphs
Bengt Richter
bokr at oz.net
Mon Jul 28 22:07:14 EDT 2003
On Mon, 28 Jul 2003 12:13:10 -0500, John Hunter <jdhunter at ace.bsd.uchicago.edu> wrote:
>
>I have a tree structure (directed acyclic graph), where each node can
>represent itself as a multi-line string that is not very wide (eg, 10
>chars per line). I would like to print the graph like
>
> C
> C1 C2
>C1a C1b C2a C2b
>
The outline format is not good? I.e.,
C
C1
C1a
C1b
C2
C2a
C2b
An outline would be simple to print recursively.
[... snip code etc ...]
>
>This does part of the work, printing the child nodes on the same rows,
>but doesn't the hierarchical part very well. What I would like is
>something like this:
>
> 1 2 3 0
> 1 2 3 4
> 1 2 1 5
> 1 2 1 1
> 4 3 2 2
> 4 3 2 7
> 2 3 2 3
> 2 3 2 9
>
> 1 2 3 0 4 3 2 2
> 1 2 3 4 4 3 2 7
> 1 2 1 5 2 3 2 3
> 1 2 1 1 2 3 2 9
> ---------- ----------
> 1 1 0 0 0 1 1 0
>
>
>1 2 1 5 1 2 3 0 2 3 2 3 4 3 2 2
>1 2 1 1 1 2 3 4 2 3 2 9 4 3 2 7
>---------- ---------- ---------- ----------
>1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0
>
>
>
How about (I added a name in the first node line for debugging, and boxing):
(code follows output). Not tested much ;-)
[19:04] C:\pywk\clp>python pphunter.py
+----------+
| n0|
|1 2 3 0|
|1 2 3 4|
|1 2 1 5|
|1 2 1 1|
|4 3 2 2|
|4 3 2 7|
|2 3 2 3|
|2 3 2 9|
+----------+
+----------+ +----------+
| n1| | n2|
|1 2 3 0| |4 3 2 2|
|1 2 3 4| |4 3 2 7|
|1 2 1 5| |2 3 2 3|
|1 2 1 1| |2 3 2 9|
|----------| |----------|
|1 1 0 0| |0 1 1 0|
+----------+ +----------+
+----------+ +----------+ +----------+ +----------+
| n1a| | n1b| | n2a| | n2b|
|1 2 1 5| |1 2 3 0| |2 3 2 3| |4 3 2 2|
|1 2 1 1| |1 2 3 4| |2 3 2 9| |4 3 2 7|
|----------| |----------| |----------| |----------|
|1 1 1 0| |1 1 1 0| |1 1 1 0| |1 1 1 0|
+----------+ +----------+ +----------+ +----------+
====< pphunter.py >==============================================
from __future__ import division, generators
def enumerate(seq):
"Waiting for python 2.3"
for i in range(len(seq)):
yield i, seq[i]
class TextBox:
def __init__(self, text):
self.text = text
lines = text.splitlines()
self.bb = len(lines)+2, max(map(len, lines))+2 # rows,cols bounding box
def __str__(self):
return self.text
class Node:
PageHeight = 6*11; PageWidth = 78
def __repr__(self): return '<Node w/ text %r ...>'%self.textBox.text.splitlines()[0]
def treebb(self): # tree bb incl this node
childMaxHeight, childTotWidth = 0, 0
for child in self.children:
h, w = child.treebb()
childMaxHeight = max(childMaxHeight, h)
childTotWidth += w
ret = childMaxHeight+self.textBox.bb[0], max(childTotWidth, self.textBox.bb[1])
return ret
def __init__(self, textBox):
self.textBox = textBox
self.children = []
def boxlines(node, boxHeight, boxWidth):
oh, ow = node.textBox.bb # this node top text box bb
th, tw = node.treebb() # minimal child tree bb incl text box at top
render = ['']*boxHeight
ofmt = '|%%%ds|'% (ow-2)
render[0] = ('+'+'-'*(ow-2)+'+').center(boxWidth)
iLine=1
for line in node.textBox.text.splitlines():
render[iLine] = (ofmt%line).center(boxWidth)
iLine += 1
render[iLine] = render[0]
iLine += 1
if node.children:
availSepSpaces = boxWidth - tw
nch = len(node.children)
sep = nch>1 and availSepSpaces//nch or 0
childBoxes = []
for child in node.children:
chh, chw = child.treebb()
childBoxes.append(child.boxlines(boxHeight-oh-1, sep and chw+sep or boxWidth))
cbhs = map(len, childBoxes); assert max(cbhs)==min(cbhs) # all child boxes same ht
for iChildline in xrange(cbhs[0]):
iLine += 1
render[iLine] = ''.join(
[childBox[iChildline] for childBox in childBoxes]
).center(boxWidth)
for iLine in range(boxHeight):
if not render[iLine]: render[iLine] = ' '*boxWidth
return render
def __str__(self):
return '\n'.join(self.boxlines(self.PageHeight, self.PageWidth))
def showInPage(self, pageHeight=6*11, pageWidth=78):
return '\n'.join(self.boxlines(PageHeight, PageWidth))
def test():
n0 = Node(TextBox("""n0
1 2 3 0
1 2 3 4
1 2 1 5
1 2 1 1
4 3 2 2
4 3 2 7
2 3 2 3
2 3 2 9
"""))
n1 = Node(TextBox("""n1
1 2 3 0
1 2 3 4
1 2 1 5
1 2 1 1
----------
1 1 0 0
"""))
n2 = Node(TextBox("""n2
4 3 2 2
4 3 2 7
2 3 2 3
2 3 2 9
----------
0 1 1 0
"""))
n1a = Node(TextBox("""n1a
1 2 1 5
1 2 1 1
----------
1 1 1 0
"""))
n1b = Node(TextBox("""n1b
1 2 3 0
1 2 3 4
----------
1 1 1 0
"""))
n2a = Node(TextBox("""n2a
2 3 2 3
2 3 2 9
----------
1 1 1 0
"""))
n2b = Node(TextBox("""n2b
4 3 2 2
4 3 2 7
----------
1 1 1 0
"""))
n0.children.extend([n1, n2])
n1.children.extend([n1a, n1b])
n2.children.extend([n2a, n2b])
print n0
if __name__ == '__main__': test()
=================================================================
Regards,
Bengt Richter
More information about the Python-list
mailing list