memory-graph 0.3.77__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.77 → memory_graph-0.3.79}/PKG-INFO +85 -22
- {memory_graph-0.3.77 → memory_graph-0.3.79}/README.md +84 -21
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/__init__.py +2 -1
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/config.py +5 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/config_default.py +92 -29
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/html_table.py +10 -8
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/memory_to_nodes.py +5 -5
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/utils.py +5 -1
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph.egg-info/PKG-INFO +85 -22
- {memory_graph-0.3.77 → memory_graph-0.3.79}/pyproject.toml +1 -1
- {memory_graph-0.3.77 → memory_graph-0.3.79}/LICENSE.txt +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/call_stack.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/config_helpers.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/extension_numpy.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/extension_pandas.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/extension_torch.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/list_view.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/node_base.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/node_key_value.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/node_leaf.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/node_linear.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/node_table.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/sequence.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/slicer.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/slices.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/slices_iterator.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/slices_table_iterator.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/test.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/test_max_graph_depth.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/test_memory_graph.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/test_memory_to_nodes.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/test_sequence.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/test_slicer.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/test_slices.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph/test_slices_iterator.py +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph.egg-info/SOURCES.txt +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph.egg-info/dependency_links.txt +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph.egg-info/requires.txt +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/memory_graph.egg-info/top_level.txt +0 -0
- {memory_graph-0.3.77 → memory_graph-0.3.79}/setup.cfg +0 -0
- {memory_graph-0.3.77 → 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) |
|
|
@@ -102,7 +102,7 @@ a graph showing `a` and `b` share the list
|
|
|
102
102
|
|
|
103
103
|
</td></tr></table>
|
|
104
104
|
|
|
105
|
-
The fact that `a` and `b` share the list can not be verified by printing the lists. It can be verified by comparing the identity of both variables using the `id()` function or by using the `is` comparison operator as shown in the program output below, but this quickly becomes impractical for larger programs.
|
|
105
|
+
The fact that `a` and `b` share the list can **not** be verified by printing the lists. It can be verified by comparing the identity of both variables using the `id()` function or by using the `is` comparison operator as shown in the program output below, but this quickly becomes impractical for larger programs.
|
|
106
106
|
```{verbatim}
|
|
107
107
|
a: 4, 3, 2, 1
|
|
108
108
|
b: 4, 3, 2, 1
|
|
@@ -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,12 +270,16 @@ 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.
|
|
277
277
|
|
|
278
|
-
|
|
278
|
+
In the example below, also note the difference between expressions:
|
|
279
|
+
- `b += [300]`: that changes both `b` and `a`
|
|
280
|
+
- `c = c + [600]`: that first creates a new value `c + [600]` and then assigns this new value to `c` without affecting `b`
|
|
281
|
+
|
|
282
|
+
This shows that `x += y` is not the same as `x = x + y` for a value `x` of mutable type.
|
|
279
283
|
|
|
280
284
|
```python
|
|
281
285
|
import memory_graph as mg
|
|
@@ -296,7 +300,7 @@ mg.render(locals(), 'rebinding3.png')
|
|
|
296
300
|
|:--------------:|:--------------:|:--------------:|
|
|
297
301
|
| rebinding1.png | rebinding2.png | rebinding3.png |
|
|
298
302
|
|
|
299
|
-
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).
|
|
300
304
|
|
|
301
305
|
## Copying Values of Immutable Type ##
|
|
302
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.
|
|
@@ -354,7 +358,7 @@ print(f"a:{a} b:{b} c:{c}")
|
|
|
354
358
|
```
|
|
355
359
|

|
|
356
360
|
|
|
357
|
-
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).
|
|
358
362
|
|
|
359
363
|
In the printed output we see that only `a` is changed as a result of the function call:
|
|
360
364
|
```
|
|
@@ -383,7 +387,7 @@ print(f"a:{a} b:{b[0]}")
|
|
|
383
387
|
```
|
|
384
388
|
a:10 b:11
|
|
385
389
|
```
|
|
386
|
-
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)
|
|
387
391
|
|
|
388
392
|
The effect of calling `add_one()` is that `b[0]` increases by 1, while `a` is unaffected.
|
|
389
393
|
|
|
@@ -424,7 +428,7 @@ print( factorial(4) )
|
|
|
424
428
|
|
|
425
429
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
426
430
|
|
|
427
|
-
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).
|
|
428
432
|
|
|
429
433
|
## Binary Conversion ##
|
|
430
434
|
A more interesting recursive example is function `binary()` that converts a integer from decimal to binary representation.
|
|
@@ -448,7 +452,7 @@ print( binary(100) )
|
|
|
448
452
|
[1, 1, 0, 0, 1, 0, 0]
|
|
449
453
|
```
|
|
450
454
|
|
|
451
|
-
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).
|
|
452
456
|
|
|
453
457
|
## Power Set ##
|
|
454
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.
|
|
@@ -480,7 +484,7 @@ print( power_set(['a', 'b', 'c']) )
|
|
|
480
484
|
[['a', 'b', 'c'], ['a', 'b'], ['a', 'c'], ['a'], ['b', 'c'], ['b'], ['c'], []]
|
|
481
485
|
```
|
|
482
486
|
|
|
483
|
-
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).
|
|
484
488
|
|
|
485
489
|
## Invocation Tree ##
|
|
486
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.
|
|
@@ -644,7 +648,7 @@ for i in range(n):
|
|
|
644
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.
|
|
645
649
|

