-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add implementations for dictionaries
- Loading branch information
1 parent
fbbdeee
commit c23d8a1
Showing
10 changed files
with
312 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
digraph Dict { | ||
rankdir=LR | ||
subgraph cluster_Dict { | ||
node [color=white style=filled] | ||
label=Dictionary | ||
style=filled | ||
color=lightgrey | ||
key1 [label="key1: one"] | ||
key2 [label="key2: 2"] | ||
key3 [label="key3: three"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
digraph Dict { | ||
rankdir=LR | ||
subgraph cluster_Dict { | ||
node [color=white style=filled] | ||
label=Dictionary | ||
style=filled | ||
color=lightgrey | ||
key1 [label="key1: value1"] | ||
key2 [label=key2 color=lightblue2 shape=rectangle style=filled] | ||
nested_key1 [label="nested_key1: nested_value1"] | ||
key2 -> nested_key1 | ||
nested_key2 [label="nested_key2: nested_value2"] | ||
key2 -> nested_key2 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
digraph Dict { | ||
rankdir=LR | ||
subgraph cluster_Dict { | ||
node [color=white style=filled] | ||
label=Dictionary | ||
style=filled | ||
color=lightgrey | ||
apple [label="apple: red"] | ||
banana [label="banana: yellow"] | ||
goldfish [label="goldfish: gold"] | ||
kiwi [label="kiwi: green"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
digraph Dict { | ||
rankdir=LR | ||
subgraph cluster_Dict { | ||
node [color=white style=filled] | ||
label=Dictionary | ||
style=filled | ||
color=lightgrey | ||
apple [label="apple: red"] | ||
banana [label="banana: yellow"] | ||
kiwi [label="kiwi: green"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
digraph Dict { | ||
rankdir=LR | ||
subgraph cluster_Dict { | ||
node [color=white style=filled] | ||
label=Dictionary | ||
style=filled | ||
color=lightgrey | ||
1 [label="1: 1"] | ||
2 [label="2: 4"] | ||
3 [label="3: 9"] | ||
4 [label="4: 16"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
digraph Dict { | ||
rankdir=LR | ||
subgraph cluster_Dict { | ||
node [color=white style=filled] | ||
label=Dictionary | ||
style=filled | ||
color=lightgrey | ||
1 [label="1: 1"] | ||
2 [label="2: 4"] | ||
3 [label="3: 9"] | ||
4 [label="4: 16"] | ||
5 [label="5: 25" color=green style=filled] | ||
6 [label="6: 36" color=green style=filled] | ||
7 [label="7: 49" color=green style=filled] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
""" | ||
This module contains the functionality to visualize a dictionary | ||
data structure as it changes throughout a function. | ||
This involves the following classes: | ||
* `TrackedDict(dict)`: detects changes made to a given dictionary | ||
data structure and triggers creation of a new visualization for each change. | ||
* `Dict`: uses graphviz to construct a visualization of the dictionary using a table. | ||
""" | ||
|
||
from graphviz import Digraph | ||
import webbrowser | ||
|
||
class TrackedDict(dict): | ||
""" | ||
Tracks changes to a dictionary data structure and triggers creation of new visualization | ||
Args: | ||
dict: the dictionary data structure to track | ||
""" | ||
|
||
def update(self, iterable): | ||
""" | ||
Sets the value of a key-value pair and checks the keys of the dictionary | ||
Args: | ||
key (Any): key of the key-value pair to be set | ||
value (Any): value to be set for the specified key | ||
""" | ||
super().update(iterable) | ||
keys = list(iterable.keys()) | ||
Dict.create_viz(self, self, keys) | ||
|
||
|
||
def pop(self, key): | ||
""" | ||
Removes a key-value pair given the key. | ||
Args: | ||
key (Any): key of the key-value pair to be removed | ||
Raises: | ||
KeyError: If the element to be removed is not in the dictionary. | ||
""" | ||
super().pop(key) | ||
Dict.create_viz(self, self) | ||
|
||
|
||
class Dict: | ||
""" | ||
Create graphviz visualization for dictionary data structure | ||
""" | ||
|
||
filenum = 1 | ||
|
||
def see(self, func, data): | ||
""" | ||
Creates a visualization for the initial dictionary and starts tracking | ||
a given dictionary as it changes throughout a given function. | ||
Args: | ||
func (function): function that the dictionary is being altered through | ||
data (dict): dictionary to track | ||
""" | ||
Dict.create_viz(self, data) | ||
data = TrackedDict(data) | ||
if func is not None: | ||
func(data) | ||
|
||
|
||
def create_viz(self, data, keys={}): | ||
""" | ||
Creates and renders a visualization of the dictionary using graphviz | ||
Args: | ||
data (dict): dictionary that is being visualized | ||
key (iterable): optional list of keys of new key-value pairs | ||
""" | ||
|
||
di_graph = Digraph('Dict', filename=f'dict{Dict.filenum}.gv') | ||
Dict.filenum += 1 | ||
di_graph.attr(rankdir='LR') | ||
|
||
with di_graph.subgraph(name='cluster_Dict') as subgraph: | ||
subgraph.attr(label='Dictionary') | ||
subgraph.attr(style='filled') | ||
subgraph.attr(color='lightgrey') | ||
subgraph.node_attr.update(style='filled', color='white') | ||
|
||
# Create nodes for each key-value pair in the dictionary | ||
for k, v in data.items(): | ||
|
||
if isinstance(v, dict): # if value is a nested dictionary | ||
subgraph.node(str(k), label=str(k), shape='rectangle', style='filled', color='lightblue2') | ||
|
||
for nested_k, nested_v in v.items(): | ||
if nested_k in keys: | ||
subgraph.node(str(nested_k), label=f"{str(nested_k)}: {str(nested_v)}", style='filled', color='green') | ||
else: | ||
subgraph.node(str(nested_k), label=f"{str(nested_k)}: {str(nested_v)}") | ||
# Add an edge from parent node to child node | ||
subgraph.edge(str(k), str(nested_k)) | ||
|
||
else: # if value is not a nested dictionary | ||
|
||
if k in keys: | ||
subgraph.node(str(k), label=f"{str(k)}: {str(v)}", style='filled', color='green') | ||
else: | ||
subgraph.node(str(k), label=f"{str(k)}: {str(v)}") | ||
|
||
# Render the graph to a file | ||
di_graph.view() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
""" | ||
This file contains unit tests for | ||
visualizations involving dictionary data structures. | ||
""" | ||
|
||
from seealgo import Dict | ||
|
||
|
||
### UNIT TESTS | ||
|
||
def test_initdict(): | ||
""" | ||
Test the visualization of an unchanged dictionary. | ||
""" | ||
|
||
init_dict = {'key1': 'one', 'key2': 2, 'key3': 'three'} | ||
viz0 = Dict() | ||
viz0.see(None, init_dict) | ||
|
||
with open('dict1.gv', 'r', encoding='utf-8') as file: | ||
viz_contents = file.read() | ||
|
||
with open('../../outputFiles/initDictOutput.txt', 'r', encoding='utf-8') as true_file: | ||
true_contents = true_file.read() | ||
|
||
assert viz_contents == true_contents | ||
|
||
|
||
def test_nesteddict(): | ||
""" | ||
Test the visualization of a nested dictionary. | ||
""" | ||
|
||
nested_dict = { | ||
'key1': 'value1', | ||
'key2': { | ||
'nested_key1': 'nested_value1', | ||
'nested_key2': 'nested_value2' | ||
} | ||
} | ||
vizN = Dict() | ||
vizN.see(None, nested_dict) | ||
|
||
with open('dict2.gv', 'r', encoding='utf-8') as file: | ||
viz_contents = file.read() | ||
|
||
with open('../../outputFiles/nestedDictOutput.txt', 'r', encoding='utf-8') as true_file: | ||
true_contents = true_file.read() | ||
|
||
assert viz_contents == true_contents | ||
|
||
|
||
def test_updatedict(): | ||
""" | ||
Test the visualization of adding | ||
a key:value pair to a dictionary. | ||
""" | ||
|
||
dict1 = {'1': 1, '2': 4, '3': 9, '4':16} | ||
dict_new = {'5': 25, '6': 36, '7': 49} | ||
viz1 = Dict() | ||
|
||
def update_func(user_dict): | ||
user_dict.update(dict_new) | ||
return user_dict | ||
|
||
viz1.see(update_func, dict1) | ||
|
||
with open('dict3.gv', 'r', encoding='utf-8') as file: | ||
viz_contents1 = file.read() | ||
with open('dict4.gv', 'r', encoding='utf-8') as file: | ||
viz_contents2 = file.read() | ||
|
||
with open('../../outputFiles/updateDictOutput1.txt', 'r', encoding='utf-8') as true_file: | ||
true_contents1 = true_file.read() | ||
with open('../../outputFiles/updateDictOutput2.txt', 'r', encoding='utf-8') as true_file: | ||
true_contents2 = true_file.read() | ||
|
||
assert viz_contents1 == true_contents1 | ||
assert viz_contents2 == true_contents2 | ||
|
||
|
||
def test_popfromdict(): | ||
""" | ||
Test the visualization of removing | ||
a value from a dictionary. | ||
""" | ||
|
||
dict2 = {'apple': 'red', 'banana': 'yellow', 'goldfish': 'gold', 'kiwi': 'green'} | ||
viz2 = Dict() | ||
|
||
def pop_func(user_dict): | ||
user_dict.pop('goldfish') | ||
return user_dict | ||
|
||
viz2.see(pop_func, dict2) | ||
|
||
with open('dict5.gv', 'r', encoding='utf-8') as file: | ||
viz_contents1 = file.read() | ||
with open('dict6.gv', 'r', encoding='utf-8') as file: | ||
viz_contents2 = file.read() | ||
|
||
with open('../../outputFiles/popDictOutput1.txt', 'r', encoding='utf-8') as true_file: | ||
true_contents1 = true_file.read() | ||
with open('../../outputFiles/popDictOutput2.txt', 'r', encoding='utf-8') as true_file: | ||
true_contents2 = true_file.read() | ||
|
||
assert viz_contents1 == true_contents1 | ||
assert viz_contents2 == true_contents2 |