Research-Stack/5-Applications/scripts/generate_project_graph.py

132 lines
5 KiB
Python

import csv
import xml.etree.ElementTree as ET
import sys
def generate_graphs(tsv_path):
nodes = {}
edges = []
with open(tsv_path, 'r', encoding='utf-8') as f:
# Skip potential comment lines at start
lines = f.readlines()
start_idx = 0
for i, line in enumerate(lines):
if line.startswith('1\t') or line.startswith('#\t'):
start_idx = i
break
reader = csv.DictReader(lines[start_idx:], delimiter='\t')
# Normalize field names (sometimes they have # or leading/trailing space)
fieldnames = [fn.strip().replace('#', 'ID') for fn in reader.fieldnames]
for row in reader:
# Re-map row to clean keys
clean_row = {fn.strip().replace('#', 'ID'): v for fn, v in zip(reader.fieldnames, row.values())}
node_id = clean_row.get('ID')
if not node_id: continue
name = clean_row.get('Model_Name', f"Model_{node_id}")
family = clean_row.get('Family', 'Uncategorized')
domain = clean_row.get('Domain_Type', 'Default')
nodes[node_id] = {
'name': name,
'family': family,
'domain': domain,
'equation': clean_row.get('Equation', ''),
'status': clean_row.get('Status', '')
}
cross_refs = clean_row.get('Cross_Refs', '')
if cross_refs and cross_refs != '-':
refs = [r.strip() for r in cross_refs.split(',') if r.strip().isdigit()]
for ref in refs:
edges.append((node_id, ref))
# 1. Generate Mermaid
mermaid_content = "graph TD\n"
# Group by domain
domains = {}
for nid, data in nodes.items():
dom = data['domain']
if dom not in domains: domains[dom] = []
domains[dom].append(nid)
for dom, nids in domains.items():
if dom == 'Default': continue
mermaid_content += f" subgraph {dom.replace('_', ' ')}\n"
for nid in nids:
# Clean label for mermaid
label = nodes[nid]['name'].replace(' ', '_').replace('(', '').replace(')', '')
mermaid_content += f" N{nid}[{label}]\n"
mermaid_content += " end\n"
for src, dst in edges:
if src in nodes and dst in nodes:
mermaid_content += f" N{src} --> N{dst}\n"
with open('research_graph.mermaid', 'w') as f:
f.write(mermaid_content)
# 2. Generate GraphML
graphml = ET.Element('graphml', {
'xmlns': "http://graphml.graphdrawing.org/xmlns",
'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
'xsi:schemaLocation': "http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"
})
# Define keys
key_name = ET.SubElement(graphml, 'key', {'id': 'd0', 'for': 'node', 'attr.name': 'name', 'attr.type': 'string'})
key_family = ET.SubElement(graphml, 'key', {'id': 'd1', 'for': 'node', 'attr.name': 'family', 'attr.type': 'string'})
key_domain = ET.SubElement(graphml, 'key', {'id': 'd2', 'for': 'node', 'attr.name': 'domain', 'attr.type': 'string'})
graph = ET.SubElement(graphml, 'graph', {'id': 'G', 'edgedefault': 'directed'})
for nid, data in nodes.items():
node = ET.SubElement(graph, 'node', {'id': f"n{nid}"})
ET.SubElement(node, 'data', {'key': 'd0'}).text = data['name']
ET.SubElement(node, 'data', {'key': 'd1'}).text = data['family']
ET.SubElement(node, 'data', {'key': 'd2'}).text = data['domain']
for i, (src, dst) in enumerate(edges):
if src in nodes and dst in nodes:
ET.SubElement(graph, 'edge', {
'id': f"e{i}",
'source': f"n{src}",
'target': f"n{dst}"
})
tree = ET.ElementTree(graphml)
tree.write('research_graph.graphml', encoding='utf-8', xml_declaration=True)
# 3. Generate simplified Mermaid (Top nodes by degree)
# Count connections
degree = {nid: 0 for nid in nodes}
for src, dst in edges:
if src in degree: degree[src] += 1
if dst in degree: degree[dst] += 1
top_nodes = sorted(degree.items(), key=lambda x: x[1], reverse=True)[:50]
top_ids = [nid for nid, deg in top_nodes]
simp_mermaid = "graph TD\n"
for nid in top_ids:
label = nodes[nid]['name'].replace(' ', '_')
simp_mermaid += f" N{nid}[{label}]\n"
for src, dst in edges:
if src in top_ids and dst in top_ids:
simp_mermaid += f" N{src} --> N{dst}\n"
with open('research_graph_summary.mermaid', 'w') as f:
f.write(simp_mermaid)
print(f"✅ Generated graphs for {len(nodes)} nodes and {len(edges)} edges.")
if __name__ == "__main__":
import os
base_path = "/home/allaun/Documents/Research Stack"
tsv_path = os.path.join(base_path, "3-Mathematical-Models", "MATH_MODEL_MAP.tsv")
generate_graphs(tsv_path)