From ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Zrounba?= <6691770+clement-z@users.noreply.github.com> Date: Sat, 30 Sep 2023 23:06:01 +0200 Subject: Initial release --- pyspecs/draw_graph_from_json.py | 145 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 pyspecs/draw_graph_from_json.py (limited to 'pyspecs/draw_graph_from_json.py') diff --git a/pyspecs/draw_graph_from_json.py b/pyspecs/draw_graph_from_json.py new file mode 100644 index 0000000..78a3c64 --- /dev/null +++ b/pyspecs/draw_graph_from_json.py @@ -0,0 +1,145 @@ +import sys +import json +import html +import graphviz + +def shorten(s, length=8): + if type(s) == list: + return "[...]" + s = str(s) + if len(s) > length: + return s[:length-3] + else: + return s + +def edge_label(name, net): + bgcolors = { + "default": "white", + "OANALOG": "turquoise", + "EANALOG": "orange", + } + try: + bgcolor = bgcolors[net["type"]] + except: + bgcolor = bgcolors["default"] + + short_name = name + if short_name.startswith('ROOT/'): + short_name = short_name[5:] + + attributes = [f''] + attributes.append(f'') + + attributes.append(f'
{html.escape(short_name)}
') + # attributes.append(f'') + + attributes.append('
') + attributes.append(f'') + attributes.append(f'') + attributes.append(f'') + attributes.append(f'') + attributes.append(f'') + attributes.append(f'
Type{net["type"]}
Bidirectional{"true" if net["bidirectional"] else "false"}
Size{net["size"]}
Readers{net["readers"]}
Writers{net["writers"]}
') + return f'"{name}" [label=<{"".join(attributes)}> shape=none fillcolor="{bgcolor}" margin="0.05"]' + + + +def node_label(element): + attributes = [''] + + short_name = element["name"] + if short_name.startswith('ROOT/'): + short_name = short_name[5:] + # Header + attributes.append(f'') + + # Nets + attributes.append(f'') + + # Args + attributes.append(f'') + + # Kwargs + attributes.append(f'') + + attributes.append('
{html.escape(short_name)}
') + if 'nets' in element and element['nets']: + nets = ''.join(f'' for i,net in enumerate(element['nets'])) + attributes.append(f'{nets}') + else: + attributes.append('') + attributes.append(f'
{str(i)}
') + if 'args' in element and element['args']: + args = ''.join(f'' for v in element['args']) + attributes.append(f'{args}') + else: + attributes.append('') + attributes.append(f'
{html.escape(shorten(v["value"]))}
') + if 'kwargs' in element and element['kwargs']: + kwargs = ''.join(f'' for k, v in element['kwargs'].items()) + attributes.append(f'{kwargs}') + else: + attributes.append('') + attributes.append(f'
{html.escape(k)}{html.escape(shorten(v["value"]))}
') + return f'"{element["name"]}" [label=<{"".join(attributes)}> shape=none margin="0"]' + +def edge(element): + if 'nets' in element: + for i,net in enumerate(element['nets']): + # yield f'"{element["name"]}":"{str(i)}" -- "{net}":"head"' + yield f'"{element["name"]}":"{str(i)}" -> "{net}":"middle"[ arrowhead = none ]' + +def generate_graph(description): + result = [] + result.append('digraph G {') + # result.append(' fontname="Helvetica,Arial,sans-serif"') + # result.append(' node [fontname="Helvetica,Arial,sans-serif"]') + # result.append(' edge [fontname="Helvetica,Arial,sans-serif"]') + result.append(' fontname="Cascadia,Courrier,mono"') + result.append(' node [fontname="Cascadia,Courrier,mono"]') + result.append(' edge [fontname="Cascadia,Courrier,mono"]') + result.append(' layout="sfdp"') + result.append(' overlap=false') + result.append(' splines=curved') + + for name, net in description["nets"].items(): + result.append(' ' + edge_label(name, net)) + + for element in description["elements"]: + result.append(' ' + node_label(element)) + result.extend(' ' + e for e in edge(element)) + + result.append('}') + return '\n'.join(result) + +def draw_graph(json_file, out_file): + with open(json_file) as f: + description = json.load(f) + + dot_src = generate_graph(description) + # print(dot_src) + graph = graphviz.Source(dot_src) + graph.render(outfile=out_file) + print(f'Results written to {out_file}') + +def main(): + try: + json_file = sys.argv[1] + except IndexError: + print('First and only argument should be a JSON description of the circuit') + try: + out_file = sys.argv[2] + except IndexError: + out_file = json_file + ".png" + + with open(json_file) as f: + description = json.load(f) + + dot_src = generate_graph(description) + # print(dot_src) + graph = graphviz.Source(dot_src) + graph.render(outfile=out_file) + print(f'Results written to {out_file}') + +if __name__ == '__main__': + main() -- cgit v1.2.3