Testing lolviz

I liked how the lolviz module looked like. Let's try it!

In [1]:
%load_ext watermark
%watermark -v -m -p lolviz
CPython 3.6.5
IPython 6.4.0

lolviz n

compiler   : GCC 7.3.0
system     : Linux
release    : 4.15.0-23-generic
machine    : x86_64
processor  : x86_64
CPU cores  : 4
interpreter: 64bit
In [3]:
from lolviz import *

Testing naively

In [4]:
data = ['hi', 'mom', {3, 4}, {"parrt": "user"}]
g = listviz(data)
print(g.source) # if you want to see the graphviz source
g.view() # render and show graphviz.files.Source object
    digraph G {
        nodesep=.05;
        node [penwidth="0.5", width=.1,height=.1];
    node139621679300936 [shape="box", space="0.0", margin="0.01", fontcolor="#444443", fontname="Helvetica", label=<<table BORDER="0" CELLBORDER="0" CELLSPACING="0">
<tr>
<td cellspacing="0" cellpadding="0" bgcolor="#fefecd" border="1" sides="br" valign="top"><font color="#444443" point-size="9">0</font></td>
<td cellspacing="0" cellpadding="0" bgcolor="#fefecd" border="1" sides="br" valign="top"><font color="#444443" point-size="9">1</font></td>
<td cellspacing="0" cellpadding="0" bgcolor="#fefecd" border="1" sides="br" valign="top"><font color="#444443" point-size="9">2</font></td>
<td cellspacing="0" cellpadding="0" bgcolor="#fefecd" border="1" sides="b" valign="top"><font color="#444443" point-size="9">3</font></td>
</tr>
<tr>
<td port="0" bgcolor="#fefecd" border="1" sides="r" align="center"><font point-size="11">'hi'</font></td>
<td port="1" bgcolor="#fefecd" border="1" sides="r" align="center"><font point-size="11">'mom'</font></td>
<td port="2" bgcolor="#fefecd" border="1" sides="r" align="center"><font point-size="11">{3, 4}</font></td>
<td port="3" bgcolor="#fefecd" border="0" align="center"><font point-size="11">{'parrt': 'user'}</font></td>
</tr></table>
>];
}

Out[4]:
'Source.gv.pdf'

It opened a window showing me this image:

Testing from within a Jupyter notebook

I test here all the features of lolviz :

List

In [13]:
squares = [ i**2 for i in range(10) ]
In [14]:
squares
Out[14]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
In [15]:
listviz(squares)
Out[15]:
G node139621679302728 0 1 2 3 4 5 6 7 8 9 0 1 4 9 16 25 36 49 64 81

List of lists

In [16]:
n, m = 3, 4
example_matrix = [[0 if i != j else 1 for i in range(n)] for j in range(m)]
In [17]:
example_matrix
Out[17]:
[[1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 0, 0]]
In [18]:
lolviz(example_matrix)
Out[18]:
G node139621679287176 0 1 2 3 node139621670526280 0 1 2 1 0 0 node139621679287176:0->node139621670526280:w node139621679304328 0 1 2 0 1 0 node139621679287176:1->node139621679304328:w node139621670630344 0 1 2 0 0 1 node139621679287176:2->node139621670630344:w node139621679286344 0 1 2 0 0 0 node139621679287176:3->node139621679286344:w

List of lists of lists???

In [22]:
n, m, o = 2, 3, 4
example_3D_matrix = [[[
    1 if i < j < k else 0
    for i in range(n)]
    for j in range(m)]
    for k in range(o)]
In [23]:
example_3D_matrix
Out[23]:
[[[0, 0], [0, 0], [0, 0]],
 [[0, 0], [0, 0], [0, 0]],
 [[0, 0], [1, 0], [0, 0]],
 [[0, 0], [1, 0], [1, 1]]]
In [25]:
lolviz(example_3D_matrix)
Out[25]:
G node139621670152520 0 1 2 3 node139621670150344 0 1 2 [0, 0] [0, 0] [0, 0] node139621670152520:0->node139621670150344:w node139621670441480 0 1 2 [0, 0] [0, 0] [0, 0] node139621670152520:1->node139621670441480:w node139621670152456 0 1 2 [0, 0] [1, 0] [0, 0] node139621670152520:2->node139621670152456:w node139621670441032 0 1 2 [0, 0] [1, 0] [1, 1] node139621670152520:3->node139621670441032:w

It works, even if it is not as pretty.

Tree

Only for binary trees, apparently. Let's try with a dictionary that looks like a binary tree:

