memory-graph 0.3.78__tar.gz → 0.3.79__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.
- {memory_graph-0.3.78 → memory_graph-0.3.79}/PKG-INFO +78 -19
- {memory_graph-0.3.78 → memory_graph-0.3.79}/README.md +77 -18
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/__init__.py +2 -1
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/config.py +5 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/config_default.py +92 -29
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/html_table.py +6 -6
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/memory_to_nodes.py +5 -5
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph.egg-info/PKG-INFO +78 -19
- {memory_graph-0.3.78 → memory_graph-0.3.79}/pyproject.toml +1 -1
- {memory_graph-0.3.78 → memory_graph-0.3.79}/LICENSE.txt +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/call_stack.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/config_helpers.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/extension_numpy.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/extension_pandas.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/extension_torch.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/list_view.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/node_base.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/node_key_value.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/node_leaf.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/node_linear.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/node_table.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/sequence.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/slicer.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/slices.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/slices_iterator.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/slices_table_iterator.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/test.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/test_max_graph_depth.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/test_memory_graph.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/test_memory_to_nodes.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/test_sequence.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/test_slicer.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/test_slices.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/test_slices_iterator.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph/utils.py +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph.egg-info/SOURCES.txt +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph.egg-info/dependency_links.txt +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph.egg-info/requires.txt +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/memory_graph.egg-info/top_level.txt +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/setup.cfg +0 -0
- {memory_graph-0.3.78 → memory_graph-0.3.79}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memory_graph
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.79
|
|
4
4
|
Summary: Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy.
|
|
5
5
|
Author-email: Bas Terwijn <bterwijn@gmail.com>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -27,7 +27,7 @@ Additionally [Graphviz](https://graphviz.org/download/) needs to be installed.
|
|
|
27
27
|
|
|
28
28
|
# Highlights #
|
|
29
29
|

|
|
30
|
-
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1&
|
|
30
|
+
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1&play) 👈 now, no installation required!
|
|
31
31
|
|
|
32
32
|
- learn the right **mental model** to think about Python data (references, mutability, shallow vs deep copy)
|
|
33
33
|
- **visualize the structure of your data** to more easily understand and debug any data structure
|
|
@@ -35,7 +35,7 @@ Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph
|
|
|
35
35
|
|
|
36
36
|
An example Binary Tree data structure:
|
|
37
37
|

