2016-03-06 4 views
8

Mein Beispieldatensatz im CSV-Format sieht wie folgt aus.Erstellen von Netzwerkdiagrammen

Der ungerichtete Graph hat 90 Knoten mit den Zahlen {10,11,12 .... 99} , deren Kanten mit Gewichten wie folgt definiert sind.

[Beispieldaten]

node1 node2 weight 
23  89 34.9 (i.e. there is an edge between node 23 and 89 with weight 34.9) 
75  14 28.5 
so on.... 

Ich möchte diese Form im Netzwerk darzustellen. Was ist der effektive Weg, um es zu repräsentieren (zum Beispiel Gephi, Networkx, etc). Die Stärke der Kante sollte das Kantengewicht darstellen.

Antwort

4

hinzufügen Wenn Sie in Linux sind, und Datei sieht Ihre csv vorausgesetzt wie folgt aus (zum Beispiel):

23;89;3.49 
23;14;1.29 
75;14;2.85 
14;75;2.9 
75;23;0.9 
23;27;4.9 

Sie diese verwenden können Programm:

import os 

def build_G(csv_file): 

    #init graph dict 
    g={} 

    #here we open csv file 
    with open(csv_file,'r') as f: 
     cont=f.read() 

    #here we get field content 
    for line in cont.split('\n'): 
     if line != '': 

      fields=line.split(';') 

      #build origin node 
      if g.has_key(fields[0])==False: 
       g[fields[0]]={} 

      #build destination node   
      if g.has_key(fields[1])==False: 
       g[fields[1]]={} 

      #build edge origin>destination 
      if g[fields[0]].has_key(fields[1])==False: 
       g[fields[0]][fields[1]]=float(fields[2]) 

    return g 

def main(): 

    #filename 
    csv_file="mynode.csv" 

    #build graph 
    G=build_G(csv_file) 

    #G is now a python dict 
    #G={'27': {}, '75': {'14': 2.85, '23': 0.9}, '89': {}, '14': {'75': 2.9}, '23': {'27': 4.9, '89': 3.49, '14': 1.29}} 


    #write to file 
    f = open('dotgraph.txt','w') 
    f.writelines('digraph G {\nnode [width=.3,height=.3,shape=octagon,style=filled,color=skyblue];\noverlap="false";\nrankdir="LR";\n') 
    f.writelines 

    for i in G: 
     for j in G[i]: 
      #get weight 
      weight = G[i][j] 
      s= '  '+ i 
      s += ' -> ' + j + ' [dir=none,label="' + str(G[i][j]) + '",penwidth='+str(weight)+',color=black]' 
      if s!='  '+ i: 
       s+=';\n' 
       f.writelines(s) 

    f.writelines('}') 
    f.close() 

    #generate graph image from graph text file 
    os.system("dot -Tjpg -omyImage.jpg dotgraph.txt") 

main() 

Ich war zuvor auf der Suche nach einer effektiven Lösung t Ich habe ein komplexes Diagramm erstellt und dies ist die einfachste (ohne Python-Modulabhängigkeit) Methode, die ich gefunden habe. Hier

ist das Bildergebnis für einen ungerichteten Graphen (mit dir = keine):

enter image description here

+0

können Sie ' sudo apt-get inst alle graphviz' von Ihrem Terminal, wenn ** dot ** binary nicht auf Ihrem System vorhanden ist –

+0

@ Stefani Danke .. !! Mein Diagramm ist ungerichtet. Wie kann ich die Anweisungen entfernen? – user1659936

+0

