Wrap graph generation in python code, remove API dependency.
This commit is contained in:
parent
3f5ec66c3d
commit
135423b8e5
@ -1,125 +0,0 @@
|
|||||||
import requests
|
|
||||||
import sys
|
|
||||||
|
|
||||||
url = 'http://localhost:8000/notes/graph.json'
|
|
||||||
reference_node = sys.argv[1]
|
|
||||||
out = sys.argv[2]
|
|
||||||
|
|
||||||
g = requests.get(url).json()
|
|
||||||
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
|
|
||||||
|
|
||||||
f = open('graph.dot', 'wt')
|
|
||||||
f.write('digraph {\n')
|
|
||||||
# f.write('bgcolor="#222222"\n')
|
|
||||||
# f.write('fontcolor="#ffffff"\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')
|
|
||||||
# f.write('edge[color="#ffffff"]\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('color="#ffffff"\n')
|
|
||||||
|
|
||||||
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')
|
|
||||||
# dot graph.dot -Tsvg graph.svg
|
|
||||||
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
subprocess.call("fdp graph.dot -Tsvg -o '{}'".format(out), shell=True)
|
|
||||||
# return "graph.svg"
|
|
126
scripts/gen_centered_graph.py
Normal file
126
scripts/gen_centered_graph.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
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()
|
@ -25,6 +25,7 @@ from org_rw import token_list_to_raw
|
|||||||
import pygments
|
import pygments
|
||||||
import pygments.lexers
|
import pygments.lexers
|
||||||
import pygments.formatters
|
import pygments.formatters
|
||||||
|
import gen_centered_graph
|
||||||
|
|
||||||
# Set custom states
|
# Set custom states
|
||||||
for state in ("NEXT", "MEETING", "Q", "PAUSED", "SOMETIME", "TRACK", "WAITING"):
|
for state in ("NEXT", "MEETING", "Q", "PAUSED", "SOMETIME", "TRACK", "WAITING"):
|
||||||
@ -710,19 +711,9 @@ def render_connections(headline_id, content, graph):
|
|||||||
# if headline_id != 'aa29be89-70e7-4465-91ed-361cf0ce62f2':
|
# if headline_id != 'aa29be89-70e7-4465-91ed-361cf0ce62f2':
|
||||||
# return
|
# return
|
||||||
|
|
||||||
# TODO: Cache results
|
|
||||||
# TODO: Avoid querying graph API on script
|
|
||||||
# TODO: Properly render outgouing links
|
|
||||||
logging.info("Generating centered graph for {}".format(headline_id))
|
logging.info("Generating centered graph for {}".format(headline_id))
|
||||||
import subprocess
|
svg = gen_centered_graph.gen(headline_id, graph['nodes'])
|
||||||
this_dir = os.path.dirname(os.path.abspath(__file__))
|
content.append("<div class='connections'>{}</div>".format(svg))
|
||||||
os.makedirs('cache', exist_ok=True)
|
|
||||||
subprocess.check_call(['python3', os.path.join(this_dir, 'gen-centered-graph.py'), headline_id, 'cache/' + headline_id + '.svg'])
|
|
||||||
try:
|
|
||||||
with open('cache/' + headline_id + '.svg') as f:
|
|
||||||
content.append("<div class='connections'>{}</div>".format(f.read()))
|
|
||||||
except FileNotFoundError:
|
|
||||||
logging.exception('Graph file not produced on headline: "{}"'.format(headline_id))
|
|
||||||
|
|
||||||
def render(headline, doc, graph, headlineLevel):
|
def render(headline, doc, graph, headlineLevel):
|
||||||
try:
|
try:
|
||||||
|
0
scripts/ops_cache.py
Normal file
0
scripts/ops_cache.py
Normal file
Loading…
Reference in New Issue
Block a user