|
|
646
650
|
|
|
647
|
-
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).
|
|
648
652
|
|
|
649
653
|
## Binary Tree ##
|
|
650
654
|
```python
|
|
@@ -686,7 +690,7 @@ for i in range(n):
|
|
|
686
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.
|
|
687
691
|

|
|
688
692
|
|
|
689
|
-
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.
|
|
690
694
|
|
|
691
695
|
## Hash Set ##
|
|
692
696
|
```python
|
|
@@ -730,7 +734,7 @@ for i in range(n):
|
|
|
730
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.
|
|
731
735
|

|
|
732
736
|
|
|
733
|
-
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).
|
|
734
738
|
|
|
735
739
|
|
|
736
740
|
# Sorting Algorithms #
|
|
@@ -757,7 +761,7 @@ In this configuration example we show the decimal, binary and [two's complement
|
|
|
757
761
|
|
|
758
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:
|
|
759
763
|
|
|
760
|
-
- [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)
|
|
761
765
|
|
|
762
766
|

|
|
763
767
|
|
|
@@ -1245,13 +1249,72 @@ Arguably the visualization is then more clear when we show a List_View object as
|
|
|
1245
1249
|
|
|
1246
1250
|
```python
|
|
1247
1251
|
mg.config.type_to_node[List_View] = (lambda l: mg.Node_Linear(l,
|
|
1248
|
-
[v if l.begin <= i < l.end else mg.
|
|
1252
|
+
[v if l.begin <= i < l.end else mg.unquoted_str('') for i, v in enumerate(l.lst)]
|
|
1249
1253
|
if hasattr(l, 'end') else [])
|
|
1250
1254
|
)
|
|
1251
1255
|
```
|
|
1252
1256
|

|
|
1253
1257
|
|
|
1254
|
-
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
|
+

|
|
1255
1318
|
|
|
1256
1319
|
## Collapse Type ##
|
|
1257
1320
|
|
|
@@ -1384,7 +1447,7 @@ mg.show(locals())
|
|
|
1384
1447
|
```
|
|
1385
1448
|

|
|
1386
1449
|
|
|
1387
|
-
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).
|
|
1388
1451
|
|
|
1389
1452
|
## Pandas ##
|
|
1390
1453
|
For pandas types `Series` and `DataFrame`, use `mg.extend_pandas()`:
|
|
@@ -1405,7 +1468,7 @@ mg.show(locals())
|
|
|
1405
1468
|
```
|
|
1406
1469
|

|
|
1407
1470
|
|
|
1408
|
-
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).
|
|
1409
1472
|
|
|
1410
1473
|
## PyTorch ##
|
|
1411
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) |
|
|
@@ -82,7 +82,7 @@ a graph showing `a` and `b` share the list
|
|
|
82
82
|
|
|
83
83
|
</td></tr></table>
|
|
84
84
|
|
|
85
|
-
The fact that `a` and `b` share the list can not be verified by printing the lists. It can be verified by comparing the identity of both variables using the `id()` function or by using the `is` comparison operator as shown in the program output below, but this quickly becomes impractical for larger programs.
|
|
85
|
+
The fact that `a` and `b` share the list can **not** be verified by printing the lists. It can be verified by comparing the identity of both variables using the `id()` function or by using the `is` comparison operator as shown in the program output below, but this quickly becomes impractical for larger programs.
|
|
86
86
|
```{verbatim}
|
|
87
87
|
a: 4, 3, 2, 1
|
|
88
88
|
b: 4, 3, 2, 1
|
|
@@ -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,12 +250,16 @@ 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.
|
|
257
257
|
|
|
258
|
-
|
|
258
|
+
In the example below, also note the difference between expressions:
|
|
259
|
+
- `b += [300]`: that changes both `b` and `a`
|
|
260
|
+
- `c = c + [600]`: that first creates a new value `c + [600]` and then assigns this new value to `c` without affecting `b`
|
|
261
|
+
|
|
262
|
+
This shows that `x += y` is not the same as `x = x + y` for a value `x` of mutable type.
|
|
259
263
|
|
|
260
264
|
```python
|
|
261
265
|
import memory_graph as mg
|
|
@@ -276,7 +280,7 @@ mg.render(locals(), 'rebinding3.png')
|
|
|
276
280
|
|:--------------:|:--------------:|:--------------:|
|
|
277
281
|
| rebinding1.png | rebinding2.png | rebinding3.png |
|
|
278
282
|
|
|
279
|
-
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).
|
|
280
284
|
|
|
281
285
|
## Copying Values of Immutable Type ##
|
|
282
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.
|
|
@@ -334,7 +338,7 @@ print(f"a:{a} b:{b} c:{c}")
|
|
|
334
338
|
```
|
|
335
339
|

|
|
336
340
|
|
|
337
|
-
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).
|
|
338
342
|
|
|
339
343
|
In the printed output we see that only `a` is changed as a result of the function call:
|
|
340
344
|
```
|
|
@@ -363,7 +367,7 @@ print(f"a:{a} b:{b[0]}")
|
|
|
363
367
|
```
|
|
364
368
|
a:10 b:11
|
|
365
369
|
```
|
|
366
|
-
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)
|
|
367
371
|
|
|
368
372
|
The effect of calling `add_one()` is that `b[0]` increases by 1, while `a` is unaffected.
|
|
369
373
|
|
|
@@ -404,7 +408,7 @@ print( factorial(4) )
|
|
|
404
408
|
|
|
405
409
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
406
410
|
|
|
407
|
-
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).
|
|
408
412
|
|
|
409
413
|
## Binary Conversion ##
|
|
410
414
|
A more interesting recursive example is function `binary()` that converts a integer from decimal to binary representation.
|
|
@@ -428,7 +432,7 @@ print( binary(100) )
|
|
|
428
432
|
[1, 1, 0, 0, 1, 0, 0]
|
|
429
433
|
```
|
|
430
434
|
|
|
431
|
-
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).
|
|
432
436
|
|
|
433
437
|
## Power Set ##
|
|
434
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.
|
|
@@ -460,7 +464,7 @@ print( power_set(['a', 'b', 'c']) )
|
|
|
460
464
|
[['a', 'b', 'c'], ['a', 'b'], ['a', 'c'], ['a'], ['b', 'c'], ['b'], ['c'], []]
|
|
461
465
|
```
|
|
462
466
|
|
|
463
|
-
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).
|
|
464
468
|
|
|
465
469
|
## Invocation Tree ##
|
|
466
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.
|
|
@@ -624,7 +628,7 @@ for i in range(n):
|
|
|
624
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.
|
|
625
629
|

