puudot/code/graph.py
Lauri Koskenniemi 9328fe3388 Data update and layer planning in Graph
Added blocks in data and introduced layers in Graph.
Layers not in use yet and other plans added in comments.
2025-05-25 18:55:33 +03:00

116 lines
3.6 KiB
Python

import os
import uuid
HEADER = """
graph {
graph [splines=ortho, nodesep=1]
node [color=white]
edge [headport=n, tailport=s]
compound=true
"""
FOOTER = """
}
"""
# TODO:
# Add hidden nodes in each cluster above visible nodes connected by hidden edges and attach visible edges to them
# Solve layering of clusters
class Graph:
def __init__(self):
self.layers = {}
self.blocks = {}
self.nodes = []
self.links = {}
self.dot_file = ""
def __str__(self):
return self.dot_file
def get_id(self):
return "id" + str(uuid.uuid4().hex)
def process_blocks(self, data):
blocks = data.get('blocks', [])
for block in blocks:
block_id = self.get_id()
new_block = {
"label": block.get("label", ""),
#"layer": block.get("layer", 0),
"texts": []
}
#layer = block.get("layer", 0)
#if layer not in self.layers:
# self.layers[layer] = []
for text in block.get("texts", []):
node_id = self.get_id()
self.nodes.append({"id": node_id, "text": text.get("text", "")})
new_block["texts"].append(node_id)
#self.layers[layer].append(node_id)
links = text.get("links", {})
if links != {}:
from_links = links.get("from", [])
to_links = links.get("to", [])
for from_link in from_links:
self.links[from_link] = {"from": node_id, "to": "", "head": ""}
for to_link in to_links:
if to_link in self.links:
self.links[to_link]["to"] = node_id
self.links[to_link]["head"] = block_id
self.blocks[block_id] = new_block
def build_dot(self):
self.dot_file = HEADER
for node in self.nodes:
self.dot_file += f"{node['id']} [label=\"{node['text']}\"]\n"
self.dot_file += "\n"
for block_id, block in self.blocks.items():
self.dot_file += f"subgraph cluster_{block_id} {{\n"
self.dot_file += f"label=\"{block['label']}\"\n"
self.dot_file += f"labeljust=l\n"
for node in block["texts"]:
self.dot_file += f"{node}\n"
self.dot_file += "}\n\n"
#for layer in self.layers.keys():
# self.dot_file += f"layer{layer} [style=invis]\n"
#ranking = " -- ".join([f"layer{layer}" for layer in self.layers.keys()])
#self.dot_file += f"{ranking} [style=invis]\n"
for link in self.links:
if self.links[link]["to"] != "":
self.dot_file += f"{self.links[link]['from']} -- {self.links[link]['to']}"
if self.links[link]["head"] != "":
self.dot_file += f" [lhead=cluster_{self.links[link]['head']}]"
self.dot_file += "\n"
#for layer, nodes in self.layers.items():
# self.dot_file += "{rank=same; "
# self.dot_file += "layer{layer}; "
# for node in nodes:
# self.dot_file += f"{node}; "
# self.dot_file += "}\n"
self.dot_file += FOOTER
def make_dot(self, format="svg", dot_file="dot.gv", svg_file="graph.svg"):
if self.dot_file != "":
with open(dot_file, "w") as f:
f.write(self.dot_file)
if format == "svg":
os.system(f"dot -T{format} {dot_file} -o {svg_file}")