Samstag, Januar 18, 2020

Kann man hierarchische Graphen von networkx in python 3?

Ich versuche, display-ein Baum-graph meiner Klassen-Hierarchie mithilfe networkx. ich das alles grafisch dargestellt wird, richtig, und es zeigt feine. Aber als einen kreisförmigen Graphen mit kreuzenden Kanten, es ist eine Reine Hierarchie, und es scheint, ich sollte in der Lage sein, um es anzuzeigen als ein Baum.

Habe ich gegoogelt, diese umfassend, und jede angebotene Lösung umfasst die Verwendung pygraphviz… aber PyGraphviz funktioniert nicht mit Python 3 (Dokumentation aus der pygraphviz Website).

Hat sich schon jemand in der Lage, eine Baum-Diagramm-Anzeige in Python 3?

  • Mit networkx Sie sollten in der Lage sein zu verwenden DIGraph mit dem dot-layout. Sollte diese Anzeige einen Baum, graph.
  • Die Entwickler-version von pygraphviz funktioniert mit Python 3.
  • Sie könnten versuchen, mit dem spring-layout, networkx.spring_layout()
  • Ich habe versucht, spring-layout-was zeigt ist immer noch kreisförmig, mit überlappenden Kanten.
  • Ich habe eine Antwort, aber es wird nicht besonders schön Aussehen, wenn der Baum einige äste, die sehr „weit“. Ich denke, das ist, wo eine Menge der Aufwand, pygraphviz passiert. Lassen Sie mich wissen, wenn es für Sie arbeitet. Wenn nicht, lassen Sie mich wissen, was sieht schlecht über Sie und ich werde sehen, ob es eine einfache Lösung.
  • Vielen Dank Joel! Ich werde versuchen diese heute Abend.
  • fantastisch! Aber ich wirklich brauchen die Knoten verbreitet wird, und ich versuche, herauszufinden, wo ein eingreifen in den code zu bekommen: wenn nextx eingestellt ist?
  • Meine Etiketten sind Klasse Namen, und Sie landen auf der jeweils anderen mit diesem code. Ich möchte Ihnen etwa das doppelte der aktuellen Breite. Ich habe das Spiel mit dx und andere Werte, und bin eine Menge ärger bekommen, dass das passiert. Jede raten, ist willkommen.
  • Ich denke das Thema ist zu haben, mehr zu tun mit der änderung der tatsächlichen Breite / Seitenverhältnis der erzeugten Abbildung, eher die Breite, die ich habe. Verdoppelung width aber Plotten mit dem gleichen Seitenverhältnis wird am Ende die gleiche scheinbare Breite im Ergebnis der seit es wird nur eine Skala die horizontale Länge entsprechend. Ich denke, es ist irgendwo in rcparams, aber ich nicht oft fiddle, damit Ihr googeln ist so gut wie meine.
  • in der Tat, ich kann nur die Größe ändern Sie das Fenster und Holen Sie das meiste, was ich brauche. Nochmals vielen Dank für den code: das ist großartig!
  • Wenn Sie „akzeptieren“ der Antwort würde ich schätzen es. Auch Aric sagt, es pygraphviz scheint zu funktionieren in python 3. Aric sagt, dass der code in seiner Antwort, here funktioniert in python 3. Ich tun, python 2.7, also weiß nicht.
  • Ich habe versucht, den code von Aric Antwort, und es blies mich irgendwo in Pygraphviz.

InformationsquelleAutor NickDanger66 | 2015-04-12

