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()