memory-graph 0.3.7__tar.gz → 0.3.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. {memory_graph-0.3.7/memory_graph.egg-info → memory_graph-0.3.9}/PKG-INFO +165 -9
  2. {memory_graph-0.3.7 → memory_graph-0.3.9}/README.md +164 -8
  3. memory_graph-0.3.9/TODO.txt +9 -0
  4. memory_graph-0.3.9/images/add_one.png +0 -0
  5. memory_graph-0.3.9/images/add_one.py +18 -0
  6. memory_graph-0.3.9/images/avltree.py +43 -0
  7. memory_graph-0.3.9/images/avltree_base.png +0 -0
  8. memory_graph-0.3.9/images/avltree_dir.png +0 -0
  9. memory_graph-0.3.9/images/avltree_fail.png +0 -0
  10. memory_graph-0.3.9/images/avltree_key_value.png +0 -0
  11. memory_graph-0.3.9/images/avltree_linear.png +0 -0
  12. memory_graph-0.3.9/images/avltree_table.png +0 -0
  13. memory_graph-0.3.9/images/bin_tree.png +0 -0
  14. memory_graph-0.3.9/images/bin_tree.py +47 -0
  15. memory_graph-0.3.9/images/copies.png +0 -0
  16. memory_graph-0.3.9/images/copies.py +15 -0
  17. memory_graph-0.3.9/images/copy_method.png +0 -0
  18. memory_graph-0.3.9/images/copy_method.py +22 -0
  19. memory_graph-0.3.9/images/create_gif.sh +19 -0
  20. memory_graph-0.3.9/images/create_images.sh +34 -0
  21. memory_graph-0.3.9/images/debugging.gif +0 -0
  22. memory_graph-0.3.9/images/debugging.py +19 -0
  23. memory_graph-0.3.9/images/extension_numpy.png +0 -0
  24. memory_graph-0.3.9/images/extension_numpy.py +14 -0
  25. memory_graph-0.3.9/images/extension_pandas.png +0 -0
  26. memory_graph-0.3.9/images/extension_pandas.py +17 -0
  27. memory_graph-0.3.9/images/factorial.gif +0 -0
  28. memory_graph-0.3.9/images/factorial.py +24 -0
  29. memory_graph-0.3.9/images/hash_set.png +0 -0
  30. memory_graph-0.3.9/images/hash_set.py +39 -0
  31. memory_graph-0.3.9/images/highlight.png +0 -0
  32. memory_graph-0.3.9/images/highlight.py +15 -0
  33. memory_graph-0.3.9/images/immutable.py +11 -0
  34. memory_graph-0.3.9/images/immutable1.png +0 -0
  35. memory_graph-0.3.9/images/immutable2.png +0 -0
  36. memory_graph-0.3.9/images/jupyter_example.ipynb +85 -0
  37. memory_graph-0.3.9/images/jupyter_example.png +0 -0
  38. memory_graph-0.3.9/images/linked_list.png +0 -0
  39. memory_graph-0.3.9/images/linked_list.py +39 -0
  40. memory_graph-0.3.9/images/many_types.png +0 -0
  41. memory_graph-0.3.9/images/many_types.py +13 -0
  42. memory_graph-0.3.9/images/mutable.py +11 -0
  43. memory_graph-0.3.9/images/mutable1.png +0 -0
  44. memory_graph-0.3.9/images/mutable2.png +0 -0
  45. memory_graph-0.3.9/images/power_set.gif +0 -0
  46. memory_graph-0.3.9/images/power_set.py +28 -0
  47. memory_graph-0.3.9/images/uva.png +0 -0
  48. memory_graph-0.3.9/install.txt +31 -0
  49. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/__init__.py +84 -22
  50. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/config.py +4 -0
  51. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/config_default.py +4 -0
  52. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/config_helpers.py +4 -0
  53. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/extension_numpy.py +4 -0
  54. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/extension_pandas.py +4 -0
  55. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/html_table.py +4 -0
  56. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/list_view.py +4 -0
  57. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/memory_to_nodes.py +5 -1
  58. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/node_base.py +4 -0
  59. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/node_key_value.py +4 -0
  60. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/node_linear.py +4 -0
  61. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/node_table.py +4 -0
  62. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/sequence.py +5 -1
  63. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/slicer.py +4 -0
  64. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/slices.py +4 -0
  65. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/slices_iterator.py +4 -0
  66. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/slices_table_iterator.py +4 -0
  67. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/test.py +4 -0
  68. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/test_memory_graph.py +4 -0
  69. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/test_memory_to_nodes.py +4 -0
  70. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/test_sequence.py +4 -0
  71. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/test_slicer.py +4 -0
  72. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/test_slices.py +4 -0
  73. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/test_slices_iterator.py +4 -0
  74. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph/utils.py +9 -3
  75. {memory_graph-0.3.7 → memory_graph-0.3.9/memory_graph.egg-info}/PKG-INFO +165 -9
  76. memory_graph-0.3.9/memory_graph.egg-info/SOURCES.txt +82 -0
  77. {memory_graph-0.3.7 → memory_graph-0.3.9}/setup.py +5 -1
  78. memory_graph-0.3.9/uml/memory_graph.uxf +322 -0
  79. memory_graph-0.3.7/memory_graph/t.py +0 -15
  80. memory_graph-0.3.7/memory_graph.egg-info/SOURCES.txt +0 -36
  81. {memory_graph-0.3.7 → memory_graph-0.3.9}/LICENSE.txt +0 -0
  82. {memory_graph-0.3.7 → memory_graph-0.3.9}/MANIFEST.in +0 -0
  83. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph.egg-info/dependency_links.txt +0 -0
  84. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph.egg-info/requires.txt +0 -0
  85. {memory_graph-0.3.7 → memory_graph-0.3.9}/memory_graph.egg-info/top_level.txt +0 -0
  86. {memory_graph-0.3.7 → memory_graph-0.3.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: memory_graph
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: Draws a graph of your data to analyze its structure.
5
5
  Home-page: https://github.com/bterwijn/memory_graph
6
6
  Author: Bas Terwijn
@@ -68,7 +68,7 @@ identical?: True
68
68
  A better way to understand what data is shared is to draw a graph of the data using the [memory_graph](https://pypi.org/project/memory-graph/) package.
69
69
 
70
70
  # Memory Graph #
71
- The [memory_graph](https://pypi.org/project/memory-graph/) package can graph many different data types.
71
+ The [memory_graph](https://pypi.org/project/memory-graph/) package can graph many different data types, not limited to:
72
72
 
73
73
  ```python
74
74
  import memory_graph as mg
@@ -88,8 +88,10 @@ Instead of showing the graph you can also render it to an output file of your ch
88
88
 
89
89
  ```python
90
90
  mg.render(data, "my_graph.pdf")
91
+ mg.render(data, "my_graph.svg")
91
92
  mg.render(data, "my_graph.png")
92
93
  mg.render(data, "my_graph.gv") # Graphviz DOT file
94
+ mg.render(data) # renders to 'mg.render_filename' (default value: 'memory_graph.pdf')
93
95
  ```
94
96
 
95
97
  # Chapters #
@@ -106,6 +108,8 @@ mg.render(data, "my_graph.gv") # Graphviz DOT file
106
108
 
107
109
  [Extensions](#extensions)
108
110
 
111
+ [Introspection](#introspection)
112
+
109
113
  [Jupyter Notebook](#jupyter-notebook)
110
114
 
111
115
  [Troubleshooting](#troubleshooting)
@@ -247,10 +251,12 @@ This is because `b` is of immutable type 'tuple' so its value gets copied automa
247
251
  It is often helpful to temporarily block program execution to inspect the graph. For this, you can use the `mg.block()` function:
248
252
 
249
253
  ```python
250
- mg.block(fun, arg1, arg2, ..., loc=True)
254
+ mg.block(fun, arg1, arg2, ...)
251
255
  ```
252
256
 
253
- This function first executes `fun(arg1, arg2, ...)`, then prints the current source location in the program, and blocks execution until the <Enter> key is pressed. To skip printing the source location, set `loc=False`.
257
+ This function first executes `fun(arg1, arg2, ...)`, then prints the current source location in the program, and blocks execution until the <Enter> key is pressed.
258
+ Set `mg.block_shows_location = False` to skip printing the source location.
259
+ Set `mg.press_enter_message = None` to skip printing "Press <Enter> to continue...".
254
260
 
255
261
  ### Recursion ###
256
262
  The call stack is also helpful to visualize how recursion works. Here we use `mg.block()` to show each step of how recursively ```factorial(3)``` is computed:
@@ -333,12 +339,20 @@ mg.get_call_stack_after_up_to(after_function, up_to_function="<module>")
333
339
 
334
340
  ### Debugging without Debugger Tool ###
335
341
 
336
- To simplify debugging without a debugger tool, we offer these blocking alias functions that you can insert into your code at a specific point to visualize a graph:
342
+ To simplify debugging without a debugger tool, we offer these alias functions that you can insert into your code at the point where you want to visualize a graph:
337
343
 
338
344
  | alias | purpose | function call |
339
345
  |:---|:---|:---|
340
- | `mg.l()` | graph **l**ocal variables | `mg.block(mg.show, locals())` |
341
- | `mg.s()` | graph the call **s**tack | `mg.block(mg.show, mg.get_call_stack())` |
346
+ | `mg.sl()` | **s**how **l**ocal variables | `mg.show(locals())` |
347
+ | `mg.ss()` | **s**how the call **s**tack | `mg.show(mg.get_call_stack())` |
348
+ | `mg.bsl()` | **b**lock after **s**howing **l**ocal variables | `mg.block(mg.show, locals())` |
349
+ | `mg.bss()` | **b**lock after **s**howing the call **s**tack | `mg.block(mg.show, mg.get_call_stack())` |
350
+ | `mg.rl()` | **r**ender **l**ocal variables | `mg.render(locals())` |
351
+ | `mg.rs()` | **r**ender the call **s**tack | `mg.render(mg.get_call_stack())` |
352
+ | `mg.brl()` | **b**lock after **r**endering **l**ocal variables | `mg.block(mg.render, locals())` |
353
+ | `mg.brs()` | **b**lock after **r**endering the call **s**tack | `mg.block(mg.render, mg.get_call_stack())` |
354
+ | `mg.l()` | same as `mg.bsl()` | |
355
+ | `mg.s()` | same as `mg.bss()` | |
342
356
 
343
357
  For example, executing this program:
344
358
 
@@ -350,7 +364,7 @@ squares_collector = []
350
364
  for i in range(1, 6):
351
365
  squares.append(i**2)
352
366
  squares_collector.append(squares.copy())
353
- mg.l() # graph local variables
367
+ mg.l() # block after showing local variables
354
368
  ```
355
369
  and pressing &lt;Enter&gt; a number of times, results in:
356
370
 
@@ -564,9 +578,151 @@ mg.show(locals())
564
578
  ```
565
579
  ![extension_pandas.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/extension_pandas.png)
566
580
 
581
+ ## Introspection ##
582
+ This section is likely to change. Sometimes the introspection fails or is not as desired. For example the `bintrees.avltree.Node` object doesn't show any attributes in the graph below.
583
+
584
+ ```python
585
+ import memory_graph as mg
586
+ import bintrees
587
+
588
+ # Create an AVL tree
589
+ tree = bintrees.AVLTree()
590
+ tree.insert(10, "ten")
591
+ tree.insert(5, "five")
592
+ tree.insert(20, "twenty")
593
+ tree.insert(15, "fifteen")
594
+
595
+ mg.show(locals())
596
+ ```
597
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_fail.png)
598
+
599
+
600
+ ### dir() ###
601
+ A useful start is to give it some color, show the list of all its attributes using `dir()`, and setting an empty Slicer to see the attribute list in full.
602
+
603
+ ```python
604
+ import memory_graph as mg
605
+ import bintrees
606
+
607
+ # Create an AVL tree
608
+ tree = bintrees.AVLTree()
609
+ tree.insert(10, "ten")
610
+ tree.insert(5, "five")
611
+ tree.insert(20, "twenty")
612
+ tree.insert(15, "fifteen")
613
+
614
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
615
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_linear.Node_Linear(data,
616
+ dir(data))
617
+ mg.config.type_to_slicer[bintrees.avltree.Node] = mg.slicer.Slicer()
618
+
619
+ mg.show(locals())
620
+ ```
621
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_dir.png)
622
+
623
+ Next figure out what are the attributes you want to graph and choose a Node type, there are four options.
624
+
625
+ ### 1 Node_Base ###
626
+ Node_base is a leaf node (with no children) and shows just a single value.
627
+ ```python
628
+ import memory_graph as mg
629
+ import bintrees
630
+
631
+ # Create an AVL tree
632
+ tree = bintrees.AVLTree()
633
+ tree.insert(10, "ten")
634
+ tree.insert(5, "five")
635
+ tree.insert(20, "twenty")
636
+ tree.insert(15, "fifteen")
637
+
638
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
639
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_base.Node_Base(f"key:{data.key} value:{data.value}")
640
+
641
+ mg.show(locals())
642
+ ```
643
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_base.png)
644
+
645
+ ### 2 Node_Linear ###
646
+ Node_Linear shows all the values in a line like a list.
647
+ ```python
648
+ import memory_graph as mg
649
+ import bintrees
650
+
651
+ # Create an AVL tree
652
+ tree = bintrees.AVLTree()
653
+ tree.insert(10, "ten")
654
+ tree.insert(5, "five")
655
+ tree.insert(20, "twenty")
656
+ tree.insert(15, "fifteen")
657
+
658
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
659
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_linear.Node_Linear(data,
660
+ ['left:', data.left,
661
+ 'key:', data.key,
662
+ 'value:', data.value,
663
+ 'right:', data.right] )
664
+
665
+ mg.show(locals())
666
+ ```
667
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_linear.png)
668
+
669
+ ### 3 Node_Key_Value ###
670
+ Node_Key_Value shows key-value pairs like a dictionary. Note the required `items()` call at the end.
671
+ ```python
672
+ import memory_graph as mg
673
+ import bintrees
674
+
675
+ # Create an AVL tree
676
+ tree = bintrees.AVLTree()
677
+ tree.insert(10, "ten")
678
+ tree.insert(5, "five")
679
+ tree.insert(20, "twenty")
680
+ tree.insert(15, "fifteen")
681
+
682
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
683
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_key_value.Node_Key_Value(data,
684
+ {'left': data.left,
685
+ 'key': data.key,
686
+ 'value': data.value,
687
+ 'right': data.right}.items() )
688
+
689
+ mg.show(locals())
690
+ ```
691
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_key_value.png)
692
+
693
+ ### 4 Node_Table ###
694
+ Node_Table shows all the values as a table.
695
+ ```python
696
+ import memory_graph as mg
697
+ import bintrees
698
+
699
+ # Create an AVL tree
700
+ tree = bintrees.AVLTree()
701
+ tree.insert(10, "ten")
702
+ tree.insert(5, "five")
703
+ tree.insert(20, "twenty")
704
+ tree.insert(15, "fifteen")
705
+
706
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
707
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_table.Node_Table(data,
708
+ [[data.key, data.value],
709
+ [data.left, data.right]] )
710
+
711
+
712
+ mg.show(locals())
713
+ ```
714
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_table.png)
715
+
716
+
567
717
  ## Jupyter Notebook ##
718
+ In Jupyter Notebook `locals()` has additional variables that cause problems in the graph, use `mg.locals_jupyter()` to get the local variables with these problematic variables filtered out. Use `mg.get_call_stack_jupyter()` to get the whole call stack with these variables filtered out.
568
719
 
569
- In Jupyter Notebook `locals()` has additional variables that cause problems in the graph, use `mg.locals_jupyter()` to get the local variables with these problematic variables filtered out. Use `mg.get_call_stack_jupyter()` to get the whole call stack with these variables filtered out.
720
+ We can use `mg.show()` and `mg.render()` in a Jupyter Notebook, but alternatively we can also use `mg.create_graph()` to create a graph and the `display()` function to render it inline with for example:
721
+
722
+ ```python
723
+ display( mg.create_graph(mg.locals_jupyter()) ) # display the local variables inline
724
+ mg.block(display, mg.create_graph(mg.locals_jupyter()) ) # the same but blocked
725
+ ```
570
726
 
571
727
  See for example [jupyter_example.ipynb](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/jupyter_example.ipynb).
572
728
  ![jupyter_example.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/jupyter_example.png)
@@ -49,7 +49,7 @@ identical?: True
49
49
  A better way to understand what data is shared is to draw a graph of the data using the [memory_graph](https://pypi.org/project/memory-graph/) package.
50
50
 
51
51
  # Memory Graph #
52
- The [memory_graph](https://pypi.org/project/memory-graph/) package can graph many different data types.
52
+ The [memory_graph](https://pypi.org/project/memory-graph/) package can graph many different data types, not limited to:
53
53
 
54
54
  ```python
55
55
  import memory_graph as mg
@@ -69,8 +69,10 @@ Instead of showing the graph you can also render it to an output file of your ch
69
69
 
70
70
  ```python
71
71
  mg.render(data, "my_graph.pdf")
72
+ mg.render(data, "my_graph.svg")
72
73
  mg.render(data, "my_graph.png")
73
74
  mg.render(data, "my_graph.gv") # Graphviz DOT file
75
+ mg.render(data) # renders to 'mg.render_filename' (default value: 'memory_graph.pdf')
74
76
  ```
75
77
 
76
78
  # Chapters #
@@ -87,6 +89,8 @@ mg.render(data, "my_graph.gv") # Graphviz DOT file
87
89
 
88
90
  [Extensions](#extensions)
89
91
 
92
+ [Introspection](#introspection)
93
+
90
94
  [Jupyter Notebook](#jupyter-notebook)
91
95
 
92
96
  [Troubleshooting](#troubleshooting)
@@ -228,10 +232,12 @@ This is because `b` is of immutable type 'tuple' so its value gets copied automa
228
232
  It is often helpful to temporarily block program execution to inspect the graph. For this, you can use the `mg.block()` function:
229
233
 
230
234
  ```python
231
- mg.block(fun, arg1, arg2, ..., loc=True)
235
+ mg.block(fun, arg1, arg2, ...)
232
236
  ```
233
237
 
234
- This function first executes `fun(arg1, arg2, ...)`, then prints the current source location in the program, and blocks execution until the &lt;Enter&gt; key is pressed. To skip printing the source location, set `loc=False`.
238
+ This function first executes `fun(arg1, arg2, ...)`, then prints the current source location in the program, and blocks execution until the &lt;Enter&gt; key is pressed.
239
+ Set `mg.block_shows_location = False` to skip printing the source location.
240
+ Set `mg.press_enter_message = None` to skip printing "Press <Enter> to continue...".
235
241
 
236
242
  ### Recursion ###
237
243
  The call stack is also helpful to visualize how recursion works. Here we use `mg.block()` to show each step of how recursively ```factorial(3)``` is computed:
@@ -314,12 +320,20 @@ mg.get_call_stack_after_up_to(after_function, up_to_function="<module>")
314
320
 
315
321
  ### Debugging without Debugger Tool ###
316
322
 
317
- To simplify debugging without a debugger tool, we offer these blocking alias functions that you can insert into your code at a specific point to visualize a graph:
323
+ To simplify debugging without a debugger tool, we offer these alias functions that you can insert into your code at the point where you want to visualize a graph:
318
324
 
319
325
  | alias | purpose | function call |
320
326
  |:---|:---|:---|
321
- | `mg.l()` | graph **l**ocal variables | `mg.block(mg.show, locals())` |
322
- | `mg.s()` | graph the call **s**tack | `mg.block(mg.show, mg.get_call_stack())` |
327
+ | `mg.sl()` | **s**how **l**ocal variables | `mg.show(locals())` |
328
+ | `mg.ss()` | **s**how the call **s**tack | `mg.show(mg.get_call_stack())` |
329
+ | `mg.bsl()` | **b**lock after **s**howing **l**ocal variables | `mg.block(mg.show, locals())` |
330
+ | `mg.bss()` | **b**lock after **s**howing the call **s**tack | `mg.block(mg.show, mg.get_call_stack())` |
331
+ | `mg.rl()` | **r**ender **l**ocal variables | `mg.render(locals())` |
332
+ | `mg.rs()` | **r**ender the call **s**tack | `mg.render(mg.get_call_stack())` |
333
+ | `mg.brl()` | **b**lock after **r**endering **l**ocal variables | `mg.block(mg.render, locals())` |
334
+ | `mg.brs()` | **b**lock after **r**endering the call **s**tack | `mg.block(mg.render, mg.get_call_stack())` |
335
+ | `mg.l()` | same as `mg.bsl()` | |
336
+ | `mg.s()` | same as `mg.bss()` | |
323
337
 
324
338
  For example, executing this program:
325
339
 
@@ -331,7 +345,7 @@ squares_collector = []
331
345
  for i in range(1, 6):
332
346
  squares.append(i**2)
333
347
  squares_collector.append(squares.copy())
334
- mg.l() # graph local variables
348
+ mg.l() # block after showing local variables
335
349
  ```
336
350
  and pressing &lt;Enter&gt; a number of times, results in:
337
351
 
@@ -545,9 +559,151 @@ mg.show(locals())
545
559
  ```
546
560
  ![extension_pandas.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/extension_pandas.png)
547
561
 
562
+ ## Introspection ##
563
+ This section is likely to change. Sometimes the introspection fails or is not as desired. For example the `bintrees.avltree.Node` object doesn't show any attributes in the graph below.
564
+
565
+ ```python
566
+ import memory_graph as mg
567
+ import bintrees
568
+
569
+ # Create an AVL tree
570
+ tree = bintrees.AVLTree()
571
+ tree.insert(10, "ten")
572
+ tree.insert(5, "five")
573
+ tree.insert(20, "twenty")
574
+ tree.insert(15, "fifteen")
575
+
576
+ mg.show(locals())
577
+ ```
578
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_fail.png)
579
+
580
+
581
+ ### dir() ###
582
+ A useful start is to give it some color, show the list of all its attributes using `dir()`, and setting an empty Slicer to see the attribute list in full.
583
+
584
+ ```python
585
+ import memory_graph as mg
586
+ import bintrees
587
+
588
+ # Create an AVL tree
589
+ tree = bintrees.AVLTree()
590
+ tree.insert(10, "ten")
591
+ tree.insert(5, "five")
592
+ tree.insert(20, "twenty")
593
+ tree.insert(15, "fifteen")
594
+
595
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
596
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_linear.Node_Linear(data,
597
+ dir(data))
598
+ mg.config.type_to_slicer[bintrees.avltree.Node] = mg.slicer.Slicer()
599
+
600
+ mg.show(locals())
601
+ ```
602
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_dir.png)
603
+
604
+ Next figure out what are the attributes you want to graph and choose a Node type, there are four options.
605
+
606
+ ### 1 Node_Base ###
607
+ Node_base is a leaf node (with no children) and shows just a single value.
608
+ ```python
609
+ import memory_graph as mg
610
+ import bintrees
611
+
612
+ # Create an AVL tree
613
+ tree = bintrees.AVLTree()
614
+ tree.insert(10, "ten")
615
+ tree.insert(5, "five")
616
+ tree.insert(20, "twenty")
617
+ tree.insert(15, "fifteen")
618
+
619
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
620
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_base.Node_Base(f"key:{data.key} value:{data.value}")
621
+
622
+ mg.show(locals())
623
+ ```
624
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_base.png)
625
+
626
+ ### 2 Node_Linear ###
627
+ Node_Linear shows all the values in a line like a list.
628
+ ```python
629
+ import memory_graph as mg
630
+ import bintrees
631
+
632
+ # Create an AVL tree
633
+ tree = bintrees.AVLTree()
634
+ tree.insert(10, "ten")
635
+ tree.insert(5, "five")
636
+ tree.insert(20, "twenty")
637
+ tree.insert(15, "fifteen")
638
+
639
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
640
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_linear.Node_Linear(data,
641
+ ['left:', data.left,
642
+ 'key:', data.key,
643
+ 'value:', data.value,
644
+ 'right:', data.right] )
645
+
646
+ mg.show(locals())
647
+ ```
648
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_linear.png)
649
+
650
+ ### 3 Node_Key_Value ###
651
+ Node_Key_Value shows key-value pairs like a dictionary. Note the required `items()` call at the end.
652
+ ```python
653
+ import memory_graph as mg
654
+ import bintrees
655
+
656
+ # Create an AVL tree
657
+ tree = bintrees.AVLTree()
658
+ tree.insert(10, "ten")
659
+ tree.insert(5, "five")
660
+ tree.insert(20, "twenty")
661
+ tree.insert(15, "fifteen")
662
+
663
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
664
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_key_value.Node_Key_Value(data,
665
+ {'left': data.left,
666
+ 'key': data.key,
667
+ 'value': data.value,
668
+ 'right': data.right}.items() )
669
+
670
+ mg.show(locals())
671
+ ```
672
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_key_value.png)
673
+
674
+ ### 4 Node_Table ###
675
+ Node_Table shows all the values as a table.
676
+ ```python
677
+ import memory_graph as mg
678
+ import bintrees
679
+
680
+ # Create an AVL tree
681
+ tree = bintrees.AVLTree()
682
+ tree.insert(10, "ten")
683
+ tree.insert(5, "five")
684
+ tree.insert(20, "twenty")
685
+ tree.insert(15, "fifteen")
686
+
687
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
688
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_table.Node_Table(data,
689
+ [[data.key, data.value],
690
+ [data.left, data.right]] )
691
+
692
+
693
+ mg.show(locals())
694
+ ```
695
+ ![extension_numpy.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/avltree_table.png)
696
+
697
+
548
698
  ## Jupyter Notebook ##
699
+ In Jupyter Notebook `locals()` has additional variables that cause problems in the graph, use `mg.locals_jupyter()` to get the local variables with these problematic variables filtered out. Use `mg.get_call_stack_jupyter()` to get the whole call stack with these variables filtered out.
549
700
 
550
- In Jupyter Notebook `locals()` has additional variables that cause problems in the graph, use `mg.locals_jupyter()` to get the local variables with these problematic variables filtered out. Use `mg.get_call_stack_jupyter()` to get the whole call stack with these variables filtered out.
701
+ We can use `mg.show()` and `mg.render()` in a Jupyter Notebook, but alternatively we can also use `mg.create_graph()` to create a graph and the `display()` function to render it inline with for example:
702
+
703
+ ```python
704
+ display( mg.create_graph(mg.locals_jupyter()) ) # display the local variables inline
705
+ mg.block(display, mg.create_graph(mg.locals_jupyter()) ) # the same but blocked
706
+ ```
551
707
 
552
708
  See for example [jupyter_example.ipynb](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/jupyter_example.ipynb).
553
709
  ![jupyter_example.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/jupyter_example.png)
@@ -0,0 +1,9 @@
1
+
2
+ mg.block(fun, print_loc=True), update docs, stack-overflow posts
3
+
4
+ Jupyter Notebook inline render using display()
5
+
6
+ webassembly inline render
7
+
8
+ optional max introspect depth for each type/id
9
+ https://discuss.python.org/t/request-for-feedback-memory-graph-a-python-visualization-tool-for-education/78347
Binary file
@@ -0,0 +1,18 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ import memory_graph as mg
6
+
7
+ def add_one(a, b, c):
8
+ a += [1]
9
+ b += (1,)
10
+ c += [1]
11
+ mg.render( mg.get_call_stack(), "add_one.png")
12
+
13
+ a = [4, 3, 2]
14
+ b = (4, 3, 2)
15
+ c = [4, 3, 2]
16
+
17
+ add_one(a, b, c.copy())
18
+ print(f"a:{a} b:{b} c:{c}")
@@ -0,0 +1,43 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ import memory_graph as mg
6
+ import bintrees
7
+
8
+ # Create an AVL tree
9
+ tree = bintrees.AVLTree()
10
+ tree.insert(10, "ten")
11
+ tree.insert(5, "five")
12
+ tree.insert(20, "twenty")
13
+ tree.insert(15, "fifteen")
14
+
15
+ # mg.render(locals(), 'avltree_fail.png') # id keeps changing
16
+
17
+ mg.config.type_to_color[bintrees.avltree.Node] = "sandybrown"
18
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_linear.Node_Linear(data, dir(data))
19
+ mg.config.type_to_slicer[bintrees.avltree.Node] = mg.slicer.Slicer()
20
+ mg.render(locals(), 'avltree_dir.png')
21
+
22
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_base.Node_Base(f"key:{data.key} value:{data.value}")
23
+ mg.render(locals(), 'avltree_base.png')
24
+
25
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_linear.Node_Linear(data,
26
+ ['left:', data.left,
27
+ 'key:', data.key,
28
+ 'value:', data.value,
29
+ 'right:', data.right])
30
+ mg.render(locals(), 'avltree_linear.png')
31
+
32
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_key_value.Node_Key_Value(data,
33
+ {'left': data.left,
34
+ 'key': data.key,
35
+ 'value': data.value,
36
+ 'right': data.right}.items())
37
+ mg.render(locals(), 'avltree_key_value.png')
38
+
39
+ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.node_table.Node_Table(data,
40
+ [[data.key, data.value],
41
+ [data.left, data.right]]
42
+ )
43
+ mg.render(locals(), 'avltree_table.png')
Binary file
@@ -0,0 +1,47 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ import memory_graph as mg
6
+ import random
7
+ random.seed(0) # use same random numbers each run
8
+
9
+ class Node:
10
+
11
+ def __init__(self, value):
12
+ self.smaller = None
13
+ self.value = value
14
+ self.larger = None
15
+
16
+ class BinTree:
17
+
18
+ def __init__(self):
19
+ self.root = None
20
+
21
+ def add_recursive(self, new_value, node):
22
+ if new_value < node.value:
23
+ if node.smaller is None:
24
+ node.smaller = Node(new_value)
25
+ else:
26
+ self.add_recursive(new_value, node.smaller)
27
+ else:
28
+ if node.larger is None:
29
+ node.larger = Node(new_value)
30
+ else:
31
+ self.add_recursive(new_value, node.larger)
32
+ if new_value == 51:
33
+ mg.render(locals(), f"bin_tree.png")
34
+ exit(0)
35
+
36
+ def add(self, value):
37
+ if self.root is None:
38
+ self.root = Node(value)
39
+ else:
40
+ self.add_recursive(value, self.root)
41
+
42
+ tree = BinTree()
43
+ n = 100
44
+ for i in range(n):
45
+ new_value = random.randrange(n)
46
+ tree.add(new_value)
47
+
Binary file
@@ -0,0 +1,15 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ import memory_graph as mg
6
+ import copy
7
+
8
+ a = [ [1, 2], ['x', 'y'] ] # a nested list (a list containing lists)
9
+
10
+ # three different ways to make a "copy" of 'a':
11
+ c1 = a
12
+ c2 = copy.copy(a) # equivalent to: a.copy() a[:] list(a)
13
+ c3 = copy.deepcopy(a)
14
+
15
+ mg.render(locals(), 'copies.png')
@@ -0,0 +1,22 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ import memory_graph as mg
6
+ import copy
7
+
8
+ class My_Class:
9
+
10
+ def __init__(self):
11
+ self.digits = [1, 2]
12
+ self.letters = ['x', 'y']
13
+
14
+ def copy(self): # custom copy method copies the digits but shares the letters
15
+ c = copy.copy(self)
16
+ c.digits = copy.copy(self.digits)
17
+ return c
18
+
19
+ a = My_Class()
20
+ b = a.copy()
21
+
22
+ mg.render(locals(), 'copy_method.png')
@@ -0,0 +1,19 @@
1
+ #!/bin/bash
2
+ #
3
+ # install:
4
+ #
5
+ # sudo apt install imagemagick
6
+
7
+ name="$1"
8
+ files=$(ls -v $name*.png)
9
+ echo "creating gif with:"
10
+ echo "$files"
11
+
12
+ largest_size=$(identify -format "%Wx%H %f\n" $name*.png | sort -nr | head -n1)
13
+ echo "largest_size: $largest_size"
14
+
15
+ echo "resizing images"
16
+ mogrify -resize $largest_size -background white -gravity center -extent $largest_size $files
17
+ echo "creating file: $name.gif"
18
+ convert -delay 150 -loop 0 $files $name.gif
19
+ echo "done"