import requests import sys import subprocess import ops_cache import copy import tempfile # TODO: Cache results # TODO: Properly render outgouing links # @ops_cache() def gen(headline_id, graph): reference_node = headline_id g = copy.deepcopy(graph) centered_graph = { reference_node: g[reference_node] } del g[reference_node] new_nodes = True in_emacs_tree = { reference_node: set(), } while new_nodes: new_nodes = False removed = set() for k, v in g.items(): for link in v["links"]: if link["target"].startswith("id:"): link["target"] = link["target"][3:] if link['target'] in centered_graph and link.get('relation') == 'in': centered_graph[k] = v for l in v["links"]: if l.get('relation') == 'in': t = l['target'] if t.startswith("id:"): t = t[3:] if '[' in t: # Special case, to be handled on org_rw continue if t not in in_emacs_tree: in_emacs_tree[t] = set() in_emacs_tree[t].add(k) v['links'] = [ l for l in v["links"] if l.get('relation') != 'in' ] removed.add(k) new_nodes = True break for k in removed: del g[k] in_emacs = set(centered_graph.keys()) # One more round for the rest, not requiring "in" for k, v in g.items(): for link in v["links"]: if link["target"].startswith("id:"): link["target"] = link["target"][3:] if link['target'] in in_emacs: centered_graph[k] = v removed.add(k) g = centered_graph with tempfile.NamedTemporaryFile(suffix='.dot', mode='wt') as f: f.write('digraph {\n') f.write('maxiter=1000\n') f.write('splines=curved\n') # f.write('splines=spline\n') # Not supported with edges to cluster f.write('node[shape=rect]\n') def draw_subgraph(node_id): f.write("subgraph cluster_{} {{\n".format(node_id.replace("-", "_"))) f.write('URL="./{}.node.html"\n'.format(node_id)) f.write("label=\"{}\"\n".format(g[node_id]['title'].replace("\"", "'"))) f.write("\n") # print("T: {}".format(in_emacs_tree), file=sys.stderr) for k in in_emacs_tree[node_id]: v = g[k] print("_" + k.replace("-", "_") + "[label=\"" + v["title"].replace("\"", "'") + "\", URL=\"" + k + ".node.html\"];", file=f) if k in in_emacs_tree: draw_subgraph(k) f.write("\n}") draw_subgraph(reference_node) for k, v in g.items(): if k not in in_emacs: print("_" + k.replace("-", "_") + "[label=\"" + v["title"].replace("\"", "'") + "\", URL=\"" + k + ".node.html\"];", file=f) for k, v in g.items(): for link in v["links"]: if link["target"].startswith("id:"): link["target"] = link["target"][3:] if '[' in link['target']: # Special case, to be handled on org_rw continue if link['target'] not in g: # Irrelevant continue if link['target'] in in_emacs_tree: t = 'cluster_{}'.format(link['target'].replace("-", "_")) else: t = "_" + link["target"].replace("-", "_") print("_" + k.replace("-", "_") + "->" + t, file=f) f.write('}\n') f.close() with tempfile.NamedTemporaryFile(suffix='.svg') as fsvg: subprocess.call("fdp graph.dot -Tsvg -o '{}'".format(fsvg.name), shell=True) fsvg.seek(0) return fsvg.read().decode()