C
C1 C2
C1a C1b C2a C2b
Where C, C1, etc.. are the multiline string blocks referred to above.
Does anybody know of a tool that can do this. Here is an example,
somewhat long because I have to create the multiline strings.
from __future__ import division, generators
def enumerate(seq):
"Waiting for python 2.3"
for i in range(len(seq)):
yield i, seq[i]
class O:
def __init__(self, text):
self.text = text
def __str__(self):
return self.text
class Node:
def __init__(self, o):
self.node = o
self.children = []
def __str__(self):
s = ''
#s += str(self.node) + '\n\n'
if len(self.children)==0: return s
childStrs = [str(child.node) for child in self.children]
lines = [[] for tmp in childStrs]
for lineNum, t in enumerate(childStrs):
lines[lineNum].extend(t.split('\n'))
maxLines = max([len(l) for l in lines])
sep = ' '
for lineNum in range(maxLines):
row = ''
for childNum in range(len(childStrs)):
row += lines[childNum][lineNum] + sep
s += row + '\n'
s += '\n\n'
for l in self.children:
s += str(l)
return s
n0 = Node(O("""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(O("""1 2 3 0
1 2 3 4
1 2 1 5
1 2 1 1
----------
1 1 0 0"""))
n2 = Node(O("""4 3 2 2
4 3 2 7
2 3 2 3
2 3 2 9
----------
0 1 1 0"""))
n1a = Node(O("""1 2 1 5
1 2 1 1
----------
1 1 1 0"""))
n1b = Node(O("""1 2 3 0
1 2 3 4
----------
1 1 1 0"""))
n2a = Node(O("""2 3 2 3
2 3 2 9
----------
1 1 1 0"""))
n2b = Node(O("""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
Which prints:
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
1 2 1 1 1 2 3 4
---------- ----------
1 1 1 0 1 1 1 0
2 3 2 3 4 3 2 2
2 3 2 9 4 3 2 7
---------- ----------
1 1 1 0 1 1 1 0
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
Thanks,
John Hunter
>
> 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
[P&M]
John -
Do you strictly require plain text output? If not, look into
graphiz. It's fairly easy to generate dot files from python and
then generate output in postscript or in a bitmap format (jpg,
png, etc) using the graphiz tools.
graphiz can be had from http://www.graphviz.org
There is a python interface to graphviz available from
http://www.cs.brown.edu/~er/software , but I have not used it.
graphviz's output is customizable to some extant, and looks
rather nice.
HTH,
Bill
--
Bill.Scherer at Verizon Wireless
RHCE 807101044903581
Hey "dot" is great! I didn't know about it before readin your post.
In a very short time I came out with the following recipe to draw
Python inheritance hierarchies (which I post since it is pretty
short and useful ;):
"How to draw inheritance hierarchies via dot"
import os
def label(i,n):
if n>1: return '[label="%s"]' % (i+1)
return ""
def dotMRO(cls):
"Generates the dot code for the MRO directed graph"
yield "digraph MRO_of_%s{\n" % cls.__name__
for c in cls.__mro__:
n=len(c.__bases__)
yield ' '.join([' %s -> %s %s;' % (b.__name__,c.__name__,label(i,n))
for i,b in enumerate(c.__bases__)])
yield '}'
# Example hierarchy
O = object
class F(O): pass
class E(O): pass
class D(O): pass
class G(O): pass
class C(F,D,G): pass
class B(E,D): pass
class A(B,C): pass
# creates the graph
dotcode='\n'.join(dotMRO(A)); print dotcode
os.system('echo "%s" | dot -Tps > prova.ps' % dotcode)
os.system('gv prova.ps&')
Assuming you have "dot" and the standard Unix tools installed this
will generate a very nice diagram. I am open to suggestion to improve it,
since this is may first trial with "dot". I am quite impressed by the
easy of use.
Very nice!
Michele
>
>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
Some graphs of hidden Markov models, also drawn by dot (GraphViz) code
generated by a very similar Python program can be found in the figures (scroll
down a bit, on the left) for the paper at
http://www.biomedcentral.com/1472-6947/2/9
Tim C
Decided to try the tree print I did for John Hunter in pphunter.py on your class tree:
explore is just a quick-n-dirty to make the tree.
====< mrog.py >=====================
# Example hierarchy
O = object
class F(O): pass
class E(O): pass
class D(O): pass
class G(O): pass
class C(F,D,G): pass
class B(E,D): pass
class A(B,C): pass
import pphunter
def explore(cls, tree):
node = pphunter.Node(pphunter.TextBox(cls.__name__))
tree.children.append(node)
for b in cls.__bases__: explore(b, node)
root = pphunter.Node(pphunter.TextBox('root'))
explore(A, root)
print root.children[0].showInPage(20, 60)
====================================
Result:
[21:26] C:\pywk\clp>python mrog.py
+-+
|A|
+-+
+-+ +-+
|B| |C|
+-+ +-+
+-+ +-+ +-+ +-+ +-+
|E| |D| |F| |D| |G|
+-+ +-+ +-+ +-+ +-+
+------+ +------+ +------+ +------+ +------+
|object| |object| |object| |object| |object|
+------+ +------+ +------+ +------+ +------+
I guess I will have to do connector lines ;-)
BTW, I found a bug in the showInPage method of pphunter.Node. It should be
--
def showInPage(self, pageHeight=6*11, pageWidth=78):
return '\n'.join(self.boxlines(pageHeight, pageWidth))
--
(I capitalized pageHeight and page Width) . Boo :-(
(see 'pretty printing graphs' thread).
Regards,
Bengt Richter
Sorry.
Regards,
Bengt Richter
>"Scherer, Bill" <Bill.S...@verizonwireless.com> wrote in message news:<mailman.105941338...@python.org>...
>
>Hey "dot" is great! I didn't know about it before readin your post.
>
>In a very short time I came out with the following recipe to draw
>Python inheritance hierarchies (which I post since it is pretty
>short and useful ;):
>
Well, here's the version with connectors:
====< pptree.py >===============================================
# pptree.py v 0.01 -- 20030728 22:20:17 bokr
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:
# do connector line (with wasteful repetition)
conn = ''.join(['+'.center(sep and child.treebb()[1]+sep or boxWidth)
for child in node.children])
conn = conn.center(boxWidth)
first = conn.find('+'); last = conn.rfind('+')
conn = conn[:first] + conn[first:last].replace(' ','-') + conn[last:]
center = '+'.center(boxWidth).find('+') # whatever the alg is
conn = list(conn); conn[center]='|'; conn = ''.join(conn)
render[iLine] = conn
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(height,width): # dimensions of chart
# Example hierarchy
O = object
class F(O): pass
class E(O): pass
class D(O): pass
class G(O): pass
class C(F,D,G): pass
class B(E,D): pass
class A(B,C): pass
def explore(cls, tree):
node = Node(TextBox(cls.__name__))
tree.children.append(node)
for b in cls.__bases__: explore(b, node)
root = Node(TextBox('root'))
explore(A, root)
print
print root.children[0].showInPage(height, width)
if __name__ == '__main__':
import sys; args = sys.argv[1:]
height = args and int(args.pop(0)) or 20
width = args and int(args.pop(0)) or 60
test(height,width)
================================================================
Results: first 50 wide, then 90
[22:54] C:\pywk\clp>pptree.py 20 50
+-+
|A|
+-+
+-------------|----------+
+-+ +-+
|B| |C|
+-+ +-+
+----|----+ +--------|--------+
+-+ +-+ +-+ +-+ +-+
|E| |D| |F| |D| |G|
+-+ +-+ +-+ +-+ +-+
| | | | |
+------+ +------+ +------+ +------+ +------+
|object| |object| |object| |object| |object|
+------+ +------+ +------+ +------+ +------+
[22:54] C:\pywk\clp>pptree.py 20 90
+-+
|A|
+-+
+-----------------------|--------------------+
+-+ +-+
|B| |C|
+-+ +-+
+---------|---------+ +---------------|---------------+
+-+ +-+ +-+ +-+ +-+
|E| |D| |F| |D| |G|
+-+ +-+ +-+ +-+ +-+
| | | | |
+------+ +------+ +------+ +------+ +------+
|object| |object| |object| |object| |object|
+------+ +------+ +------+ +------+ +------+
The code is pretty hacky, but I wanted to show the art ;-)
BTW, TextBox can accept a multiline string, and finds the bounding box (without trimming blanks).
Regards,
Bengt Richter
import os
def label(i,n):
if n>1: return '[label="%s"]' % (i+1)
return ""
def dotMRO(cls):
"Generate the dot code for the MRO directed graph"
yield "digraph MRO_of_%s{\n" % cls.__name__
for c in cls.__mro__:
n=len(c.__bases__)
yield ' '.join([
' edge [style=solid]; %s -> %s %s;' %
(b.__name__,c.__name__,label(i,n))
for i,b in enumerate(c.__bases__)])
if type(c) is not type: yield \
' edge [style=dashed]; %s -> %s;' % (type(c).__name__,c.__name__)
yield '}'
class M(type): pass
O=object
class F(O): pass
class E(O): pass
class D(O): pass
class G(O): __metaclass__=M
class C(F,D,G): pass
class B(E,D): pass
class A(B,C): pass
dotcode='\n'.join(dotMRO(A)); print dotcode
See the graph at
http://www.phyast.pitt.edu/~micheles/prova.ps
Here I had a problem due to my lack of knowledge of "dot":
class C inherits from F,D and G (in this order, see the labels
1,2,3). However, "dot" draws D before F and, without looking
at the labels, one would think that D comes before F, which
is not the case. IOW, the line FC should cross the line DC,
and the F-arrow should be on the left of the D-arrow.
Is there any way of fixing that?
TIA,
Michele
Bengt> How about (I added a name in the first node line for
Bengt> debugging, and boxing): (code follows output). Not tested
Bengt> much ;-)
Thanks Bengt - that looks great. You really should be on the payroll.
I won't have time until tonight to wrap my head around your code, but
I think I'll add a to_dot method to the Node class which generates dot
output, so I can use your ascii output for day-to-day stuff, and then
go to dot for publication quality.
Thanks all for the suggestions,
JDH
Thanks Bengt,
this give me some idea. I was writing something similar three or four
days ago, but I was stuck with the connection lines. I had the very
bad idea of drawing them as dots, but this is the unhappy result in
a similar hierarchy:
+------+
|object|
+------+..
. . ...
. . ...
. . ...
+------+ +------+ +------+
|ClassD| |ClassE| |ClassF|
+------+.. .+------+ +------+
. ..... .
. ... ... .
. ... ... .
+------+ +------+
|ClassB| |ClassC|
+------+ .....+------+
. .....
. .....
. .....
+------+..
|ClassA|
+------+
I think I will copy your connection lines idea, if not the code ;)
Michele
Bengt> should be -- def showInPage(self, pageHeight=6*11,
Bengt> pageWidth=78): return '\n'.join(self.boxlines(pageHeight,
Bengt> pageWidth)) -- [...]
I think I may have discovered another bug. In the longish example below,
the children of n2 are n20 and n21
n2.children.extend([n20, n21])
These children are the branch:
|------------------+
+-------+ +-------+
|3 4 5 6| |6 4 5 6|
|3 4 5 6| |-------|
|-------| |1 1 1 1|
|1 1 1 1| +-------+
+-------+
However, if you run your pprint on this example, they appear below the
n4 branch.
Haven't had a chance to grok the code yet -- I just came across this
bug when using your code on a test case for a projective clustering
neural network algorithm I'm implementing. The example is from Cao
and Wu, Neural Networks 15(2002) 105-120.
def test3():
n = Node(TextBox("""1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
6 7 8 9
1 2 3 4
3 4 5 6
2 3 4 5
6 4 5 6
4 2 3 1
6 7 1 2
4 5 6 7
-------
0 0 0 0
"""))
n0 = Node(TextBox("""1 2 3 4
1 2 3 4
4 2 3 1
-------
0 1 1 0
"""))
n1 = Node(TextBox("""2 3 4 5
2 3 4 5
-------
1 1 1 1
"""))
n2 = Node(TextBox("""3 4 5 6
3 4 5 6
6 4 5 6
-------
0 1 1 1
"""))
n3 = Node(TextBox("""4 5 6 7
4 5 6 7
-------
1 1 1 1
"""))
n4 = Node(TextBox("""6 7 8 9
6 7 1 2
-------
1 1 0 0
"""))
n.children.extend([n0, n1, n2, n3, n4])
n00 = Node(TextBox("""1 2 3 4
1 2 3 4
-------
1 1 1 1
"""))
n01 = Node(TextBox("""4 2 3 1
-------
1 1 1 1
"""))
n0.children.extend([n00, n01])
n20 = Node(TextBox("""3 4 5 6
3 4 5 6
-------
1 1 1 1
"""))
n21 = Node(TextBox("""6 4 5 6
-------
1 1 1 1
"""))
n2.children.extend([n20, n21])
n40 = Node(TextBox("""6 7 8 9
-------
1 1 1 1
"""))
n41 = Node(TextBox("""6 7 1 2
-------
1 1 1 1
"""))
n4.children.extend([n40, n41])
print n
>>>>>> "Bengt" == Bengt Richter <bo...@oz.net> writes:
>
> Bengt> How about (I added a name in the first node line for
> Bengt> debugging, and boxing): (code follows output). Not tested
> Bengt> much ;-)
>
>Thanks Bengt - that looks great. You really should be on the payroll.
>
Email me for particulars on how to send money ;-))
>I won't have time until tonight to wrap my head around your code, but
>I think I'll add a to_dot method to the Node class which generates dot
>output, so I can use your ascii output for day-to-day stuff, and then
>go to dot for publication quality.
If you have an interactive window with tty font with box characters, it could
look pretty nice for "day-to-day", I think (though requiring a little more logic
for choosing boxing and connection line characters).
>
>Thanks all for the suggestions,
You're welcome. Be aware that I just copied your original post and
vimmed at it until something emerged. It's pretty brute force, recomputing
a lot, etc etc. And not very well factored. OTOH, it seems to work, within its limits ;-)
It could use some sanity checks etc. though.
BTW, also in this thread there is a version with connector lines
called pptree.py, in case that is of interest.
I think to make a real tool, I would design differently. Off hand IWT using a random access
2-dimensional mutable character array as a page "canvas" to paint on would eliminate
some of the constraints on the layout that are inherent in the way I did it in pptree.
(I.e., hierarchical box model where any box may be contain a centered smaller
box connected to one row of boxes underneath it, and any of those may similarly either
be a single box or contain a smaller top box with its row of children, etc., so each box
is only a matter of one top single box and one row of child boxes, whatever the content of
the child boxes. Then its just a matter of dealing with the different sizes.)
Also more abstract element definitions and drawing primitives could allow for subclassing
for different output media like ascii, tty/boxchars, tkinter, postscript, etc.
I'm curious as to what your actual text blocks represent...
Regards,
Bengt Richter
>>>>>> "Bengt" == Bengt Richter <bo...@oz.net> writes:
>
> Bengt> should be -- def showInPage(self, pageHeight=6*11,
> Bengt> pageWidth=78): return '\n'.join(self.boxlines(pageHeight,
> Bengt> pageWidth)) -- [...]
>
>I think I may have discovered another bug. In the longish example below,
>the children of n2 are n20 and n21
>
> n2.children.extend([n20, n21])
>
>These children are the branch:
>
> |------------------+
> +-------+ +-------+
> |3 4 5 6| |6 4 5 6|
> |3 4 5 6| |-------|
> |-------| |1 1 1 1|
> |1 1 1 1| +-------+
> +-------+
>
>However, if you run your pprint on this example, they appear below the
>n4 branch.
>
I suspect the default "page" width of 78 is insufficient. I modded your
data to include a node names (e.g., see first two below)
e.g.,
>Haven't had a chance to grok the code yet -- I just came across this
>bug when using your code on a test case for a projective clustering
>neural network algorithm I'm implementing. The example is from Cao
>and Wu, Neural Networks 15(2002) 105-120.
>
> http://www.sciencedirect.com/science?_ob=ArticleURL&_udi=B6T08-43T2MC4-1&_user=5745&_handle=W-WA-A-A-AD-MsSAYZA-UUW-AUCEZCZEBD-AZZEEDDUV-AD-U&_fmt=full&_coverDate=01%2F31%2F2002&_rdoc=10&_orig=browse&_srch=%23toc%234856%232002%23999849998%23290257!&_cdi=4856&view=c&_acct=C000001358&_version=1&_urlVersion=0&_userid=5745&md5=61f59ff40e082d56154538b436b0010e
>
>
>def test3():
#> n = Node(TextBox("""1 2 3 4
n = Node(TextBox("""n
1 2 3 4
>2 3 4 5
>3 4 5 6
>4 5 6 7
>6 7 8 9
>1 2 3 4
>3 4 5 6
>2 3 4 5
>6 4 5 6
>4 2 3 1
>6 7 1 2
>4 5 6 7
>-------
>0 0 0 0
>"""))
>
#> n0 = Node(TextBox("""1 2 3 4
n0 = Node(TextBox("""n0
1 2 3 4
>1 2 3 4
>4 2 3 1
>-------
>0 1 1 0
>"""))
>
[...]
> n4.children.extend([n40, n41])
>
> print n
To specify a page wide enough here, try
print n.showInPage(35, 90)
With the name-modded data, I got
[11:56] C:\pywk\clp>pptree_t3.py 35 90
+-------+
| n|
|1 2 3 4|
|2 3 4 5|
|3 4 5 6|
|4 5 6 7|
|6 7 8 9|
|1 2 3 4|
|3 4 5 6|
|2 3 4 5|
|6 4 5 6|
|4 2 3 1|
|6 7 1 2|
|4 5 6 7|
|-------|
|0 0 0 0|
+-------+
+---------------+----------------|---------------+----------------+
+-------+ +-------+ +-------+ +-------+ +-------+
| n0| | n1| | n2| | n3| | n4|
|1 2 3 4| |2 3 4 5| |3 4 5 6| |4 5 6 7| |6 7 8 9|
|1 2 3 4| |2 3 4 5| |3 4 5 6| |4 5 6 7| |6 7 1 2|
|4 2 3 1| |-------| |6 4 5 6| |-------| |-------|
|-------| |1 1 1 1| |-------| |1 1 1 1| |1 1 0 0|
|0 1 1 0| +-------+ |0 1 1 1| +-------+ +-------+
+-------+ +-------+ +----|----+
+----|----+ +----|----+ +-------+ +-------+
+-------+ +-------+ +-------+ +-------+ | n40| | n41|
| n00| | n01| | n20| | n21| |6 7 8 9| |6 7 1 2|
|1 2 3 4| |4 2 3 1| |3 4 5 6| |6 4 5 6| |-------| |-------|
|1 2 3 4| |-------| |3 4 5 6| |-------| |1 1 1 1| |1 1 1 1|
|-------| |1 1 1 1| |-------| |1 1 1 1| +-------+ +-------+
|1 1 1 1| +-------+ |1 1 1 1| +-------+
+-------+ +-------+
I guess it would be good to make it self-expanding if the default page is too small, or raise
an informative exception.
Regards,
Bengt Richter