Pregunta Creando Gráficos de Red


Mi conjunto de datos de muestra en formato CSV se ve de la siguiente manera.

El gráfico no dirigido tiene 90 nodos representados con números {10,11,12 ... 99} cuyos bordes con pesos se definen de la siguiente manera.

[Data de muestra]

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

Me gustaría representar esto en forma de red. ¿Cuál es la forma efectiva de representarlo (por ejemplo, Gephi, networkx, etc.)? El grosor del borde debe representar el peso del borde.


8
2018-03-06 18:44


origen


Respuestas:


Si está en Linux y asume que su archivo csv se ve así (por ejemplo):

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

Puedes usar este programa:

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

Anteriormente estaba buscando una solución efectiva para el gráfico complejo construido y este es el método más simple (sin dependencia de módulos de Python) que encontré.

Aquí está el resultado de la imagen para un gráfico no dirigido (usando dir = ninguno)

enter image description here


4
2018-03-10 15:21



Utilizando networkx, puedes agregar bordes con atributos

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

6
2018-03-10 05:54



Si tienes una csv grande, te recomiendo usar pandas para la parte de E / S de su tarea. networkx tiene un método útil para interactuar con pandas llamado from_pandas_dataframe. Suponiendo que sus datos estén en una csv en el formato que indicó anteriormente, este comando debería funcionar para usted:

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

Pero para la demostración usaré 10 bordes aleatorios dentro de tus requisitos (no necesitarás importar numpy, Solo lo estoy usando para generación de números aleatorios):

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

Todo en el bloque anterior debería generar lo mismo que tu pd.read_csv mando. Como resultado en este 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

Utilizar from_pandas_dataframe inicializar MultiGraph. Esto supone que tendrá múltiples bordes que se conectan a un nodo (no especificado en OP). Para usar este método, deberá hacer un cambio fácil en networkx código fuente en el convert_matrix.py archivo, implementado aquí (fue un error simple).

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

Esto genera su MultiGraph, puede visualizarlo utilizando 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)

En detalle: positions es un diccionario donde cada nodo es una clave y el valor es una posición en el gráfico. Describiré por qué almacenamos positions abajo. El genérico draw dibujará su instancia de MultiGraph MG con los nodos en el especificado positions. Sin embargo, como puede ver, los bordes tienen el mismo ancho:
Unweighted

Pero tienes todo lo que necesitas para agregar los pesos. Primero, coloque los pesos en una lista llamada weights. Iterando (con la lista de comprensión) a través de cada borde con edges, podemos extraer los pesos. Elegí multiplicarme por 5 porque parecía el más limpio:

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

Finalmente usaremos draw_networkx_edges, que solo dibuja los bordes del gráfico (no hay nodos). Como tenemos el positions de los nodos, y establecemos hold=True, podemos dibujar bordes pesados ​​justo encima de nuestra visualización previa.

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

Weighted

Puedes ver el nodo (14, 13) tiene la línea más pesada y el valor más grande del DataFrame df (junto al (13,13))


5
2018-03-10 21:50



Debe editar la línea al comienzo del archivo csv de la siguiente manera:

fuente objetivo tipo peso 23 89 no dirigido 34.9 (es decir, hay un borde entre el nodo 23 y 89 con un peso de 34.9) 75 14 no dirigido 28.5 pronto....

Después de eso, puede importar el archivo csv en Gephi para representar el gráfico que representa el grosor de los bordes del peso, por ejemplo: enter image description here


0
2018-03-17 00:15



Preguntas populares