Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a circular tree with multiple root trees

Using the C converted to python Radial Positions algorithm from this question, I have been successful in creating a radial graph based on a root node, all the way to the last child of each node. Now I have a new problem where I have multiple root nodes and will need them to be centered around the first root found, or at least a center point.

The closest example I've found is this graph:

enter image description here

So far all I could think of was for each root node found, multiply it by it's index and add the x position with a y radius. So far it hasn't worked out too well as I the children nodes do not follow it. I've been stumped on this for a few days now.

def RadialPositions(node, id):

    children_in_node = len(timelinedatta.neighbors(id, mode="out"))

    def rotate_node(x, y, nangle):
        nx = x * math.cos(nangle) - y * math.sin(nangle)
        ny = x * math.sin(nangle) + y * math.cos(nangle)
        return nx, ny

    def get_depth(id):
        count = 0
        for v in timelinedatta.bfsiter(id, mode="in", advanced=True):
            count = count + 1
        return count - 1

    if len(timelinedatta.neighbors(id, mode="out")) > 0 and len(timelinedatta.neighbors(id, mode="in")) == 0:
        node["positions"] = (0, 0)

    node["depth"] = get_depth(id)
    
    node_children_list = []

    for child in timelinedatta.neighbors(id, mode="out"):
        node_children_list.append((child, timelinedatta.vs[child]))

    for idx, (child_node_id, child_node) in enumerate(node_children_list, start=0):


        centerAdjust = 0

        if timelinedatta.neighbors(id, mode="in"):
            centerAdjust = (-node["angleRange"] + node["angleRange"] / children_in_node) / 2

        child_node["depth"] = get_depth(child_node_id)
        child_depth = child_node["depth"]



        child_node["nodeAngle"] = node["nodeAngle"] + node["angleRange"] / children_in_node * idx + centerAdjust
        child_node["angleRange"] = node["angleRange"] / children_in_node

        nx = rotate_node(40 * child_depth, 0, child_node["nodeAngle"])[0]
        ny = rotate_node(40 * child_depth, 0, child_node["nodeAngle"])[1]
        
        child_node["positions"] = [2 * nx, 2 * ny]


        RadialPositions(child_node, child_node_id)

I have an example of my graph here on pastebin as well

like image 997
Khailz Avatar asked Jul 16 '20 20:07

Khailz


1 Answers

You can use graphviz (as suggested by @thoku) with the neato layout engine (man neato):

neato draws undirected graphs using a spring model and reducing the related energy (see Kamada and Kawai, Information Processing Letters 31:1, April 1989).

For instance, the example

from graphviz import Digraph

tree = Digraph(engine='neato')

tree.node('root1',"R1")
tree.node('root2',"R2")
tree.node('root3',"R3")
tree.node('root4',"R4")
tree.edge('root1','root2')
tree.edge('root1','root3')
tree.edge('root3','root4')

tree.node('child11',"C11")
tree.node('child12',"C12")
tree.node('child13',"C13")
tree.edge('root1','child11')
tree.edge('root1','child12')
tree.edge('root1','child13')

tree.node('child21',"C21")
tree.node('child22',"C22")
tree.edge('root2','child21')
tree.edge('root2','child22')

tree.node('child31',"C31")
tree.node('child32',"C32")
tree.edge('root3','child31')
tree.edge('root3','child32')

tree.node('child41',"C41")
tree.node('child42',"C42")
tree.node('child43',"C43")
tree.edge('root4','child41')
tree.edge('root4','child42')
tree.edge('root4','child43')

tree.render("tree")

generates the following output:

tree

like image 98
Gorka Avatar answered Sep 29 '22 10:09

Gorka