In [26]:
anakin = {
    "name": "Anakin Skywalker",
    "son": {
        "name": "Luke Skywalker",
    },
    "daughter": {
        "name": "Leia Skywalker",
    },
}
In [27]:
from pprint import pprint
pprint(anakin)
{'daughter': {'name': 'Leia Skywalker'},
 'name': 'Anakin Skywalker',
 'son': {'name': 'Luke Skywalker'}}
In [42]:
treeviz(anakin, leftfield='son', rightfield='daugther')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-42-93eee6442074> in <module>()
----> 1 treeviz(myDict(anakin), leftfield='son', rightfield='daugther')

/usr/local/lib/python3.6/dist-packages/lolviz.py in treeviz(root, leftfield, rightfield)
    102         nodename = "node%d" % id(p)
    103         fields = []
--> 104         for k, v in p.__dict__.items():
    105             if k==leftfield or k==rightfield:
    106                 continue

AttributeError: 'dict' object has no attribute '__dict__'

It doesn't work out of the box for dictionaries, sadly.

Let's check another example:

In [67]:
class Tree:
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right
        
root = Tree('parrt',
            Tree('mary',
                 Tree('jim',
                      Tree('srinivasan'),
                      Tree('april'))),
            Tree('xue',None,Tree('mike')))

treeviz(root)
Out[67]:
G node139621501191336 Tree value 'parrt' left right node139621501191168 Tree value 'mary' left right node139621501191336:c->node139621501191168 node139621501191280 Tree value 'xue' left right node139621501191336:c->node139621501191280 node139621501191112 Tree value 'jim' left right node139621501191168:c->node139621501191112 node139621501191000 Tree value 'srinivasan' left right node139621501191112:c->node139621501191000 node139621501191056 Tree value 'april' left right node139621501191112:c->node139621501191056 node139621501191224 Tree value 'mike' left right node139621501191280:c->node139621501191224

Objects

In [48]:
objviz(anakin)
Out[48]:
G node139621669833160 0 1 2 'name' 'son' 'daughter'
In [49]:
objviz(anakin.values())
Out[49]:
G node139621669714760 0 1 2 node139621670161144 'name' 'Luke Skywalker' node139621669714760:1->node139621670161144:w node139621679147480 'name' 'Leia Skywalker' node139621669714760:2->node139621679147480:w
In [50]:
objviz(anakin.items())
Out[50]:
G node139621669834568 0 1 2 node139621669839688 0 1 'name' 'Anakin Skywalker' node139621669834568:0->node139621669839688:w node139621669769864 0 1 'son'   node139621669834568:1->node139621669769864:w node139621670000264 0 1 'daughter'   node139621669834568:2->node139621670000264:w node139621670161144 'name' 'Luke Skywalker' node139621669769864:c->node139621670161144 node139621679147480 'name' 'Leia Skywalker' node139621670000264:c->node139621679147480

For complex numbers for instance?

In [74]:
z = 1+4j
In [75]:
print(z)
(1+4j)
In [77]:
objviz(z)
Out[77]:
G node139621501117296 CANNOT HANDLE: type=...

OK, this fails.

Calls

In [55]:
def factorial(n):
    if n < 0: return 0
    elif n == 0: return 1
    else: return n * factorial(n - 1)
In [57]:
for n in range(12):
    print(f"{n}! = {factorial(n)}")
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800

And now with some visualization:

In [ ]:
from IPython.display import display
In [72]:
def factorial2(n):
    display(callsviz(varnames=["n"]))
    if n < 0: return 0
    elif n == 0: return 1
    else: return n * factorial2(n - 1)
In [73]:
n = 4
print(f"{n}! = {factorial2(n)}")
G node139621871104440 globals n 4 node139621870916024 factorial2 n 4
G node139621871104440 globals n 4 node139621870916024 factorial2 n 4 node139621870950200 factorial2 n 3
G node139621871104440 globals n 4 node139621870916024 factorial2 n 4 node139621870950200 factorial2 n 3 node139621870776968 factorial2 n 2
G node139621871104440 globals n 4 node139621870916024 factorial2 n 4 node139621870950200 factorial2 n 3 node139621870776968 factorial2 n 2 node139621871111880 factorial2 n 1
G node139621871104440 globals n 4 node139621870916024 factorial2 n 4 node139621870950200 factorial2 n 3 node139621870776968 factorial2 n 2 node139621871111880 factorial2 n 1 node40808488 factorial2 n 0
4! = 24

We really see the "call stack" as the system keeps track of the nested calls. I like that! 👌

String

In [8]:
import string
string.hexdigits
Out[8]:
'0123456789abcdefABCDEF'
In [9]:
strviz(string.hexdigits)
Out[9]:
G node139622250733760 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ' 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F '

Conclusion

That's it. See this other example for more.