@ user1659936 Gern geschehen, du musst ** dir = none ** während der Bauphase hinzufügen, also ersetze bitte die Zeile: 's + = '->' + j + '[label =' '+ str (G [i ] [j]) + '", penwidth =' + str (gewicht) + ', color = schwarz]'' durch 's + = '->' + j + '[dir = keine, label ="' + str (G [i] [j]) + '", penwidth =' + str (gewicht) + ', color = schwarz]'" um die Richtung zu entfernen –

6

networkx verwenden, können Sie Kanten mit Attributen

import networkx as nx 
G = nx.Graph() 
G.add_edge(23, 89, weight=34.9) 
G.add_edge(75, 14, weight=28.5) 
5

Wenn Sie eine große csv haben würde ich empfehlen die Verwendung von pandas für den I/O-Teil deine Aufgabe. networkx hat eine nützliche Methode zur Verbindung mit pandas namens from_pandas_dataframe. Angenommen, Ihre Daten in einer CSV im Format Sie oben angegeben, soll dieser Befehl für Sie arbeitet:

df = pd.read_csv('path/to/file.csv', columns=['node1', 'node2', 'weight']) 

Aber zur Demonstration werde ich 10 zufällige Kanten verwendet innerhalb Ihrer Anforderungen (Sie werden nicht müssen numpy importieren , ich verwende es nur für Erzeugung von Zufallszahlen):

import matplotlib as plt 
import networkx as nx 
import pandas as pd 

#Generate Random edges and weights 
import numpy as np 
np.random.seed(0) # for reproducibility 

w = np.random.rand(10) # weights 0-1 
node1 = np.random.randint(10,19, (10)) # I used 10-19 for demo 
node2 = np.random.randint(10,19, (10)) 
df = pd.DataFrame({'node1': node1, 'node2': node2, 'weight': w}, index=range(10)) 

Alles im vorhergehenden Satz sollte die gleiche wie Ihre pd.read_csv Befehl erzeugen. Resultierende in diesem Datenrahmen, df:

node1 node2 weight 
0 16 13 0.548814 
1 17 15 0.715189 
2 17 10 0.602763 
3 18 12 0.544883 
4 11 13 0.423655 
5 15 18 0.645894 
6 18 11 0.437587 
7 14 13 0.891773 
8 13 13 0.963663 
9 10 13 0.383442 

Verwenden from_pandas_dataframeMultiGraph zu initialisieren. Dies setzt voraus, dass Sie mehrere Kanten haben, die sich mit einem Knoten verbinden (nicht in OP angegeben). Um diese Methode zu verwenden, müssen Sie eine einfache Änderung in networkx Quellcode in der convert_matrix.py Datei vornehmen, implementiert here (es war ein einfacher Fehler).

positions = nx.spring_layout(MG) # saves the positions of the nodes on the visualization 
# pass positions and set hold=True 
nx.draw(MG, pos=positions, hold=True, with_labels=True, node_size=1000, font_size=16) 

Im Detail: positions ist ein Wörterbuch, in dem jeder Knoten ein Schlüssel ist, und der Wert eine Position auf dem Diagramm

MG = nx.from_pandas_dataframe(df, 
           'node1', 
           'node2', 
           edge_attr='weight', 
           create_using=nx.MultiGraph() 
          ) 

Dies erzeugt Ihr Multigraphen, können Sie es draw visualisieren nutzen.Ich werde beschreiben, warum wir positions unten speichern. Das generische Objekt draw zeichnet Ihre MultiGraph-Instanz MG mit den Knoten unter der angegebenen Nummer positions. Wie Sie jedoch sehen können, sind die Kanten alle gleich breit:
Unweighted

Aber Sie haben alles, was Sie brauchen, um die Gewichte hinzuzufügen. Holen Sie zuerst die Gewichte in eine Liste mit dem Namen weights. Iterieren (mit Listenverständnis) durch jede Kante mit edges, können wir die Gewichte extrahieren. Ich wählte von 5 zu multiplizieren, weil es die sauberste sah:

weights = [w[2]['weight']*5 for w in MG.edges(data=True)] 

Schließlich werden wir draw_networkx_edges verwenden, die nur die Kanten des Graphen zeichnet (keine Knoten). Da wir die positions der Knoten haben, und wir setzen hold=True, können wir gewichtete Kanten direkt über unserer vorherigen Visualisierung zeichnen.

nx.draw_networkx_edges(MG, pos=positions, width=weights) #width can be array of floats 

Weighted

Sie Knoten sehen (14, 13) hat die schwerste Linie und den größten Wert aus dem Datenrahmen df (neben dem (13,13)).

+0

bei nx.Multigraph() bekomme ich diesen Fehler: TypeError: nicht hashbarer Typ: 'dict' – swyx

+0

Es sollte funktionieren, wenn Sie die Änderung im Absatz direkt davor notieren Codeblock. [Ein weiterer Link zur SO-Frage] (http://stackoverflow.com/questions/35210724/networkx-multigraph-from-pandas-dataframe) & die [GH-Ausgabe] (https://github.com/networkx/networkx/ Ausgaben/1982). Es wird auch funktionieren, wenn Sie das Argument 'create_using' komplett entfernen, nur wenn Sie wissen, dass Ihr Graph ein' Graph' und kein 'MultiGraph' ist. – Kevin

0

Sie sollten die Zeile am Anfang der CSV-Datei bearbeiten, wie folgt:

Quelle Zielart Gewicht 23 89 ungerichteten 34,9 (dh es gibt eine Kante zwischen Knoten 23 und 89 mit dem Gewicht 34,9) 75 14 ungerichtete 28,5 so weiter ....

Danach können Sie die cSV-Datei in Gephi importieren können Sie die Grafik darzustellen, die die Dicke der Kanten für das Gewicht, zum Beispiel steht: enter image description here