5 Kommentare

  1. 31

    Bearbeiten (19 Jan 2019) habe ich aktualisiert, der code robuster: Er arbeitet nun für gerichtete und ungerichtete Graphen ohne jegliche änderung, die nicht mehr erfordert, dass der Benutzer geben Sie das root, und es testet, dass der graph ein Baum, bevor er ausgeführt wird (ohne den test hätte es eine unendliche Rekursion – siehe user2479115 Antwort für eine Art und Weise zu behandeln, die nicht mit Bäumen).

    Bearbeiten (27 Aug 2018) Wenn Sie möchten, erstellen Sie einen plot mit den Knoten erscheinen als Ringe um den root-Knoten, den code rechts unten zeigt eine einfache Modifikation, dies zu tun

    Bearbeiten (17 Sept 2017) ich glaube, die Mühe mit pygraphviz, dass OP hatte, sollte jetzt repariert sein. So pygraphviz ist wahrscheinlich eine bessere Lösung, was ich habe, unter.


    Hier ist ein einfaches Rekursives Programm zum definieren der Positionen. Die Rekursion geschieht in _hierarchy_pos, das von hierarchy_pos. Die Hauptaufgabe der hierarcy_pos ist noch ein bisschen testen, um sicherzustellen, dass die Grafik angemessen ist, bevor Sie in die Rekursion:

    import networkx as nx
    import random
    
    
    def hierarchy_pos(G, root=None, width=1., vert_gap = 0.2, vert_loc = 0, xcenter = 0.5):
    
        '''
        From Joel's answer at https://stackoverflow.com/a/29597209/2966723.  
        Licensed under Creative Commons Attribution-Share Alike 
    
        If the graph is a tree this will return the positions to plot this in a 
        hierarchical layout.
    
        G: the graph (must be a tree)
    
        root: the root node of current branch 
        - if the tree is directed and this is not given, 
          the root will be found and used
        - if the tree is directed and this is given, then 
          the positions will be just for the descendants of this node.
        - if the tree is undirected and not given, 
          then a random choice will be used.
    
        width: horizontal space allocated for this branch - avoids overlap with other branches
    
        vert_gap: gap between levels of hierarchy
    
        vert_loc: vertical location of root
    
        xcenter: horizontal location of root
        '''
        if not nx.is_tree(G):
            raise TypeError('cannot use hierarchy_pos on a graph that is not a tree')
    
        if root is None:
            if isinstance(G, nx.DiGraph):
                root = next(iter(nx.topological_sort(G)))  #allows back compatibility with nx version 1.11
            else:
                root = random.choice(list(G.nodes))
    
        def _hierarchy_pos(G, root, width=1., vert_gap = 0.2, vert_loc = 0, xcenter = 0.5, pos = None, parent = None):
            '''
            see hierarchy_pos docstring for most arguments
    
            pos: a dict saying where all nodes go if they have been assigned
            parent: parent of this branch. - only affects it if non-directed
    
            '''
    
            if pos is None:
                pos = {root:(xcenter,vert_loc)}
            else:
                pos[root] = (xcenter, vert_loc)
            children = list(G.neighbors(root))
            if not isinstance(G, nx.DiGraph) and parent is not None:
                children.remove(parent)  
            if len(children)!=0:
                dx = width/len(children) 
                nextx = xcenter - width/2 - dx/2
                for child in children:
                    nextx += dx
                    pos = _hierarchy_pos(G,child, width = dx, vert_gap = vert_gap, 
                                        vert_loc = vert_loc-vert_gap, xcenter=nextx,
                                        pos=pos, parent = root)
            return pos
    
    
        return _hierarchy_pos(G, root, width, vert_gap, vert_loc, xcenter)

    und ein Beispiel für die Verwendung:

    import matplotlib.pyplot as plt
    import networkx as nx
    G=nx.Graph()
    G.add_edges_from([(1,2), (1,3), (1,4), (2,5), (2,6), (2,7), (3,8), (3,9), (4,10),
                      (5,11), (5,12), (6,13)])
    pos = hierarchy_pos(G,1)    
    nx.draw(G, pos=pos, with_labels=True)
    plt.savefig('hierarchy.png')

    Kann man hierarchische Graphen von networkx in python 3?

    Idealerweise sollte dies ändern der Skalierung der horizontalen Trennung, basierend auf, wie weit die Dinge unter ihm. Ich bin nicht versuchen, das jetzt.

    Radiale expansion

    Lassen Sie uns sagen, Sie wollen das Grundstück so Aussehen:

    Kann man hierarchische Graphen von networkx in python 3?

    Hier ist der code dafür:

    pos = hierarchy_pos(G, 0, width = 2*math.pi, xcenter=0)
    new_pos = {u:(r*math.cos(theta),r*math.sin(theta)) for u, (theta, r) in pos.items()}
    nx.draw(G, pos=new_pos, node_size = 50)
    nx.draw_networkx_nodes(G, pos=new_pos, nodelist = [0], node_color = 'blue', node_size = 200)

    Bearbeiten – Dank Deepak Saini für die Feststellung, dass ein Fehler treten in gerichteten Graphen

    • Genau das, was ich gesucht habe! Awesome dude!
    • Muss neighbors = list(G.neighbors(root)) für python 3.
    • Können Sie überprüfen, ob neighbors = G.neighbors(root) und dann später if neighbors: eher als if len(neighbors)!=0: funktioniert?
    • Was, wenn es ein loop -, können wir zeigen, indem Sie obigen Grafik? Beispiel: Für diese Daten [(1,2), (1,3), (1,4), (2,5), (2,6), (2,7), (3,8), (3,9), (4,10),(5,11), (5,12), (6,13),(13,1)]
    • Der code ist ausgelegt für einen Baum. Was ich denke, Sie tun könnten, wenn es Zyklen haben eine Reihe von „Knoten finden“, die auch entfernt von neighbors. Sie müssen möglicherweise einige änderungen an der Positionierung, weil Sie würde haben der Kanten innerhalb einer Hierarchie-Ebene, die führen würde, um eine Reihe von überlappenden Kanten, so wäre es schwer zu sagen, welche Knoten tatsächlich angeschlossen sind.
  2. 10

    Hier ist eine Lösung für große Bäume. Es ist eine Abwandlung von Joel rekursive Ansatz, der gleichmäßig Räumen Knoten auf jeder Ebene.

    def hierarchy_pos(G, root, levels=None, width=1., height=1.):
        '''If there is a cycle that is reachable from root, then this will see infinite recursion.
           G: the graph
           root: the root node
           levels: a dictionary
                   key: level number (starting from 0)
                   value: number of nodes in this level
           width: horizontal space allocated for drawing
           height: vertical space allocated for drawing'''
        TOTAL = "total"
        CURRENT = "current"
        def make_levels(levels, node=root, currentLevel=0, parent=None):
            """Compute the number of nodes for each level
            """
            if not currentLevel in levels:
                levels[currentLevel] = {TOTAL : 0, CURRENT : 0}
            levels[currentLevel][TOTAL] += 1
            neighbors = G.neighbors(node)
            for neighbor in neighbors:
                if not neighbor == parent:
                    levels =  make_levels(levels, neighbor, currentLevel + 1, node)
            return levels
    
        def make_pos(pos, node=root, currentLevel=0, parent=None, vert_loc=0):
            dx = 1/levels[currentLevel][TOTAL]
            left = dx/2
            pos[node] = ((left + dx*levels[currentLevel][CURRENT])*width, vert_loc)
            levels[currentLevel][CURRENT] += 1
            neighbors = G.neighbors(node)
            for neighbor in neighbors:
                if not neighbor == parent:
                    pos = make_pos(pos, neighbor, currentLevel + 1, node, vert_loc-vert_gap)
            return pos
        if levels is None:
            levels = make_levels({})
        else:
            levels = {l:{TOTAL: levels[l], CURRENT:0} for l in levels}
        vert_gap = height / (max([l for l in levels])+1)
        return make_pos({})

    Joel ‚ s z.B. wie folgt Aussehen wird:
    Kann man hierarchische Graphen von networkx in python 3?

    – Und dies ist ein komplexer graph (gerendert mit plotly):Kann man hierarchische Graphen von networkx in python 3?

    • Dies scheint etwas zu sein, das sollte leicht sein out-of-the-box. Ich unterrichte CS, und ich würde lieben, verwenden Sie dieses Paket zu erstellen, b-Bäume, rot-schwarz-Bäume, etc…. Aber es ist ein wenig umständlich jetzt.
    • Beachten Sie, dass Sie zu ersetzen neighbors = G.neighbors(node) mit neighbors = list(G.neighbors(node)) dies funktioniert in Python 3.
    • Danke, ich habe aktualisiert, der code jetzt (das problem wurde durch eine alte version von networkx).
  3. 7

    Ich leicht modifiziert, so dass es nicht unendlich recurse.

    import networkx as nx
    
    def hierarchy_pos(G, root, width=1., vert_gap = 0.2, vert_loc = 0, xcenter = 0.5 ):
        '''If there is a cycle that is reachable from root, then result will not be a hierarchy.
    
           G: the graph
           root: the root node of current branch
           width: horizontal space allocated for this branch - avoids overlap with other branches
           vert_gap: gap between levels of hierarchy
           vert_loc: vertical location of root
           xcenter: horizontal location of root
        '''
    
        def h_recur(G, root, width=1., vert_gap = 0.2, vert_loc = 0, xcenter = 0.5, 
                      pos = None, parent = None, parsed = [] ):
            if(root not in parsed):
                parsed.append(root)
                if pos == None:
                    pos = {root:(xcenter,vert_loc)}
                else:
                    pos[root] = (xcenter, vert_loc)
                neighbors = G.neighbors(root)
                if parent != None:
                    neighbors.remove(parent)
                if len(neighbors)!=0:
                    dx = width/len(neighbors) 
                    nextx = xcenter - width/2 - dx/2
                    for neighbor in neighbors:
                        nextx += dx
                        pos = h_recur(G,neighbor, width = dx, vert_gap = vert_gap, 
                                            vert_loc = vert_loc-vert_gap, xcenter=nextx, pos=pos, 
                                            parent = root, parsed = parsed)
            return pos
    
        return h_recur(G, root, width=1., vert_gap = 0.2, vert_loc = 0, xcenter = 0.5)
  4. 5

    Der einfachste Weg, um eine gut aussehende Baum-Diagramm-Anzeige in Python 2 oder 3 ohne PyGraphviz ist die Verwendung PyDot (https://pypi.python.org/pypi/pydot). In der Erwägung, dass PyGraphviz bietet eine Schnittstelle, um das ganze von Graphviz, PyDot stellt nur eine Schnittstelle zur Graphviz Dot Werkzeug, das ist das einzige, das Sie brauchen, wenn das, was Sie suchen, ist ein hierarchischer graph /Baum. Wenn Sie möchten, erstellen Sie Ihr Diagramm in NetworkX eher als PyDot, können Sie mit NetworkX zu exportieren PyDot graph, wie in der folgenden:

    import networkx as nx
    
    g=nx.DiGraph()
    g.add_edges_from([(1,2), (1,3), (1,4), (2,5), (2,6), (2,7), (3,8), (3,9),
                      (4,10), (5,11), (5,12), (6,13)])
    p=nx.drawing.nx_pydot.to_pydot(g)
    p.write_png('example.png')

    Beachten Sie, dass Graphviz und PyDot installiert werden müssen für die oben genannten, um korrekt zu arbeiten.

    Kann man hierarchische Graphen von networkx in python 3?

    Achtung: ich habe Probleme bei der Verwendung von PyDot zeichnen von Graphen mit Knoten-Attribut exportierte Wörterbücher aus NetworkX – manchmal sind die Wörterbücher scheinen exportiert werden mit Anführungszeichen fehlen von Zeichenfolgen, die bewirkt, dass die write Methode zum Absturz zu bringen. Dies kann vermieden werden, durch weglassen der Wörterbücher.

  5. 2

    Für einen gerichteten Graphen, Da die Nachbarn(x) sind nur die succesors(x), so müssen Sie die Zeilen:

    if parent != None:
            neighbors.remove(parent)

    Auch eine bessere Möglichkeit wäre diese:

    pos=nx.graphviz_layout(G,prog='dot')

Kostenlose Online-Tests