web-dev-qa-db-fra.com

Comment améliorer la visualisation des graphes réseau?

J'ai essayé d'utiliser networkx dans python pour transformer une matrice adjacente en un graphique. Mon graphique "pondéré" a environ 8000 nœuds et 14000 arêtes. Existe-t-il une grande forme de mise en page ou d'autres packages, outils pour rendre mon graphique plus beau? J'espère que le résultat est que le poids Edge plus élevé les nœuds se rapprochent. Afin que je puisse analyser les nœuds du cluster.

J'avais essayé toute la mise en page fournie dans le document networkx. J'ai aussi essayé d'utiliser gephi et il n'est toujours pas satisfait de mon idéal. Voici à quoi cela ressemble dans networkx. Il peut montrer tout le cluster mais cela semble un peu terrible pour quelqu'un qui a une phobie intensive:

enter image description here

Voici le code que j'ai utilisé pour dessiner le graphique:

G = nx.Graph()
for i in range(10000):
    for j in range(10000):
        if mat[i][j] > 10:
            G.add_Edge(a[i], a[j], weight=mat[i][j])
pos = nx.nx_pydot.graphviz_layout(G)
plt.figure(figsize=(8, 8))
plt.axis('off')
nx.draw_networkx(G, pos=pos, with_labels=False, node_size=25, edgecolors='black', Edge_color='b')
plt.show()
9
shaoyu0105

Plongeons un peu dans la visualisation de grands graphes:

Dans le contexte de votre question, vous avez trois façons de visualiser un graphique:

  1. Dessinez le graphique entier sur un seul écran
  2. Dessinez le graphique sur une surface plus grande qu'un écran
  3. Dessinez partiellement le graphique ou réduisez le nombre d'éléments dessinés

Nous passerons en revue ces façons une par une:

1. Compressez l'incompressible

Vous avez 8000 nœuds et 14000 arêtes dans votre graphique. Imaginons que vous n'ayez qu'à dessiner des nœuds sans arêtes. Ainsi, pour un affichage FullHD moyen, vous aurez:

1920 * 1080 / 8000 = 259 Pixels par nœud. C'est:

sqrt(259) = 17

Un 17 × 17 px. nœud si vous allez carreler tout l'affichage avec des nœuds. Si vous souhaitez dessiner des étiquettes de nœuds, vous aurez:

17 - 1 * 2 (outer node borders) - 1 * 2 (inner node borders) = 13×13 carré. La police la plus petite possible (je ne parlerai pas des polices ésotériques ) a une taille de 3×3(+1) donc vous ne pouvez pas stocker plus de 9 caractères par nœud.

Cela ressemble à ceci:

enter image description here

Et nous n'avons toujours pas dessiné les bords du graphique! Si nous voulons le faire, nous utiliserons:

1920 * 1080 / (8000 + 14000) = 94 pixels par élément graphique, et:

sqrt(94) = 9.7 - 9×9 px. nœuds, il est donc presque impossible d'avoir même des étiquettes simples sur eux.

Je pense qu'il est évident maintenant que l'ensemble du graphique sur l'écran unique ressemblera toujours à un désordre horrible. Ce n'est donc pas une option pour dessiner votre graphique de cette façon.

2. Développez le non extensible

Si nous ne pouvons pas dessiner le graphique sur un écran, nous pouvons ratisser nos cerveaux et inventer une issue - pour le dessiner sur plusieurs écrans! Nous pouvons le faire de deux manières:

  • Utilisation de matplotlib
  • Utilisation de graphviz

Dans le cas de matplotlib, nous créons une très grande figure (avec l'argument figsize) puis importons notre graphique dans une image (avec plt.savefig):

import networkx as nx 
import matplotlib.pyplot as plt 

fig = plt.figure(figsize=(40, 40)) 
G = nx.fast_gnp_random_graph(300, 0.02, seed=1337) 
nx.draw(G, node_size=30) 
plt.axis('equal') 
plt.show() 
fig.savefig('waka.svg') 

Nous aurons donc une grande image vectorielle (en voici une petite partie):

enter image description here

Dans ce cas, nous pouvons utiliser n'importe quelle disposition de graphique disponible dans networkx.

Une autre façon est d'utiliser la bibliothèque externe Graphviz qui dessinera notre graphique. Honnêtement, dans ce cas, networkx va simplement convertir le graphique en fichier .dot Et l'envoyer à Graphviz. Le principal inconvénient est que vous ne pouvez pas contrôler la façon dont Graphviz dessinera votre graphique. Mais il a de très bonnes dispositions, donc le résultat sera acceptable.

Utilisez ce code Python pour générer le fichier .dot:

import networkx as nx 

G = nx.fast_gnp_random_graph(300, 0.02, seed=1337) 
nx.nx_agraph.write_dot(G, './waka.dot')

puis utilisez Graphviz:

dot -Tsvg waka.dot >waka.svg

ou pour les graphes non dirigés:

neato -Tsvg waka.dot -Goverlap=false >waka.svg

donc l'image résultante ressemblera à ceci (voici aussi une petite partie de l'image entière):

enter image description here

Graphviz possède une énorme quantité d'options différentes afin que vous puissiez transformer votre graphique en le regardant presque comme vous le souhaitez.

3. Coupez l'impossible

Dans votre graphique, vous avez quelque chose comme un composant géant connecté ( GCC ) et de nombreux petits sous-graphiques. L'image est d'environ 580 × 580 et GCC est d'environ 290 × 290, donc GCC utilise:

(290 × 290) ÷ (580 × 580) × 100 = 25% De votre toile. Si vous ne gardez que GCC, vous aurez 4 fois plus d'espace pour dessiner! Dans ce cas, vous pouvez dessiner un autre composant connecté sur une autre image.

Vous ne pouvez conserver que GCC avec un code comme celui-ci:

import networkx as nx 

G = nx.fast_gnp_random_graph(300, 0.01, seed=1337)
gcc = max(nx.connected_components(G), key=lambda x: len(x))
H = G.subgraph(gcc)
nx.draw(G, node_size=30, node_color='red')

dessinera le graphique d'origine:

enter image description here

Et avec cette dernière ligne:

nx.draw(H, node_size=30, node_color='red')

il attirera uniquement le CCG:

enter image description here


P.S.

Que pouvez-vous faire d'autre avec votre graphique:

  • Clusteriser les nœuds
  • Jouez avec la taille du nœud (PageRank, etc.)
  • Jouez avec la couleur Edge
  • Ne dessinez pas les bords mais gardez la disposition
  • WEEP (au cas où ma réponse ne vous aurait même pas aidé un peu)
11
vurmux