|
|
38
|
-
Or see it in the [Memory
|
|
38
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play).
|
|
39
39
|
|
|
40
40
|
# Videos #
|
|
41
41
|
| [](https://www.youtube.com/watch?v=23_bHcr7hqo) | [](https://www.youtube.com/watch?v=pvIJgHCaXhU) |
|
|
@@ -163,7 +163,7 @@ Bas Terwijn
|
|
|
163
163
|
## Inspiration ##
|
|
164
164
|
Inspired by [Python Tutor](https://pythontutor.com/).
|
|
165
165
|
|
|
166
|
-
The main differences are that by running memory_graph locally we support Python Tutor’s [unsupported features](https://github.com/pythontutor-dev/pythontutor/blob/master/unsupported-features.md#unsupported-features) so that it scales to full programs in many environments and IDEs instead of just code snippets in a webbrowser, and by mirroring the data’s hierarchy we improve graph readability for larger graphs.
|
|
166
|
+
The main differences are that by running memory_graph locally we support Python Tutor’s [unsupported features](https://github.com/pythontutor-dev/pythontutor/blob/master/unsupported-features.md#unsupported-features) so that it scales to full multi-file programs in many environments and IDEs instead of just code snippets in a webbrowser, and by mirroring the data’s hierarchy we improve graph readability for larger graphs.
|
|
167
167
|
|
|
168
168
|
## Social Media #
|
|
169
169
|
* [LinkedIn](https://www.linkedin.com/groups/13244150/)
|
|
@@ -242,7 +242,7 @@ mg.show(locals())
|
|
|
242
242
|
|
|
243
243
|

|
|
244
244
|
|
|
245
|
-
Or see it in the [Memory
|
|
245
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/copies.py&play).
|
|
246
246
|
|
|
247
247
|
## Custom Copy ##
|
|
248
248
|
We can write our own custom copy function or method in case the three standard "copy" options don't do what we want. For example, in the code below the `custom_copy()` method of My_Class copies the `digits` but shares the `letters` between two objects.
|
|
@@ -270,7 +270,7 @@ mg.show(locals())
|
|
|
270
270
|
```
|
|
271
271
|

|
|
272
272
|
|
|
273
|
-
Or see it in the [Memory
|
|
273
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/custom_copy.py&breakpoints=15&continues=1&play).
|
|
274
274
|
|
|
275
275
|
## Name Rebinding ##
|
|
276
276
|
When `a` and `b` share a mutable value, then changing the value of `b` changes the value of `a` and vice versa. However, reassigning `b` does not change `a`. When you reassign `b`, you only **rebind** the name `b` to another value without affecting any other variable.
|
|
@@ -300,7 +300,7 @@ mg.render(locals(), 'rebinding3.png')
|
|
|
300
300
|
|:--------------:|:--------------:|:--------------:|
|
|
301
301
|
| rebinding1.png | rebinding2.png | rebinding3.png |
|
|
302
302
|
|
|
303
|
-
Or see it in the [Memory
|
|
303
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/rebind.py&play).
|
|
304
304
|
|
|
305
305
|
## Copying Values of Immutable Type ##
|
|
306
306
|
Because a value of immutable type will be copied automatically when it is changed, there is no need to copy it beforehand. Therefore, a shallow or deep copy of a value of immutable type will result in just an assignment to save on the time needed to make the copy and the space (=memory) needed to store the values.
|
|
@@ -358,7 +358,7 @@ print(f"a:{a} b:{b} c:{c}")
|
|
|
358
358
|
```
|
|
359
359
|

|
|
360
360
|
|
|
361
|
-
Or see it in the [Memory
|
|
361
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/function_call.py&play).
|
|
362
362
|
|
|
363
363
|
In the printed output we see that only `a` is changed as a result of the function call:
|
|
364
364
|
```
|
|
@@ -387,7 +387,7 @@ print(f"a:{a} b:{b[0]}")
|
|
|
387
387
|
```
|
|
388
388
|
a:10 b:11
|
|
389
389
|
```
|
|
390
|
-
Or see it in the [Memory
|
|
390
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/wrap.py&breakpoints=5&continues=1&play)
|
|
391
391
|
|
|
392
392
|
The effect of calling `add_one()` is that `b[0]` increases by 1, while `a` is unaffected.
|
|
393
393
|
|
|
@@ -428,7 +428,7 @@ print( factorial(4) )
|
|
|
428
428
|
|
|
429
429
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
430
430
|
|
|
431
|
-
Or see it in the [Memory
|
|
431
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/factorial.py×tep=1.0&play).
|
|
432
432
|
|
|
433
433
|
## Binary Conversion ##
|
|
434
434
|
A more interesting recursive example is function `binary()` that converts a integer from decimal to binary representation.
|
|
@@ -452,7 +452,7 @@ print( binary(100) )
|
|
|
452
452
|
[1, 1, 0, 0, 1, 0, 0]
|
|
453
453
|
```
|
|
454
454
|
|
|
455
|
-
Or see it in the [Memory
|
|
455
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/binary_convert.py×tep=1.0&play).
|
|
456
456
|
|
|
457
457
|
## Power Set ##
|
|
458
458
|
A more complex recursive example is function `power_set()` where lists are shared by different function calls. A power set is the set of all subsets of a collection of values.
|
|
@@ -484,7 +484,7 @@ print( power_set(['a', 'b', 'c']) )
|
|
|
484
484
|
[['a', 'b', 'c'], ['a', 'b'], ['a', 'c'], ['a'], ['b', 'c'], ['b'], ['c'], []]
|
|
485
485
|
```
|
|
486
486
|
|
|
487
|
-
Or see it in the [Memory
|
|
487
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/power_set.py×tep=1.0&play).
|
|
488
488
|
|
|
489
489
|
## Invocation Tree ##
|
|
490
490
|
The memory_graph package visualizes data at the currect time, but to better understand recursion it can also be helpful to visualize different function calls over time. This is what the [invocation_tree](https://github.com/bterwijn/invocation_tree?tab=readme-ov-file#installation) package does.
|
|
@@ -648,7 +648,7 @@ for i in range(n):
|
|
|
648
648
|
Here we show values being added to a Linked List in Cursor AI. When adding the last value '5' we "Step Into" the code to show more of the details.
|
|
649
649
|

|
|
650
650
|
|
|
651
|
-
Or see it in the [Memory
|
|
651
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/linked_list.py×tep=0.2&play).
|
|
652
652
|
|
|
653
653
|
## Binary Tree ##
|
|
654
654
|
```python
|
|
@@ -690,7 +690,7 @@ for i in range(n):
|
|
|
690
690
|
Here we show values being inserted in a Binary Tree in Visual Studio Code. When inserting the last value '29' we "Step Into" the code to show the recursive implementation.
|
|
691
691
|

|
|
692
692
|
|
|
693
|
-
See it in the [Memory
|
|
693
|
+
See it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play) or see the more advanced [Multiway Tree](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/multiway_tree.py&breakpoints=19,33&continues=1×tep=0.2&play) with more than two children per node, making the tree less deep and more efficient.
|
|
694
694
|
|
|
695
695
|
## Hash Set ##
|
|
696
696
|
```python
|
|
@@ -734,7 +734,7 @@ for i in range(n):
|
|
|
734
734
|
Here we show values being inserted in a HashSet in PyCharm. When inserting the last value '44' we "Step Into" the code to show more of the details.
|
|
735
735
|

|
|
736
736
|
|
|
737
|
-
Or see it in the [Memory
|
|
737
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py&breakpoints=32&continues=1×tep=0.5&play).
|
|
738
738
|
|
|
739
739
|
|
|
740
740
|
# Sorting Algorithms #
|
|
@@ -761,7 +761,7 @@ In this configuration example we show the decimal, binary and [two's complement
|
|
|
761
761
|
|
|
762
762
|
A sliding puzzle solver as a challenging example showing how memory_graph deals with large amounts of data. Click "Continue" to step through the breadth-first search generations until a solution path is found:
|
|
763
763
|
|
|
764
|
-
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=16,26,28,39&continues=1)
|
|
764
|
+
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=16,26,28,39,136&continues=1)
|
|
765
765
|
|
|
766
766
|

|
|
767
767
|
|
|
@@ -1255,7 +1255,66 @@ mg.config.type_to_node[List_View] = (lambda l: mg.Node_Linear(l,
|
|
|
1255
1255
|
```
|
|
1256
1256
|

|
|
1257
1257
|
|
|
1258
|
-
Or see it in the [Memory
|
|
1258
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_search.py&breakpoints=38&continues=1×tep=0.5&play)
|
|
1259
|
+
|
|
1260
|
+
## String Types ##
|
|
1261
|
+
|
|
1262
|
+
For special string formatting different `str` types are available:
|
|
1263
|
+
|
|
1264
|
+
| string type | format |
|
|
1265
|
+
|:--------------------------:|:--------------------:|
|
|
1266
|
+
| `str` | normal Python `str` type is limited by `config.max_string_length` |
|
|
1267
|
+
| `mg.full_str('text')` | not limited |
|
|
1268
|
+
| `mg.unquoted_str('text')` | not limited and not quoted |
|
|
1269
|
+
| `mg.html_str('text')` | for [Grahviz html-like formatting](https://graphviz.org/doc/info/shapes.html#html) |
|
|
1270
|
+
|
|
1271
|
+
The [Grahviz html-like formatting](https://graphviz.org/doc/info/shapes.html#html) supports a subset of html tags that allow for things like:
|
|
1272
|
+
```python
|
|
1273
|
+
import memory_graph as mg
|
|
1274
|
+
|
|
1275
|
+
elements = ['<B>bold</B>',
|
|
1276
|
+
'<I>italic</I>',
|
|
1277
|
+
'<S>strikethrough</S>',
|
|
1278
|
+
'<U>under</U><O>over</O>',
|
|
1279
|
+
'<SUB>sub</SUB><SUP>sup</SUP>',
|
|
1280
|
+
'<FONT FACE="Courier">monospaced</FONT>',
|
|
1281
|
+
'<FONT COLOR="red">red</FONT><FONT COLOR="green">green</FONT>',
|
|
1282
|
+
'<FONT POINT-SIZE="20">Large</FONT><FONT POINT-SIZE="10">small</FONT>',
|
|
1283
|
+
'<TABLE BORDER="1"><TR><TD>c1</TD><TD>c2</TD></TR></TABLE>',
|
|
1284
|
+
'line1<BR/>line2<BR/>line3<BR/>']
|
|
1285
|
+
|
|
1286
|
+
normal_str = '<TABLE BORDER="0">\n'
|
|
1287
|
+
for element in elements:
|
|
1288
|
+
normal_str += '<TR><TD> ' + mg.utils.html_escape(element) + ' </TD><TD> ' + element+ ' </TD></TR>element\n'
|
|
1289
|
+
normal_str += '</TABLE>\n'
|
|
1290
|
+
|
|
1291
|
+
html_example = mg.html_str(normal_str)
|
|
1292
|
+
del elements, element, normal_str
|
|
1293
|
+
mg.show(locals())
|
|
1294
|
+
```
|
|
1295
|
+

|
|
1296
|
+
|
|
1297
|
+
Including the `<IMG>` tag that allows for showing local image files only, but that currently doesn't work in the Memory Graph Web Debugger, that uses 'Viz.js' for graph rendering, unfortunately.
|
|
1298
|
+
|
|
1299
|
+
```python
|
|
1300
|
+
import memory_graph as mg
|
|
1301
|
+
import matplotlib.pyplot as plt
|
|
1302
|
+
import random
|
|
1303
|
+
random.seed(0)
|
|
1304
|
+
|
|
1305
|
+
N = 100
|
|
1306
|
+
value = 0
|
|
1307
|
+
data = [value]
|
|
1308
|
+
for i in range(N):
|
|
1309
|
+
value += random.uniform(-1, 1)
|
|
1310
|
+
data.append(value)
|
|
1311
|
+
|
|
1312
|
+
plt.plot(data)
|
|
1313
|
+
plt.savefig('plot.png')
|
|
1314
|
+
image = {mg.html_str('<IMG SRC="plot.png"/>')}
|
|
1315
|
+
mg.show(locals())
|
|
1316
|
+
```
|
|
1317
|
+

|
|
1259
1318
|
|
|
1260
1319
|
## Collapse Type ##
|
|
1261
1320
|
|
|
@@ -1388,7 +1447,7 @@ mg.show(locals())
|
|
|
1388
1447
|
```
|
|
1389
1448
|

|
|
1390
1449
|
|
|
1391
|
-
Or see it in the [Memory
|
|
1450
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#micropip=numpy&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_numpy.py&play).
|
|
1392
1451
|
|
|
1393
1452
|
## Pandas ##
|
|
1394
1453
|
For pandas types `Series` and `DataFrame`, use `mg.extend_pandas()`:
|
|
@@ -1409,7 +1468,7 @@ mg.show(locals())
|
|
|
1409
1468
|
```
|
|
1410
1469
|

|
|
1411
1470
|
|
|
1412
|
-
Or see it in the [Memory
|
|
1471
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#micropip=pandas&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_pandas.py&play).
|
|
1413
1472
|
|
|
1414
1473
|
## PyTorch ##
|
|
1415
1474
|
For torch type `tensor`, use `mg.extend_torch()`:
|
|
@@ -7,7 +7,7 @@ Additionally [Graphviz](https://graphviz.org/download/) needs to be installed.
|
|
|
7
7
|
|
|
8
8
|
# Highlights #
|
|
9
9
|

|
|
10
|
-
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1&
|
|
10
|
+
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1&play) 👈 now, no installation required!
|
|
11
11
|
|
|
12
12
|
- learn the right **mental model** to think about Python data (references, mutability, shallow vs deep copy)
|
|
13
13
|
- **visualize the structure of your data** to more easily understand and debug any data structure
|
|
@@ -15,7 +15,7 @@ Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph
|
|
|
15
15
|
|
|
16
16
|
An example Binary Tree data structure:
|
|
17
17
|

|
|
18
|
-
Or see it in the [Memory
|
|
18
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play).
|
|
19
19
|
|
|
20
20
|
# Videos #
|
|
21
21
|
| [](https://www.youtube.com/watch?v=23_bHcr7hqo) | [](https://www.youtube.com/watch?v=pvIJgHCaXhU) |
|
|
@@ -143,7 +143,7 @@ Bas Terwijn
|
|
|
143
143
|
## Inspiration ##
|
|
144
144
|
Inspired by [Python Tutor](https://pythontutor.com/).
|
|
145
145
|
|
|
146
|
-
The main differences are that by running memory_graph locally we support Python Tutor’s [unsupported features](https://github.com/pythontutor-dev/pythontutor/blob/master/unsupported-features.md#unsupported-features) so that it scales to full programs in many environments and IDEs instead of just code snippets in a webbrowser, and by mirroring the data’s hierarchy we improve graph readability for larger graphs.
|
|
146
|
+
The main differences are that by running memory_graph locally we support Python Tutor’s [unsupported features](https://github.com/pythontutor-dev/pythontutor/blob/master/unsupported-features.md#unsupported-features) so that it scales to full multi-file programs in many environments and IDEs instead of just code snippets in a webbrowser, and by mirroring the data’s hierarchy we improve graph readability for larger graphs.
|
|
147
147
|
|
|
148
148
|
## Social Media #
|
|
149
149
|
* [LinkedIn](https://www.linkedin.com/groups/13244150/)
|
|
@@ -222,7 +222,7 @@ mg.show(locals())
|
|
|
222
222
|
|
|
223
223
|

|
|
224
224
|
|
|
225
|
-
Or see it in the [Memory
|
|
225
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/copies.py&play).
|
|
226
226
|
|
|
227
227
|
## Custom Copy ##
|
|
228
228
|
We can write our own custom copy function or method in case the three standard "copy" options don't do what we want. For example, in the code below the `custom_copy()` method of My_Class copies the `digits` but shares the `letters` between two objects.
|
|
@@ -250,7 +250,7 @@ mg.show(locals())
|
|
|
250
250
|
```
|
|
251
251
|

|
|
252
252
|
|
|
253
|
-
Or see it in the [Memory
|
|
253
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/custom_copy.py&breakpoints=15&continues=1&play).
|
|
254
254
|
|
|
255
255
|
## Name Rebinding ##
|
|
256
256
|
When `a` and `b` share a mutable value, then changing the value of `b` changes the value of `a` and vice versa. However, reassigning `b` does not change `a`. When you reassign `b`, you only **rebind** the name `b` to another value without affecting any other variable.
|
|
@@ -280,7 +280,7 @@ mg.render(locals(), 'rebinding3.png')
|
|
|
280
280
|
|:--------------:|:--------------:|:--------------:|
|
|
281
281
|
| rebinding1.png | rebinding2.png | rebinding3.png |
|
|
282
282
|
|
|
283
|
-
Or see it in the [Memory
|
|
283
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/rebind.py&play).
|
|
284
284
|
|
|
285
285
|
## Copying Values of Immutable Type ##
|
|
286
286
|
Because a value of immutable type will be copied automatically when it is changed, there is no need to copy it beforehand. Therefore, a shallow or deep copy of a value of immutable type will result in just an assignment to save on the time needed to make the copy and the space (=memory) needed to store the values.
|
|
@@ -338,7 +338,7 @@ print(f"a:{a} b:{b} c:{c}")
|
|
|
338
338
|
```
|
|
339
339
|

|
|
340
340
|
|
|
341
|
-
Or see it in the [Memory
|
|
341
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/function_call.py&play).
|
|
342
342
|
|
|
343
343
|
In the printed output we see that only `a` is changed as a result of the function call:
|
|
344
344
|
```
|
|
@@ -367,7 +367,7 @@ print(f"a:{a} b:{b[0]}")
|
|
|
367
367
|
```
|
|
368
368
|
a:10 b:11
|
|
369
369
|
```
|
|
370
|
-
Or see it in the [Memory
|
|
370
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/wrap.py&breakpoints=5&continues=1&play)
|
|
371
371
|
|
|
372
372
|
The effect of calling `add_one()` is that `b[0]` increases by 1, while `a` is unaffected.
|
|
373
373
|
|
|
@@ -408,7 +408,7 @@ print( factorial(4) )
|
|
|
408
408
|
|
|
409
409
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
410
410
|
|
|
411
|
-
Or see it in the [Memory
|
|
411
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/factorial.py×tep=1.0&play).
|
|
412
412
|
|
|
413
413
|
## Binary Conversion ##
|
|
414
414
|
A more interesting recursive example is function `binary()` that converts a integer from decimal to binary representation.
|
|
@@ -432,7 +432,7 @@ print( binary(100) )
|
|
|
432
432
|
[1, 1, 0, 0, 1, 0, 0]
|
|
433
433
|
```
|
|
434
434
|
|
|
435
|
-
Or see it in the [Memory
|
|
435
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/binary_convert.py×tep=1.0&play).
|
|
436
436
|
|
|
437
437
|
## Power Set ##
|
|
438
438
|
A more complex recursive example is function `power_set()` where lists are shared by different function calls. A power set is the set of all subsets of a collection of values.
|
|
@@ -464,7 +464,7 @@ print( power_set(['a', 'b', 'c']) )
|
|
|
464
464
|
[['a', 'b', 'c'], ['a', 'b'], ['a', 'c'], ['a'], ['b', 'c'], ['b'], ['c'], []]
|
|
465
465
|
```
|
|
466
466
|
|
|
467
|
-
Or see it in the [Memory
|
|
467
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/power_set.py×tep=1.0&play).
|
|
468
468
|
|
|
469
469
|
## Invocation Tree ##
|
|
470
470
|
The memory_graph package visualizes data at the currect time, but to better understand recursion it can also be helpful to visualize different function calls over time. This is what the [invocation_tree](https://github.com/bterwijn/invocation_tree?tab=readme-ov-file#installation) package does.
|
|
@@ -628,7 +628,7 @@ for i in range(n):
|
|
|
628
628
|
Here we show values being added to a Linked List in Cursor AI. When adding the last value '5' we "Step Into" the code to show more of the details.
|
|
629
629
|

|
|
630
630
|
|
|
631
|
-
Or see it in the [Memory
|
|
631
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/linked_list.py×tep=0.2&play).
|
|
632
632
|
|
|
633
633
|
## Binary Tree ##
|
|
634
634
|
```python
|
|
@@ -670,7 +670,7 @@ for i in range(n):
|
|
|
670
670
|
Here we show values being inserted in a Binary Tree in Visual Studio Code. When inserting the last value '29' we "Step Into" the code to show the recursive implementation.
|
|
671
671
|

|
|
672
672
|
|
|
673
|
-
See it in the [Memory
|
|
673
|
+
See it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play) or see the more advanced [Multiway Tree](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/multiway_tree.py&breakpoints=19,33&continues=1×tep=0.2&play) with more than two children per node, making the tree less deep and more efficient.
|
|
674
674
|
|
|
675
675
|
## Hash Set ##
|
|
676
676
|
```python
|
|
@@ -714,7 +714,7 @@ for i in range(n):
|
|
|
714
714
|
Here we show values being inserted in a HashSet in PyCharm. When inserting the last value '44' we "Step Into" the code to show more of the details.
|
|
715
715
|

|
|
716
716
|
|
|
717
|
-
Or see it in the [Memory
|
|
717
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py&breakpoints=32&continues=1×tep=0.5&play).
|
|
718
718
|
|
|
719
719
|
|
|
720
720
|
# Sorting Algorithms #
|
|
@@ -741,7 +741,7 @@ In this configuration example we show the decimal, binary and [two's complement
|
|
|
741
741
|
|
|
742
742
|
A sliding puzzle solver as a challenging example showing how memory_graph deals with large amounts of data. Click "Continue" to step through the breadth-first search generations until a solution path is found:
|
|
743
743
|
|
|
744
|
-
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=16,26,28,39&continues=1)
|
|
744
|
+
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=16,26,28,39,136&continues=1)
|
|
745
745
|
|
|
746
746
|

|
|
747
747
|
|
|
@@ -1235,7 +1235,66 @@ mg.config.type_to_node[List_View] = (lambda l: mg.Node_Linear(l,
|
|
|
1235
1235
|
```
|
|
1236
1236
|

|
|
1237
1237
|
|
|
1238
|
-
Or see it in the [Memory
|
|
1238
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_search.py&breakpoints=38&continues=1×tep=0.5&play)
|
|
1239
|
+
|
|
1240
|
+
## String Types ##
|
|
1241
|
+
|
|
1242
|
+
For special string formatting different `str` types are available:
|
|
1243
|
+
|
|
1244
|
+
| string type | format |
|
|
1245
|
+
|:--------------------------:|:--------------------:|
|
|
1246
|
+
| `str` | normal Python `str` type is limited by `config.max_string_length` |
|
|
1247
|
+
| `mg.full_str('text')` | not limited |
|
|
1248
|
+
| `mg.unquoted_str('text')` | not limited and not quoted |
|
|
1249
|
+
| `mg.html_str('text')` | for [Grahviz html-like formatting](https://graphviz.org/doc/info/shapes.html#html) |
|
|
1250
|
+
|
|
1251
|
+
The [Grahviz html-like formatting](https://graphviz.org/doc/info/shapes.html#html) supports a subset of html tags that allow for things like:
|
|
1252
|
+
```python
|
|
1253
|
+
import memory_graph as mg
|
|
1254
|
+
|
|
1255
|
+
elements = ['<B>bold</B>',
|
|
1256
|
+
'<I>italic</I>',
|
|
1257
|
+
'<S>strikethrough</S>',
|
|
1258
|
+
'<U>under</U><O>over</O>',
|
|
1259
|
+
'<SUB>sub</SUB><SUP>sup</SUP>',
|
|
1260
|
+
'<FONT FACE="Courier">monospaced</FONT>',
|
|
1261
|
+
'<FONT COLOR="red">red</FONT><FONT COLOR="green">green</FONT>',
|
|
1262
|
+
'<FONT POINT-SIZE="20">Large</FONT><FONT POINT-SIZE="10">small</FONT>',
|
|
1263
|
+
'<TABLE BORDER="1"><TR><TD>c1</TD><TD>c2</TD></TR></TABLE>',
|
|
1264
|
+
'line1<BR/>line2<BR/>line3<BR/>']
|
|
1265
|
+
|
|
1266
|
+
normal_str = '<TABLE BORDER="0">\n'
|
|
1267
|
+
for element in elements:
|
|
1268
|
+
normal_str += '<TR><TD> ' + mg.utils.html_escape(element) + ' </TD><TD> ' + element+ ' </TD></TR>element\n'
|
|
1269
|
+
normal_str += '</TABLE>\n'
|
|
1270
|
+
|
|
1271
|
+
html_example = mg.html_str(normal_str)
|
|
1272
|
+
del elements, element, normal_str
|
|
1273
|
+
mg.show(locals())
|
|
1274
|
+
```
|
|
1275
|
+

|
|
1276
|
+
|
|
1277
|
+
Including the `<IMG>` tag that allows for showing local image files only, but that currently doesn't work in the Memory Graph Web Debugger, that uses 'Viz.js' for graph rendering, unfortunately.
|
|
1278
|
+
|
|
1279
|
+
```python
|
|
1280
|
+
import memory_graph as mg
|
|
1281
|
+
import matplotlib.pyplot as plt
|
|
1282
|
+
import random
|
|
1283
|
+
random.seed(0)
|
|
1284
|
+
|
|
1285
|
+
N = 100
|
|
1286
|
+
value = 0
|
|
1287
|
+
data = [value]
|
|
1288
|
+
for i in range(N):
|
|
1289
|
+
value += random.uniform(-1, 1)
|
|
1290
|
+
data.append(value)
|
|
1291
|
+
|
|
1292
|
+
plt.plot(data)
|
|
1293
|
+
plt.savefig('plot.png')
|
|
1294
|
+
image = {mg.html_str('<IMG SRC="plot.png"/>')}
|
|
1295
|
+
mg.show(locals())
|
|
1296
|
+
```
|
|
1297
|
+

|
|
1239
1298
|
|
|
1240
1299
|
## Collapse Type ##
|
|
1241
1300
|
|
|
@@ -1368,7 +1427,7 @@ mg.show(locals())
|
|
|
1368
1427
|
```
|
|
1369
1428
|

|
|
1370
1429
|
|
|
1371
|
-
Or see it in the [Memory
|
|
1430
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#micropip=numpy&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_numpy.py&play).
|
|
1372
1431
|
|
|
1373
1432
|
## Pandas ##
|
|
1374
1433
|
For pandas types `Series` and `DataFrame`, use `mg.extend_pandas()`:
|
|
@@ -1389,7 +1448,7 @@ mg.show(locals())
|
|
|
1389
1448
|
```
|
|
1390
1449
|

|
|
1391
1450
|
|
|
1392
|
-
Or see it in the [Memory
|
|
1451
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#micropip=pandas&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_pandas.py&play).
|
|
1393
1452
|
|
|
1394
1453
|
## PyTorch ##
|
|
1395
1454
|
For torch type `tensor`, use `mg.extend_torch()`:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Copyright (c) 2023, Bas Terwijn.
|
|
3
3
|
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
4
|
|
|
5
|
-
__version__ = "0.3.
|
|
5
|
+
__version__ = "0.3.79"
|
|
6
6
|
__author__ = 'Bas Terwijn'
|
|
7
7
|
|
|
8
8
|
import memory_graph.memory_to_nodes as memory_to_nodes
|
|
@@ -26,6 +26,7 @@ if not hasattr(builtins, "mg"):
|
|
|
26
26
|
builtins.mg = mg
|
|
27
27
|
|
|
28
28
|
# re-exports for shorter names
|
|
29
|
+
from .config_default import dark_mode, transparent_background
|
|
29
30
|
from .slicer import Slicer
|
|
30
31
|
from .node_leaf import Node_Leaf
|
|
31
32
|
from .node_linear import Node_Linear
|
|
@@ -17,8 +17,98 @@ import memory_graph.utils as utils
|
|
|
17
17
|
|
|
18
18
|
import types
|
|
19
19
|
|
|
20
|
+
""" Colors of the graph. """
|
|
21
|
+
foreground_color_light = 'black'
|
|
22
|
+
index_color_light = '#505050'
|
|
23
|
+
background_color_light = 'white'
|
|
24
|
+
""" Colors of different types in the graph. """
|
|
25
|
+
type_to_color_light = {
|
|
26
|
+
# ================= singular
|
|
27
|
+
type(None) : "gray",
|
|
28
|
+
bool : "pink",
|
|
29
|
+
int : "darkolivegreen1",
|
|
30
|
+
float : "plum",
|
|
31
|
+
complex : "yellow",
|
|
32
|
+
str : "cyan",
|
|
33
|
+
# ================= linear
|
|
34
|
+
tuple : "orange",
|
|
35
|
+
list : "lightcoral",
|
|
36
|
+
set : "orchid1",
|
|
37
|
+
frozenset : "orchid2",
|
|
38
|
+
bytes : "khaki1",
|
|
39
|
+
bytearray : "khaki2",
|
|
40
|
+
# ================= key_value
|
|
41
|
+
Node_Key_Value : "seagreen1", # for classes
|
|
42
|
+
call_stack : 'khaki',
|
|
43
|
+
type: "seagreen3", # where class variables are stored
|
|
44
|
+
dict : "#60a5ff",
|
|
45
|
+
types.MappingProxyType : "dodgerblue2", # not used
|
|
46
|
+
range : "cornsilk2",
|
|
47
|
+
# ================= exception
|
|
48
|
+
BaseException : "#ff6666",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
background_color_dark = "#1d1d1d"
|
|
52
|
+
foreground_color_dark = "#cccccc"
|
|
53
|
+
index_color_dark = "#999999"
|
|
54
|
+
type_to_color_dark = {
|
|
55
|
+
# ================= singular
|
|
56
|
+
type(None) : "#646464",
|
|
57
|
+
bool : "#8d646d",
|
|
58
|
+
int : "#507835",
|
|
59
|
+
float : "#7e4974",
|
|
60
|
+
complex : "#707500",
|
|
61
|
+
str : "#006f6f",
|
|
62
|
+
# ================= linear
|
|
63
|
+
tuple : "#956200",
|
|
64
|
+
list : "#783438",
|
|
65
|
+
set : "#811b7d",
|
|
66
|
+
frozenset : "#6a1666",
|
|
67
|
+
bytes : "#73753f",
|
|
68
|
+
bytearray : "#6a6c3b",
|
|
69
|
+
# ================= key_value
|
|
70
|
+
Node_Key_Value : "#00905d",
|
|
71
|
+
call_stack : '#7e8148',
|
|
72
|
+
type: "#00784e",
|
|
73
|
+
dict : "#355393",
|
|
74
|
+
types.MappingProxyType : "#304a84",
|
|
75
|
+
range : "#7e7d6c",
|
|
76
|
+
# ================= exception
|
|
77
|
+
BaseException : "#a52e37",
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
def set_colors(dark, transparent):
|
|
81
|
+
if dark:
|
|
82
|
+
config.foreground_color = foreground_color_dark
|
|
83
|
+
config.index_color = index_color_dark
|
|
84
|
+
config.background_color = background_color_dark
|
|
85
|
+
config.type_to_color = type_to_color_dark
|
|
86
|
+
else:
|
|
87
|
+
config.foreground_color = foreground_color_light
|
|
88
|
+
config.index_color = index_color_light
|
|
89
|
+
config.background_color = background_color_light
|
|
90
|
+
config.type_to_color = type_to_color_light
|
|
91
|
+
if transparent:
|
|
92
|
+
config.background_color = "transparent"
|
|
93
|
+
|
|
94
|
+
def transparent_background(transparent = None):
|
|
95
|
+
if transparent is None:
|
|
96
|
+
config.transparent_background = not config.transparent_background
|
|
97
|
+
else:
|
|
98
|
+
config.transparent_background = transparent
|
|
99
|
+
set_colors(config.color_mode_dark, config.transparent_background)
|
|
100
|
+
|
|
101
|
+
def dark_mode(dark = None):
|
|
102
|
+
if dark is None:
|
|
103
|
+
config.color_mode_dark = not config.color_mode_dark
|
|
104
|
+
else:
|
|
105
|
+
config.color_mode_dark = dark
|
|
106
|
+
set_colors(config.color_mode_dark, config.transparent_background)
|
|
107
|
+
|
|
20
108
|
def reset():
|
|
21
109
|
|
|
110
|
+
set_colors(config.color_mode_dark, config.transparent_background)
|
|
111
|
+
|
|
22
112
|
""" Reopen viewer each time show() is called, this might change window focus. """
|
|
23
113
|
config.reopen_viewer = True
|
|
24
114
|
|
|
@@ -42,7 +132,8 @@ def reset():
|
|
|
42
132
|
|
|
43
133
|
""" Types that by default will be embedded in the node of their parent. """
|
|
44
134
|
config.embedded_types = {
|
|
45
|
-
type(None), bool, int, float, complex,
|
|
135
|
+
type(None), bool, int, float, complex,
|
|
136
|
+
str, full_str, unquoted_str, html_str,
|
|
46
137
|
types.FunctionType,
|
|
47
138
|
types.MethodType,
|
|
48
139
|
classmethod,
|
|
@@ -85,34 +176,6 @@ def reset():
|
|
|
85
176
|
),
|
|
86
177
|
BaseException: lambda data: Node_Leaf(data, data),
|
|
87
178
|
}
|
|
88
|
-
|
|
89
|
-
""" Colors of different types in the graph. """
|
|
90
|
-
config.type_to_color = {
|
|
91
|
-
# ================= singular
|
|
92
|
-
type(None) : "gray",
|
|
93
|
-
bool : "pink",
|
|
94
|
-
int : "darkolivegreen1",
|
|
95
|
-
float : "plum",
|
|
96
|
-
complex : "yellow",
|
|
97
|
-
str : "cyan",
|
|
98
|
-
# ================= linear
|
|
99
|
-
tuple : "orange",
|
|
100
|
-
list : "lightcoral",
|
|
101
|
-
set : "orchid1",
|
|
102
|
-
frozenset : "orchid2",
|
|
103
|
-
bytes : "khaki1",
|
|
104
|
-
bytearray : "khaki2",
|
|
105
|
-
# ================= key_value
|
|
106
|
-
Node_Key_Value : "seagreen1", # for classes
|
|
107
|
-
call_stack : 'khaki',
|
|
108
|
-
type: "seagreen3", # where class variables are stored
|
|
109
|
-
dict : "#60a5ff",
|
|
110
|
-
types.MappingProxyType : "dodgerblue2", # not used
|
|
111
|
-
range : "cornsilk2",
|
|
112
|
-
# ================= exception
|
|
113
|
-
BaseException : "#ff5555",
|
|
114
|
-
}
|
|
115
|
-
|
|
116
179
|
|
|
117
180
|
""" Types that will be visualized in horizontal or vertical orientation based on a True/False value.
|
|
118
181
|
The 'type_to_horizontal' takes precedence over 'type_to_vertical'.
|
|
@@ -6,9 +6,9 @@ import memory_graph.config as config
|
|
|
6
6
|
import memory_graph.config_helpers as config_helpers
|
|
7
7
|
import memory_graph.utils as utils
|
|
8
8
|
|
|
9
|
-
def html_table_frame(s, border, color, spacing=5):
|
|
9
|
+
def html_table_frame(s, border, color, line_color='black', spacing=5):
|
|
10
10
|
""" Helper function to add the HTML table frame to the string s setting the 'border' and 'color'. """
|
|
11
|
-
return (f'<\n<TABLE BORDER="{border}" CELLBORDER="1" CELLSPACING="{spacing}" CELLPADDING="0" BGCOLOR="{color}" PORT="table">\n <TR>' +
|
|
11
|
+
return (f'<\n<TABLE BORDER="{border}" CELLBORDER="1" CELLSPACING="{spacing}" CELLPADDING="0" BGCOLOR="{color}" COLOR="{line_color}" PORT="table">\n <TR>' +
|
|
12
12
|
s + '</TR>\n</TABLE>\n>')
|
|
13
13
|
|
|
14
14
|
def format_string(value, quote_str):
|
|
@@ -60,7 +60,7 @@ class HTML_Table:
|
|
|
60
60
|
def add_index(self, s):
|
|
61
61
|
""" Add an index s to the table. """
|
|
62
62
|
self.check_add_new_line()
|
|
63
|
-
self.html += f'<TD BORDER="0"><font color="
|
|
63
|
+
self.html += f'<TD BORDER="0"><font color="{config.index_color}">{str(s)}</font></TD>'
|
|
64
64
|
self.col_count += 1
|
|
65
65
|
|
|
66
66
|
def add_entry(self, node, nodes, child, id_to_slices, rounded=False, border=1, dashed=False, embed=False):
|
|
@@ -100,13 +100,13 @@ class HTML_Table:
|
|
|
100
100
|
self.html += f'<TD BORDER="{border}" {r}>...</TD>'
|
|
101
101
|
self.col_count += 1
|
|
102
102
|
|
|
103
|
-
def to_string(self, border=1, color='white'):
|
|
103
|
+
def to_string(self, border=1, color='white', line_color='black'):
|
|
104
104
|
""" Construct the HTML table string with the 'border' and 'color' settings. """
|
|
105
105
|
if self.col_count == 0 and self.row_count == 0:
|
|
106
106
|
if self.is_empty:
|
|
107
107
|
self.add_value(utils.unquoted_str(''), border=0)
|
|
108
|
-
return html_table_frame(self.html, border, color, spacing=0)
|
|
109
|
-
return html_table_frame(self.html, border, color)
|
|
108
|
+
return html_table_frame(self.html, border, color, line_color, spacing=0)
|
|
109
|
+
return html_table_frame(self.html, border, color, line_color)
|
|
110
110
|
|
|
111
111
|
def get_column(self):
|
|
112
112
|
""" Get the number of columns in the table. """
|
|
@@ -218,11 +218,11 @@ def build_graph(graphviz_graph, nodes, root_id, id_to_slices):
|
|
|
218
218
|
border = 3 if node.is_root() else 1
|
|
219
219
|
if config.type_labels:
|
|
220
220
|
graphviz_graph.node(node.get_name(),
|
|
221
|
-
html_table.to_string(border, color),
|
|
221
|
+
html_table.to_string(border, color, config.foreground_color),
|
|
222
222
|
xlabel=node.get_label(slices))
|
|
223
223
|
else:
|
|
224
224
|
graphviz_graph.node(node.get_name(),
|
|
225
|
-
html_table.to_string(border, color))
|
|
225
|
+
html_table.to_string(border, color, config.foreground_color))
|
|
226
226
|
# ------------ edges
|
|
227
227
|
for parent,child,dashed in edges:
|
|
228
228
|
graphviz_graph.edge(parent, child+':table', style='dashed' if dashed else 'solid')
|
|
@@ -261,9 +261,9 @@ def memory_to_nodes(data):
|
|
|
261
261
|
id_to_slices = add_missing_edges(nodes, id_to_slices, config.max_missing_edges)
|
|
262
262
|
#print('id_to_slices:',id_to_slices)
|
|
263
263
|
embed_keys_in_key_value_nodes(nodes, nodes_key_value, id_to_slices)
|
|
264
|
-
graphviz_graph_attr = {'fontname': config.fontname, 'fontsize': config.fontsize}
|
|
265
|
-
graphviz_node_attr = {'fontname': config.fontname, 'fontsize': config.fontsize, 'shape': 'plaintext'}
|
|
266
|
-
graphviz_edge_attr = {'fontname': config.fontname, 'fontsize': config.fontsize}
|
|
264
|
+
graphviz_graph_attr = {'fontname': config.fontname, 'fontsize': config.fontsize, 'fontcolor': config.foreground_color, 'bgcolor': config.background_color}
|
|
265
|
+
graphviz_node_attr = {'fontname': config.fontname, 'fontsize': config.fontsize, 'shape': 'plaintext', 'fontcolor': config.foreground_color}
|
|
266
|
+
graphviz_edge_attr = {'fontname': config.fontname, 'fontsize': config.fontsize, 'fontcolor': config.foreground_color, 'color': config.foreground_color}
|
|
267
267
|
graphviz_graph=graphviz.Digraph('memory_graph',
|
|
268
268
|
graph_attr=graphviz_graph_attr,
|
|
269
269
|
node_attr=graphviz_node_attr,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memory_graph
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.79
|
|
4
4
|
Summary: Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy.
|
|
5
5
|
Author-email: Bas Terwijn <bterwijn@gmail.com>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -27,7 +27,7 @@ Additionally [Graphviz](https://graphviz.org/download/) needs to be installed.
|
|
|
27
27
|
|
|
28
28
|
# Highlights #
|
|
29
29
|

|
|
30
|
-
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1&
|
|
30
|
+
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1&play) 👈 now, no installation required!
|
|
31
31
|
|
|
32
32
|
- learn the right **mental model** to think about Python data (references, mutability, shallow vs deep copy)
|
|
33
33
|
- **visualize the structure of your data** to more easily understand and debug any data structure
|
|
@@ -35,7 +35,7 @@ Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph
|
|
|
35
35
|
|
|
36
36
|
An example Binary Tree data structure:
|
|
37
37
|

|
|
38
|
-
Or see it in the [Memory
|
|
38
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play).
|
|
39
39
|
|
|
40
40
|
# Videos #
|
|
41
41
|
| [](https://www.youtube.com/watch?v=23_bHcr7hqo) | [](https://www.youtube.com/watch?v=pvIJgHCaXhU) |
|
|
@@ -163,7 +163,7 @@ Bas Terwijn
|
|
|
163
163
|
## Inspiration ##
|
|
164
164
|
Inspired by [Python Tutor](https://pythontutor.com/).
|
|
165
165
|
|
|
166
|
-
The main differences are that by running memory_graph locally we support Python Tutor’s [unsupported features](https://github.com/pythontutor-dev/pythontutor/blob/master/unsupported-features.md#unsupported-features) so that it scales to full programs in many environments and IDEs instead of just code snippets in a webbrowser, and by mirroring the data’s hierarchy we improve graph readability for larger graphs.
|
|
166
|
+
The main differences are that by running memory_graph locally we support Python Tutor’s [unsupported features](https://github.com/pythontutor-dev/pythontutor/blob/master/unsupported-features.md#unsupported-features) so that it scales to full multi-file programs in many environments and IDEs instead of just code snippets in a webbrowser, and by mirroring the data’s hierarchy we improve graph readability for larger graphs.
|
|
167
167
|
|
|
168
168
|
## Social Media #
|
|
169
169
|
* [LinkedIn](https://www.linkedin.com/groups/13244150/)
|
|
@@ -242,7 +242,7 @@ mg.show(locals())
|
|
|
242
242
|
|
|
243
243
|

|
|
244
244
|
|
|
245
|
-
Or see it in the [Memory
|
|
245
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/copies.py&play).
|
|
246
246
|
|
|
247
247
|
## Custom Copy ##
|
|
248
248
|
We can write our own custom copy function or method in case the three standard "copy" options don't do what we want. For example, in the code below the `custom_copy()` method of My_Class copies the `digits` but shares the `letters` between two objects.
|
|
@@ -270,7 +270,7 @@ mg.show(locals())
|
|
|
270
270
|
```
|
|
271
271
|

|
|
272
272
|
|
|
273
|
-
Or see it in the [Memory
|
|
273
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/custom_copy.py&breakpoints=15&continues=1&play).
|
|
274
274
|
|
|
275
275
|
## Name Rebinding ##
|
|
276
276
|
When `a` and `b` share a mutable value, then changing the value of `b` changes the value of `a` and vice versa. However, reassigning `b` does not change `a`. When you reassign `b`, you only **rebind** the name `b` to another value without affecting any other variable.
|
|
@@ -300,7 +300,7 @@ mg.render(locals(), 'rebinding3.png')
|
|
|
300
300
|
|:--------------:|:--------------:|:--------------:|
|
|
301
301
|
| rebinding1.png | rebinding2.png | rebinding3.png |
|
|
302
302
|
|
|
303
|
-
Or see it in the [Memory
|
|
303
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/rebind.py&play).
|
|
304
304
|
|
|
305
305
|
## Copying Values of Immutable Type ##
|
|
306
306
|
Because a value of immutable type will be copied automatically when it is changed, there is no need to copy it beforehand. Therefore, a shallow or deep copy of a value of immutable type will result in just an assignment to save on the time needed to make the copy and the space (=memory) needed to store the values.
|
|
@@ -358,7 +358,7 @@ print(f"a:{a} b:{b} c:{c}")
|
|
|
358
358
|
```
|
|
359
359
|

|
|
360
360
|
|
|
361
|
-
Or see it in the [Memory
|
|
361
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/function_call.py&play).
|
|
362
362
|
|
|
363
363
|
In the printed output we see that only `a` is changed as a result of the function call:
|
|
364
364
|
```
|
|
@@ -387,7 +387,7 @@ print(f"a:{a} b:{b[0]}")
|
|
|
387
387
|
```
|
|
388
388
|
a:10 b:11
|
|
389
389
|
```
|
|
390
|
-
Or see it in the [Memory
|
|
390
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/wrap.py&breakpoints=5&continues=1&play)
|
|
391
391
|
|
|
392
392
|
The effect of calling `add_one()` is that `b[0]` increases by 1, while `a` is unaffected.
|
|
393
393
|
|
|
@@ -428,7 +428,7 @@ print( factorial(4) )
|
|
|
428
428
|
|
|
429
429
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
430
430
|
|
|
431
|
-
Or see it in the [Memory
|
|
431
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/factorial.py×tep=1.0&play).
|
|
432
432
|
|
|
433
433
|
## Binary Conversion ##
|
|
434
434
|
A more interesting recursive example is function `binary()` that converts a integer from decimal to binary representation.
|
|
@@ -452,7 +452,7 @@ print( binary(100) )
|
|
|
452
452
|
[1, 1, 0, 0, 1, 0, 0]
|
|
453
453
|
```
|
|
454
454
|
|
|
455
|
-
Or see it in the [Memory
|
|
455
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/binary_convert.py×tep=1.0&play).
|
|
456
456
|
|
|
457
457
|
## Power Set ##
|
|
458
458
|
A more complex recursive example is function `power_set()` where lists are shared by different function calls. A power set is the set of all subsets of a collection of values.
|
|
@@ -484,7 +484,7 @@ print( power_set(['a', 'b', 'c']) )
|
|
|
484
484
|
[['a', 'b', 'c'], ['a', 'b'], ['a', 'c'], ['a'], ['b', 'c'], ['b'], ['c'], []]
|
|
485
485
|
```
|
|
486
486
|
|
|
487
|
-
Or see it in the [Memory
|
|
487
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/power_set.py×tep=1.0&play).
|
|
488
488
|
|
|
489
489
|
## Invocation Tree ##
|
|
490
490
|
The memory_graph package visualizes data at the currect time, but to better understand recursion it can also be helpful to visualize different function calls over time. This is what the [invocation_tree](https://github.com/bterwijn/invocation_tree?tab=readme-ov-file#installation) package does.
|
|
@@ -648,7 +648,7 @@ for i in range(n):
|
|
|
648
648
|
Here we show values being added to a Linked List in Cursor AI. When adding the last value '5' we "Step Into" the code to show more of the details.
|
|
649
649
|

|
|
650
650
|
|
|
651
|
-
Or see it in the [Memory
|
|
651
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/linked_list.py×tep=0.2&play).
|
|
652
652
|
|
|
653
653
|
## Binary Tree ##
|
|
654
654
|
```python
|
|
@@ -690,7 +690,7 @@ for i in range(n):
|
|
|
690
690
|
Here we show values being inserted in a Binary Tree in Visual Studio Code. When inserting the last value '29' we "Step Into" the code to show the recursive implementation.
|
|
691
691
|

|
|
692
692
|
|
|
693
|
-
See it in the [Memory
|
|
693
|
+
See it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play) or see the more advanced [Multiway Tree](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/multiway_tree.py&breakpoints=19,33&continues=1×tep=0.2&play) with more than two children per node, making the tree less deep and more efficient.
|
|
694
694
|
|
|
695
695
|
## Hash Set ##
|
|
696
696
|
```python
|
|
@@ -734,7 +734,7 @@ for i in range(n):
|
|
|
734
734
|
Here we show values being inserted in a HashSet in PyCharm. When inserting the last value '44' we "Step Into" the code to show more of the details.
|
|
735
735
|

|
|
736
736
|
|
|
737
|
-
Or see it in the [Memory
|
|
737
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py&breakpoints=32&continues=1×tep=0.5&play).
|
|
738
738
|
|
|
739
739
|
|
|
740
740
|
# Sorting Algorithms #
|
|
@@ -761,7 +761,7 @@ In this configuration example we show the decimal, binary and [two's complement
|
|
|
761
761
|
|
|
762
762
|
A sliding puzzle solver as a challenging example showing how memory_graph deals with large amounts of data. Click "Continue" to step through the breadth-first search generations until a solution path is found:
|
|
763
763
|
|
|
764
|
-
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=16,26,28,39&continues=1)
|
|
764
|
+
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=16,26,28,39,136&continues=1)
|
|
765
765
|
|
|
766
766
|

|
|
767
767
|
|
|
@@ -1255,7 +1255,66 @@ mg.config.type_to_node[List_View] = (lambda l: mg.Node_Linear(l,
|
|
|
1255
1255
|
```
|
|
1256
1256
|

|
|
1257
1257
|
|
|
1258
|
-
Or see it in the [Memory
|
|
1258
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_search.py&breakpoints=38&continues=1×tep=0.5&play)
|
|
1259
|
+
|
|
1260
|
+
## String Types ##
|
|
1261
|
+
|
|
1262
|
+
For special string formatting different `str` types are available:
|
|
1263
|
+
|
|
1264
|
+
| string type | format |
|
|
1265
|
+
|:--------------------------:|:--------------------:|
|
|
1266
|
+
| `str` | normal Python `str` type is limited by `config.max_string_length` |
|
|
1267
|
+
| `mg.full_str('text')` | not limited |
|
|
1268
|
+
| `mg.unquoted_str('text')` | not limited and not quoted |
|
|
1269
|
+
| `mg.html_str('text')` | for [Grahviz html-like formatting](https://graphviz.org/doc/info/shapes.html#html) |
|
|
1270
|
+
|
|
1271
|
+
The [Grahviz html-like formatting](https://graphviz.org/doc/info/shapes.html#html) supports a subset of html tags that allow for things like:
|
|
1272
|
+
```python
|
|
1273
|
+
import memory_graph as mg
|
|
1274
|
+
|
|
1275
|
+
elements = ['<B>bold</B>',
|
|
1276
|
+
'<I>italic</I>',
|
|
1277
|
+
'<S>strikethrough</S>',
|
|
1278
|
+
'<U>under</U><O>over</O>',
|
|
1279
|
+
'<SUB>sub</SUB><SUP>sup</SUP>',
|
|
1280
|
+
'<FONT FACE="Courier">monospaced</FONT>',
|
|
1281
|
+
'<FONT COLOR="red">red</FONT><FONT COLOR="green">green</FONT>',
|
|
1282
|
+
'<FONT POINT-SIZE="20">Large</FONT><FONT POINT-SIZE="10">small</FONT>',
|
|
1283
|
+
'<TABLE BORDER="1"><TR><TD>c1</TD><TD>c2</TD></TR></TABLE>',
|
|
1284
|
+
'line1<BR/>line2<BR/>line3<BR/>']
|
|
1285
|
+
|
|
1286
|
+
normal_str = '<TABLE BORDER="0">\n'
|
|
1287
|
+
for element in elements:
|
|
1288
|
+
normal_str += '<TR><TD> ' + mg.utils.html_escape(element) + ' </TD><TD> ' + element+ ' </TD></TR>element\n'
|
|
1289
|
+
normal_str += '</TABLE>\n'
|
|
1290
|
+
|
|
1291
|
+
html_example = mg.html_str(normal_str)
|
|
1292
|
+
del elements, element, normal_str
|
|
1293
|
+
mg.show(locals())
|
|
1294
|
+
```
|
|
1295
|
+

|
|
1296
|
+
|
|
1297
|
+
Including the `<IMG>` tag that allows for showing local image files only, but that currently doesn't work in the Memory Graph Web Debugger, that uses 'Viz.js' for graph rendering, unfortunately.
|
|
1298
|
+
|
|
1299
|
+
```python
|
|
1300
|
+
import memory_graph as mg
|
|
1301
|
+
import matplotlib.pyplot as plt
|
|
1302
|
+
import random
|
|
1303
|
+
random.seed(0)
|
|
1304
|
+
|
|
1305
|
+
N = 100
|
|
1306
|
+
value = 0
|
|
1307
|
+
data = [value]
|
|
1308
|
+
for i in range(N):
|
|
1309
|
+
value += random.uniform(-1, 1)
|
|
1310
|
+
data.append(value)
|
|
1311
|
+
|
|
1312
|
+
plt.plot(data)
|
|
1313
|
+
plt.savefig('plot.png')
|
|
1314
|
+
image = {mg.html_str('<IMG SRC="plot.png"/>')}
|
|
1315
|
+
mg.show(locals())
|
|
1316
|
+
```
|
|
1317
|
+

|
|
1259
1318
|
|
|
1260
1319
|
## Collapse Type ##
|
|
1261
1320
|
|
|
@@ -1388,7 +1447,7 @@ mg.show(locals())
|
|
|
1388
1447
|
```
|
|
1389
1448
|

|
|
1390
1449
|
|
|
1391
|
-
Or see it in the [Memory
|
|
1450
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#micropip=numpy&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_numpy.py&play).
|
|
1392
1451
|
|
|
1393
1452
|
## Pandas ##
|
|
1394
1453
|
For pandas types `Series` and `DataFrame`, use `mg.extend_pandas()`:
|
|
@@ -1409,7 +1468,7 @@ mg.show(locals())
|
|
|
1409
1468
|
```
|
|
1410
1469
|

|
|
1411
1470
|
|
|
1412
|
-
Or see it in the [Memory
|
|
1471
|
+
Or see it in the [Memory Graph Web Debugger](https://memory-graph.com/#micropip=pandas&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_pandas.py&play).
|
|
1413
1472
|
|
|
1414
1473
|
## PyTorch ##
|
|
1415
1474
|
For torch type `tensor`, use `mg.extend_torch()`:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "memory_graph"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.79"
|
|
8
8
|
description = "Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy."
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Bas Terwijn", email = "bterwijn@gmail.com"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|