2016-03-06 25 views
8

I miei dati di esempio impostati in formato CSV hanno il seguente aspetto.Creazione di grafici di rete

Il grafico non orientato ha 90 nodi rappresentati con numeri {10,11,12 .... 99} i cui bordi con pesi sono definiti come segue.

[dati di esempio]

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.... 

Vorrei rappresentare questo in forma di rete. Qual è il modo efficace per rappresentarlo (ad esempio Gephi, networkx, ecc.). Lo spessore del bordo dovrebbe rappresentare il peso del bordo.

risposta

4

Se siete in Linux, e supponendo che il file CSV si presenta così (per esempio):

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

è possibile utilizzare questo programma:

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() 

Cercavo in precedenza una soluzione efficace t o ha costruito un grafico complesso e questo è il metodo più semplice (senza alcuna dipendenza dal modulo Python) che ho trovato.

Ecco il risultato di immagini per un grafo non orientato (usando dir = nessuno):

enter image description here

+0

È possibile utilizzare ' sudo apt-get inst tutto graphviz' dal tuo terminale se ** punto ** binario non esiste sul tuo sistema –

+0

@ Stefani Grazie .. !! Il mio grafico non è orientato, Come posso rimuovere le indicazioni. – user1659936

+0

@ user1659936 Prego, è necessario aggiungere ** dir = none ** durante la costruzione, quindi si prega di sostituire la riga: 's + = '->' + j + '[label ="' + str (G [i ] [j]) + "", penwidth = '+ str (peso) +', color = black] ''di' s + =' -> '+ j +' [dir = none, label = "'+ str (G [i] [j]) + "", penwidth = '+ str (peso) +', color = black] ''per rimuovere la direzione –

6

Utilizzando networkx, è possibile aggiungere bordi con gli attributi

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

Se si dispone di un grande csv Mi consiglia di utilizzare pandas per la parte di I/O di il tuo compito. networkx ha un metodo utile per interfacciare con pandas chiamato from_pandas_dataframe. Supponendo che i vostri dati sono in un csv nel formato indicato in precedenza, questo comando dovrebbe funzionare per voi:

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

Ma per la dimostrazione userò 10 bordi casuali all'interno delle vostre esigenze (non sarà necessario importare numpy , sto solo usando per la generazione di numeri casuali):

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)) 

Tutto nel blocco precedente dovrebbe generare lo stesso come il vostro comando pd.read_csv. Con conseguente questo dataframe, 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 

Usa from_pandas_dataframe per inizializzare MultiGraph. Ciò presuppone che si avranno più edge che si connettono a un nodo (non specificato in OP). Per utilizzare questo metodo, è necessario apportare una modifica semplice nel codice sorgente networkx nel file convert_matrix.py, implementato here (si trattava di un bug semplice).

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

Questo genera la vostra multigrafo, è possibile visualizzarla utilizzando draw:

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) 

In dettaglio: positions è un dizionario in cui ogni nodo è una chiave e il valore è una posizione sul grafico.Descriverò perché memorizziamo positions di seguito. Il codice generico draw disegna l'istanza MultiGraph MG con i nodi allo positions specificato. Tuttavia, come puoi vedere i bordi sono tutti della stessa larghezza:
Unweighted

Ma tu hai tutto il necessario per aggiungere i pesi. Per prima cosa prendi i pesi in una lista chiamata weights. Iterando (con la comprensione delle liste) attraverso ogni spigolo con edges, possiamo estrarre i pesi. Ho scelto di moltiplicare per 5 perché sembrava il più pulito:

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

Infine useremo draw_networkx_edges, che attira solo i bordi del grafico (senza nodi). Dato che abbiamo il positions dei nodi e abbiamo impostato hold=True, possiamo disegnare bordi ponderati proprio sopra la nostra visualizzazione precedente.

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

Weighted

Si può vedere nodo (14, 13) ha la linea più pesante e il più grande valore dal dataframe df (oltre al (13,13)).

+0

in nx.Multigraph() mi viene visualizzato questo errore: TypeError: tipo non disattivabile: 'dict' – swyx

+0

Dovrebbe funzionare se si apporta la modifica annotata nel paragrafo subito prima blocco di codice. [Un altro link alla domanda SO] (http://stackoverflow.com/questions/35210724/networkx-multigraph-from-pandas-dataframe) e il [GH Issue] (https://github.com/networkx/networkx/ problemi/1982). Inoltre, funzionerà se rimuoverete completamente l'argomento 'create_using', solo se sapete che il vostro grafico è un' Graph' e non un 'MultiGraph'. – Kevin

0

Si dovrebbe modificare la linea all'inizio del file csv come segue:

fonte tipo di destinazione peso 23 89 non orientato 34,9 (cioè v'è un bordo tra il nodo 23 e 89 con peso 34,9) 75 14 non orientato 28,5 così via ....

Dopo di che è possibile importare il file CSV in Gephi per rappresentare il grafico, che lo spessore dei bordi si distingue per il peso, ad esempio: enter image description here