new-codigoparallevar/scripts/gen_centered_graph.py

140 lines
4.6 KiB
Python

import subprocess
import ops_cache
import copy
import tempfile
import os
@ops_cache.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(),
}
linked_from_internal = 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'
]
for l in v['links']:
lt = l['target']
if lt.startswith("id:"):
lt = lt[3:]
linked_from_internal.add(lt)
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():
backlinked = False
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
backlinked = True
removed.add(k)
if not backlinked and (k in linked_from_internal):
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]
if k in in_emacs_tree:
draw_subgraph(k)
else:
print(" _" + k.replace("-", "_") + "[label=\"" + v["title"].replace("\"", "'") + "\", URL=\"" + k + ".node.html\"];", file=f)
f.write("\n}\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():
link_src = '_' + k.replace("-", "_")
if k in in_emacs_tree:
link_src = 'cluster_{}'.format(k.replace("-", "_"))
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(link_src + "->" + t, file=f)
f.write('}\n')
f.flush()
with tempfile.NamedTemporaryFile(suffix='.svg') as fsvg:
subprocess.call(['fdp', f.name, '-Tsvg', '-o', fsvg.name])
fsvg.seek(0)
return fsvg.read().decode()