2016-03-06 21 views
8

Mój przykładowy zestaw danych w formacie CSV wygląda następująco.Tworzenie wykresów sieciowych

Nieprzekształcony wykres zawiera 90 węzłów reprezentowanych liczbami {10,11,12 ... 99} , których krawędzie z wagami są zdefiniowane następująco.

[próbka danych]

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

ja jak do reprezentowania w postaci sieci. Jaki jest skuteczny sposób reprezentowania go (na przykład Gephi, networkx itp.). Grubość krawędzi powinna reprezentować grubość krawędzi.

Odpowiedz

4

Jeśli jesteś w Linuksie, a zakładając pliku CSV wygląda następująco (na przykład):

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

Można to wykorzystać program:

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

Dawniej szukałem skutecznego rozwiązania t o zbudowałeś złożony wykres i jest to najłatwiejsza metoda (bez zależności modułu Pythona), którą znalazłem.

Oto wynik wizerunek undirected wykresu (używając dir = brak):

enter image description here

+0

można użyć ' sudo apt-get inst wszystkie graphviz' z twojego terminala, jeśli ** dot ** binary nie istnieje w twoim systemie –

+0

@ Stefani Dzięki .. !! Mój wykres jest nie przekierowany, Jak mogę usunąć trasę. – user1659936

+0

@ user1659936 Serdecznie zapraszamy, musisz dodać ** dir = none ** podczas budowy, więc proszę zastąpić linię: 's + = '->' + j + '[etykieta ="' + str (G [i ] [j]) + '", penwidth =' + str (waga) + ', kolor = czarny]'' od 's + = '->' + j + '[dir = none, label ="' + str (G [i] [j]) + '", penwidth =' + str (waga) + ', kolor = czarny]'' aby usunąć kierunek –

6

Korzystanie networkx można dodać krawędzie z atrybutami

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

Jeśli masz dużą csv polecam korzystania pandas dla części I/O Twoje zadanie. networkx ma przydatną metodę do interfejsu z pandas o nazwie from_pandas_dataframe. Zakładając, że dane są w formacie csv w ty podanej powyżej, to polecenie powinno pracować dla Ciebie:

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

Ale do demonstracji użyję 10 losowych krawędzie wewnątrz wymagań (nie trzeba będzie importować numpy ja tylko go używać do generowania liczb losowych):

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

Wszystko w poprzednim bloku powinien wygenerować takie same jak polecenia pd.read_csv. Otrzymany w ten 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 

Zastosowanie from_pandas_dataframe zainicjować MultiGraph. Zakłada to, że będziesz mieć wiele krawędzi łączących się z jednym węzłem (nieokreślonym w OP). Aby użyć tej metody, będziesz musiał dokonać łatwej zmiany w kodzie źródłowym networkx w pliku convert_matrix.py, zaimplementowanym here (był to prosty błąd).

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

To generuje swój multigraf można wizualizować to wykorzystując 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) 

W szczegółach: positions jest słownikiem, gdzie każdy węzeł jest kluczem, a wartość jest pozycja na wykresie.Opiszę, dlaczego poniżej przechowujemy positions. Generic draw narysuje instancję MultiGraph MG z węzłami o podanej positions. Jednak, jak widać, krawędzie mają taką samą szerokość:
Unweighted

Ale masz wszystko, czego potrzebujesz, aby dodać ciężary. Najpierw sprawdź wagę na liście o nazwie weights. Iterowanie (ze zrozumieniem listy) przez każdą krawędź z edges, możemy wyodrębnić wagi. Wybrałem pomnożyć przez 5 bo wyglądało to najczystsze:

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

koniec użyjemy draw_networkx_edges, która tylko rysuje krawędzie grafu (bez węzłów). Ponieważ mamy węzły z positions i ustawiamy hold=True, możemy rysować ważone krawędzie tuż nad naszą poprzednią wizualizacją.

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

Weighted

Można zobaczyć węzeł (14, 13) ma najcięższe linię i największą wartość z DataFrame df (oprócz (13,13)).

+0

w nx.Multigraph() Otrzymuję ten błąd: TypeError: Unhashable Typ: 'Dict' – swyx

+0

Powinien działać, jeśli wprowadzisz zmiany odnotowane w akapicie tuż przed tym blok kodu. [Kolejny link do pytania SO] (http://stackoverflow.com/questions/35210724/networkx-multigraph-from-pandas-dataframe) i [GH Issue] (https://github.com/networkx/networkx/ issues/1982). Poza tym zadziała, jeśli całkowicie usuniesz argument "create_using", tylko jeśli wiesz, że twój wykres to 'Graph', a nie' MultiGraph'. – Kevin

0

Należy zmodyfikować linię na początku pliku csv następująco:

źródłowy typ docelowy ciężar 23 89 nieukierunkowane 34,9 (czyli istnieje krawędź pomiędzy węzłem 23 i 89 o masie 34,9) 75 14 nieukierunkowane 28,5 tak dalej ....

Po tym można zaimportować plik csv do Gephi do reprezentowania wykresu którym stoi grubość krawędzi do masy, na przykład: enter image description here

Powiązane problemy