|
|
626
630
|
|
|
627
|
-
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).
|
|
628
632
|
|
|
629
633
|
## Binary Tree ##
|
|
630
634
|
```python
|
|
@@ -666,7 +670,7 @@ for i in range(n):
|
|
|
666
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.
|
|
667
671
|

|
|
668
672
|
|
|
669
|
-
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.
|
|
670
674
|
|
|
671
675
|
## Hash Set ##
|
|
672
676
|
```python
|
|
@@ -710,7 +714,7 @@ for i in range(n):
|
|
|
710
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.
|
|
711
715
|

|
|
712
716
|
|
|
713
|
-
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).
|
|
714
718
|
|
|
715
719
|
|
|
716
720
|
# Sorting Algorithms #
|
|
@@ -737,7 +741,7 @@ In this configuration example we show the decimal, binary and [two's complement
|
|
|
737
741
|
|
|
738
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:
|
|
739
743
|
|
|
740
|
-
- [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)
|
|
741
745
|
|
|
742
746
|

|
|
743
747
|
|
|
@@ -1225,13 +1229,72 @@ Arguably the visualization is then more clear when we show a List_View object as
|
|
|
1225
1229
|
|
|
1226
1230
|
```python
|
|
1227
1231
|
mg.config.type_to_node[List_View] = (lambda l: mg.Node_Linear(l,
|
|
1228
|
-
[v if l.begin <= i < l.end else mg.
|
|
1232
|
+
[v if l.begin <= i < l.end else mg.unquoted_str('') for i, v in enumerate(l.lst)]
|
|
1229
1233
|
if hasattr(l, 'end') else [])
|
|
1230
1234
|
)
|
|
1231
1235
|
```
|
|
1232
1236
|

|
|
1233
1237
|
|
|
1234
|
-
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
|
+

|
|
1235
1298
|
|
|
1236
1299
|
## Collapse Type ##
|
|
1237
1300
|
|
|
@@ -1364,7 +1427,7 @@ mg.show(locals())
|
|
|
1364
1427
|
```
|
|
1365
1428
|

|
|
1366
1429
|
|
|
1367
|
-
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).
|
|
1368
1431
|
|
|
1369
1432
|
## Pandas ##
|
|
1370
1433
|
For pandas types `Series` and `DataFrame`, use `mg.extend_pandas()`:
|
|
@@ -1385,7 +1448,7 @@ mg.show(locals())
|
|
|
1385
1448
|
```
|
|
1386
1449
|

|
|
1387
1450
|
|
|
1388
|
-
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).
|
|
1389
1452
|
|
|
1390
1453
|
## PyTorch ##
|
|
1391
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,17 +6,19 @@ 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):
|
|
15
15
|
""" Helper function to format 'value' to be shown in the graph. We escape html characters and convert newlines to <BR/> tags. """
|
|
16
16
|
to_string = config_helpers.get_to_string(value)
|
|
17
17
|
s = to_string(value)
|
|
18
|
-
if quote_str and isinstance(value, str
|
|
18
|
+
if quote_str and isinstance(value, (str, utils.full_str)):
|
|
19
19
|
s = utils.quote_string(s)
|
|
20
|
+
if not isinstance(value, utils.html_str): # <IMG> can't have padding in Graphviz
|
|
21
|
+
s = utils.pad_string(s)
|
|
20
22
|
return s
|
|
21
23
|
|
|
22
24
|
class HTML_Table:
|
|
@@ -58,7 +60,7 @@ class HTML_Table:
|
|
|
58
60
|
def add_index(self, s):
|
|
59
61
|
""" Add an index s to the table. """
|
|
60
62
|
self.check_add_new_line()
|
|
61
|
-
self.html += f'<TD BORDER="0"><font color="
|
|
63
|
+
self.html += f'<TD BORDER="0"><font color="{config.index_color}">{str(s)}</font></TD>'
|
|
62
64
|
self.col_count += 1
|
|
63
65
|
|
|
64
66
|
def add_entry(self, node, nodes, child, id_to_slices, rounded=False, border=1, dashed=False, embed=False):
|
|
@@ -77,7 +79,7 @@ class HTML_Table:
|
|
|
77
79
|
""" Helper function to add 'value' to the table. """
|
|
78
80
|
self.check_add_new_line()
|
|
79
81
|
r = ' STYLE="ROUNDED"' if rounded else ''
|
|
80
|
-
self.html += f'<TD BORDER="{border}"{r}>
|
|
82
|
+
self.html += f'<TD BORDER="{border}"{r}>{format_string(value, not rounded)}</TD>'
|
|
81
83
|
self.is_empty = False
|
|
82
84
|
self.col_count += 1
|
|
83
85
|
|
|
@@ -98,13 +100,13 @@ class HTML_Table:
|
|
|
98
100
|
self.html += f'<TD BORDER="{border}" {r}>...</TD>'
|
|
99
101
|
self.col_count += 1
|
|
100
102
|
|
|
101
|
-
def to_string(self, border=1, color='white'):
|
|
103
|
+
def to_string(self, border=1, color='white', line_color='black'):
|
|
102
104
|
""" Construct the HTML table string with the 'border' and 'color' settings. """
|
|
103
105
|
if self.col_count == 0 and self.row_count == 0:
|
|
104
106
|
if self.is_empty:
|
|
105
107
|
self.add_value(utils.unquoted_str(''), border=0)
|
|
106
|
-
return html_table_frame(self.html, border, color, spacing=0)
|
|
107
|
-
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)
|
|
108
110
|
|
|
109
111
|
def get_column(self):
|
|
110
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,
|
|
@@ -45,9 +45,13 @@ def prep_str(s):
|
|
|
45
45
|
return newlines_to_br(html_escape(limit_string(s)))
|
|
46
46
|
|
|
47
47
|
def quote_string(s):
|
|
48
|
-
""" Quote 's'
|
|
48
|
+
""" Quote string 's'. """
|
|
49
49
|
return "'" + s + "'"
|
|
50
50
|
|
|
51
|
+
def pad_string(s):
|
|
52
|
+
""" Pad string 's'. """
|
|
53
|
+
return " " + s + " "
|
|
54
|
+
|
|
51
55
|
def exception_to_string(e):
|
|
52
56
|
""" Helper function to convert the traceback of an exception to a string. """
|
|
53
57
|
return ''.join(traceback.format_exception(type(e), e, e.__traceback__)).strip()
|
|
@@ -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) |
|
|
@@ -102,7 +102,7 @@ a graph showing `a` and `b` share the list
|
|
|
102
102
|
|
|
103
103
|
</td></tr></table>
|
|
104
104
|
|
|
105
|
-
The fact that `a` and `b` share the list can not be verified by printing the lists. It can be verified by comparing the identity of both variables using the `id()` function or by using the `is` comparison operator as shown in the program output below, but this quickly becomes impractical for larger programs.
|
|
105
|
+
The fact that `a` and `b` share the list can **not** be verified by printing the lists. It can be verified by comparing the identity of both variables using the `id()` function or by using the `is` comparison operator as shown in the program output below, but this quickly becomes impractical for larger programs.
|
|
106
106
|
```{verbatim}
|
|
107
107
|
a: 4, 3, 2, 1
|
|
108
108
|
b: 4, 3, 2, 1
|
|
@@ -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,12 +270,16 @@ 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.
|
|
277
277
|
|
|
278
|
-
|
|
278
|
+
In the example below, also note the difference between expressions:
|
|
279
|
+
- `b += [300]`: that changes both `b` and `a`
|
|
280
|
+
- `c = c + [600]`: that first creates a new value `c + [600]` and then assigns this new value to `c` without affecting `b`
|
|
281
|
+
|
|
282
|
+
This shows that `x += y` is not the same as `x = x + y` for a value `x` of mutable type.
|
|
279
283
|
|
|
280
284
|
```python
|
|
281
285
|
import memory_graph as mg
|
|
@@ -296,7 +300,7 @@ mg.render(locals(), 'rebinding3.png')
|
|
|
296
300
|
|:--------------:|:--------------:|:--------------:|
|
|
297
301
|
| rebinding1.png | rebinding2.png | rebinding3.png |
|
|
298
302
|
|
|
299
|
-
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).
|
|
300
304
|
|
|
301
305
|
## Copying Values of Immutable Type ##
|
|
302
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.
|
|
@@ -354,7 +358,7 @@ print(f"a:{a} b:{b} c:{c}")
|
|
|
354
358
|
```
|
|
355
359
|

|
|
356
360
|
|
|
357
|
-
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).
|
|
358
362
|
|
|
359
363
|
In the printed output we see that only `a` is changed as a result of the function call:
|
|
360
364
|
```
|
|
@@ -383,7 +387,7 @@ print(f"a:{a} b:{b[0]}")
|
|
|
383
387
|
```
|
|
384
388
|
a:10 b:11
|
|
385
389
|
```
|
|
386
|
-
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)
|
|
387
391
|
|
|
388
392
|
The effect of calling `add_one()` is that `b[0]` increases by 1, while `a` is unaffected.
|
|
389
393
|
|
|
@@ -424,7 +428,7 @@ print( factorial(4) )
|
|
|
424
428
|
|
|
425
429
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
426
430
|
|
|
427
|
-
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).
|
|
428
432
|
|
|
429
433
|
## Binary Conversion ##
|
|
430
434
|
A more interesting recursive example is function `binary()` that converts a integer from decimal to binary representation.
|
|
@@ -448,7 +452,7 @@ print( binary(100) )
|
|
|
448
452
|
[1, 1, 0, 0, 1, 0, 0]
|
|
449
453
|
```
|
|
450
454
|
|
|
451
|
-
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).
|
|
452
456
|
|
|
453
457
|
## Power Set ##
|
|
454
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.
|
|
@@ -480,7 +484,7 @@ print( power_set(['a', 'b', 'c']) )
|
|
|
480
484
|
[['a', 'b', 'c'], ['a', 'b'], ['a', 'c'], ['a'], ['b', 'c'], ['b'], ['c'], []]
|
|
481
485
|
```
|
|
482
486
|
|
|
483
|
-
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).
|
|
484
488
|
|
|
485
489
|
## Invocation Tree ##
|
|
486
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.
|
|
@@ -644,7 +648,7 @@ for i in range(n):
|
|
|
644
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.
|
|
645
649
|

|
|
646
650
|
|
|
647
|
-
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).
|
|
648
652
|
|
|
649
653
|
## Binary Tree ##
|
|
650
654
|
```python
|
|
@@ -686,7 +690,7 @@ for i in range(n):
|
|
|
686
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.
|
|
687
691
|

|
|
688
692
|
|
|
689
|
-
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.
|
|
690
694
|
|
|
691
695
|
## Hash Set ##
|
|
692
696
|
```python
|
|
@@ -730,7 +734,7 @@ for i in range(n):
|
|
|
730
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.
|
|
731
735
|

|
|
732
736
|
|
|
733
|
-
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).
|
|
734
738
|
|
|
735
739
|
|
|
736
740
|
# Sorting Algorithms #
|
|
@@ -757,7 +761,7 @@ In this configuration example we show the decimal, binary and [two's complement
|
|
|
757
761
|
|
|
758
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:
|
|
759
763
|
|
|
760
|
-
- [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)
|
|
761
765
|
|
|
762
766
|

|
|
763
767
|
|
|
@@ -1245,13 +1249,72 @@ Arguably the visualization is then more clear when we show a List_View object as
|
|
|
1245
1249
|
|
|
1246
1250
|
```python
|
|
1247
1251
|
mg.config.type_to_node[List_View] = (lambda l: mg.Node_Linear(l,
|
|
1248
|
-
[v if l.begin <= i < l.end else mg.
|
|
1252
|
+
[v if l.begin <= i < l.end else mg.unquoted_str('') for i, v in enumerate(l.lst)]
|
|
1249
1253
|
if hasattr(l, 'end') else [])
|
|
1250
1254
|
)
|
|
1251
1255
|
```
|
|
1252
1256
|

|
|
1253
1257
|
|
|
1254
|
-
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
|
+

|
|
1255
1318
|
|
|
1256
1319
|
## Collapse Type ##
|
|
1257
1320
|
|
|
@@ -1384,7 +1447,7 @@ mg.show(locals())
|
|
|
1384
1447
|
```
|
|
1385
1448
|

|
|
1386
1449
|
|
|
1387
|
-
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).
|
|
1388
1451
|
|
|
1389
1452
|
## Pandas ##
|
|
1390
1453
|
For pandas types `Series` and `DataFrame`, use `mg.extend_pandas()`:
|
|
@@ -1405,7 +1468,7 @@ mg.show(locals())
|
|
|
1405
1468
|
```
|
|
1406
1469
|

|
|
1407
1470
|
|
|
1408
|
-
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).
|
|
1409
1472
|
|
|
1410
1473
|
## PyTorch ##
|
|
1411
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
|