web-dev-qa-db-fra.com

Amélioration de la configuration du graphique Python NetworkX

J'ai des problèmes pour visualiser les graphiques créés avec python-networkx, je veux pouvoir réduire l'encombrement et réguler la distance entre les nœuds (j'ai également essayé spring_layout, il présente simplement les nœuds de manière elliptique). S'il vous plaît donnez votre avis. enter image description here

Parties du code:

nx.draw_networkx_edges(G, pos, edgelist=predges, Edge_color='red', arrows=True)
nx.draw_networkx_edges(G, pos, edgelist=black_edges, arrows=False, style='dashed')
# label fonts
nx.draw_networkx_labels(G,pos,font_size=7,font_family='sans-serif')
nx.draw_networkx_Edge_labels(G,pos,q_list,label_pos=0.3)
29
Sayan

Dans networkx, il vaut la peine de vérifier les algorithmes de dessin de graphes fournis par graphviz via nx.graphviz_layout .

J'ai eu un bon succès avec neato mais les autres entrées possibles sont

  • dot - dessins "hiérarchiques" ou en couches de graphiques dirigés. Il s'agit de l'outil par défaut à utiliser si les bords ont une directionnalité.

  • neato - Layouts "Spring model" '. C'est l'outil par défaut à utiliser si le graphique n'est pas trop grand (environ 100 nœuds) et que vous ne savez rien d'autre à ce sujet. Neato essaie de minimiser un global fonction d'énergie, qui équivaut à une mise à l'échelle multidimensionnelle statistique.

  • fdp - dispositions du "modèle de ressort" similaires à celles de neato, mais cela en réduisant les forces plutôt qu'en travaillant avec de l'énergie.

  • sfdp - version multi-échelles de fdp pour la mise en page de grands graphiques.

  • twopi - dispositions radiales, après Graham Wills 97. Les nœuds sont placés sur des cercles concentriques en fonction de leur distance par rapport à un nœud racine donné.

  • circo - disposition circulaire, après Six et Tollis 99, Kauffman et Wiese 02. Cela convient à certains schémas de structures cycliques multiples, tels que certains réseaux de télécommunications.

En général, dessin graphique est un problème difficile. Si ces algorithmes ne sont pas suffisants, vous devrez écrire le vôtre ou avoir des parties de dessin networkx individuellement.

46
Hooked

J'ai trouvé cela utile pour visualiser rapidement les données d'interaction provenant d'un fichier CSV de PostgreSQL. [Sortie ci-dessous reformatée pour plus de lisibilité.]

## PSQL ['DUMMY' DATA]:

[interactions_practice]# \copy (SELECT gene_1, gene_2 FROM interactions
  WHERE gene_1 in (SELECT gene_2 FROM interactions))
  TO '/tmp/a.csv' WITH CSV      -- << note: no terminating ";" for this query

## BASH:

[victoria@victoria ~]$ cat /tmp/a.csv                                                                                                      

  APC,TP73
  BARD1,BRCA1
  BARD1,ESR1
  BARD1,KRAS2
  BARD1,SLC22A18
  BARD1,TP53
  BRCA1,BRCA2
  BRCA1,CHEK2
  BRCA1,MLH1
  BRCA1,PHB
  BRCA2,CHEK2
  BRCA2,TP53
  CASP8,ESR1
  CASP8,KRAS2
  CASP8,PIK3CA
  CASP8,SLC22A18
  CDK2,CDKN1A
  CHEK2,CDK2
  ESR1,BRCA1
  ESR1,KRAS2
  ESR1,PPM1D
  ESR1,SLC22A18
  KRAS2,BRCA1
  MLH1,CHEK2
  MLH1,PMS2
  PIK3CA,BRCA1
  PIK3CA,ESR1
  PIK3CA,RB1CC1
  PIK3CA,SLC22A18
  PMS2,TP53
  PTEN,BRCA1
  PTEN,MLH3
  RAD51,BRCA1
  RB1CC1,SLC22A18
  SLC22A18,BRCA1
  TP53,PTEN


## PYTHON 3.5 VENV (ANACONDA):

>>> import networkx as nx
>>> import pylab as plt
>>> G = nx.read_edgelist("/tmp/a.csv", delimiter=",")

>>> G.edges()

  [('CDKN1A', 'CDK2'), ('MLH3', 'PTEN'), ('TP73', 'APC'), ('CHEK2', 'MLH1'),
   ('CHEK2', 'BRCA2'), ('CHEK2', 'CDK2'), ('CHEK2', 'BRCA1'), ('BRCA2', 'TP53'),
   ('BRCA2', 'BRCA1'), ('KRAS2', 'CASP8'), ('KRAS2', 'ESR1'), ('KRAS2', 'BRCA1'),
   ('KRAS2', 'BARD1'), ('PPM1D', 'ESR1'), ('BRCA1', 'PHB'), ('BRCA1', 'ESR1'),
   ('BRCA1', 'PIK3CA'), ('BRCA1', 'PTEN'), ('BRCA1', 'MLH1'), ('BRCA1', 'SLC22A18'),
   ('BRCA1', 'BARD1'), ('BRCA1', 'RAD51'), ('CASP8', 'ESR1'), ('CASP8', 'SLC22A18'),
   ('CASP8', 'PIK3CA'), ('TP53', 'PMS2'), ('TP53', 'PTEN'), ('TP53', 'BARD1'),
   ('PMS2', 'MLH1'), ('PIK3CA', 'SLC22A18'), ('PIK3CA', 'ESR1'), ('PIK3CA', 'RB1CC1'),
   ('SLC22A18', 'ESR1'), ('SLC22A18', 'RB1CC1'), ('SLC22A18', 'BARD1'), ('BARD1', 'ESR1')]

>>> G.number_of_edges()
  36

>>> G.nodes()

  ['CDKN1A', 'MLH3', 'TP73', 'CHEK2', 'BRCA2', 'KRAS2', 'CDK2', 'PPM1D', 'BRCA1',
   'CASP8', 'TP53', 'PMS2', 'RAD51', 'PIK3CA', 'MLH1', 'SLC22A18', 'BARD1', 'PHB', 'APC', 'ESR1', 'RB1CC1', 'PTEN']

>>> G.number_of_nodes()
  22

>>> from networkx.drawing.nx_agraph import graphviz_layout

>>> ## nx.draw(G, pos=graphviz_layout(G))

## DUE TO AN UNIDENTIFIED BUG, I GET THIS ERROR THE FIRST TIME RUNNING THIS
## COMMAND; JUST RE-RUN IT:

>>> nx.draw(G, pos=graphviz_layout(G), node_size=1200, node_color='lightblue',
    linewidths=0.25, font_size=10, font_weight='bold', with_labels=True)

  QGtkStyle could not resolve GTK. Make sure you have installed the proper libraries.

>>> nx.draw(G, pos=graphviz_layout(G), node_size=1200, node_color='lightblue',
    linewidths=0.25, font_size=10, font_weight='bold', with_labels=True)

>>> plt.show()    ## plot1.png [opens in matplotlib popup window] attached

Il est difficile de réduire la congestion dans ces tracés statiques networkx/matplotlib; une solution de contournement consiste à augmenter la taille de la figure, par ce StackOverflow Q/A: Image haute résolution d'un graphique utilisant NetworkX et Matplotlib :

>>> plt.figure(figsize=(20,14))
  <matplotlib.figure.Figure object at 0x7f1b65ea5e80>

>>> nx.draw(G, pos=graphviz_layout(G), node_size=1200, node_color='lightblue',
    linewidths=0.25, font_size=10, font_weight='bold', with_labels=True, dpi=1000)

>>> plt.show()    ## plot2.png attached

## RESET OUTPUT FIGURE SIZE TO SYSTEM DEFAULT:

>>> plt.figure()
  <matplotlib.figure.Figure object at 0x7f1b454f1588>

plot1.png plot1.png

plot2.png plot2.png

Bonus - chemin le plus court:

>>> nx.dijkstra_path(G, 'CDKN1A', 'MLH3')
['CDKN1A', 'CDK2', 'CHEK2', 'BRCA1', 'PTEN', 'MLH3']
6
Victoria Stuart

Vous avez beaucoup de données dans votre graphique, il sera donc difficile de supprimer l'encombrement.

Je vous suggère d'utiliser n'importe quelle mise en page standard. Vous avez dit que vous utilisiez spring_layout. Je vous suggère de réessayer mais cette fois en utilisant l'attribut weight lors de l'ajout des bords.

Par exemple:

import networkx as nx

G = nx.Graph();
G.add_node('A')
G.add_node('B')
G.add_node('C')
G.add_node('D')
G.add_Edge('A','B',weight=1)
G.add_Edge('C','B',weight=1)
G.add_Edge('B','D',weight=30)

pos = nx.spring_layout(G,scale=2)

nx.draw(G,pos,font_size=8)
plt.show()

De plus, vous pouvez utiliser le paramètre scale pour augmenter la distance globale entre les nœuds.

5
phyrox

Pour répondre à votre question sur la façon de réguler la distance entre les nœuds, je développe sur réponse de Hooked :

Si vous dessinez le graphique via le backend Graphviz et lorsque vous utilisez ensuite l'algorithme fdp, vous pouvez ajuster la distance entre les nœuds par Edge attribut len .

Voici un exemple de code, comment dessiner un graphique G et enregistrer dans le fichier Graphviz gvfile avec une distance plus grande entre les nœuds (la distance par défaut pour fdp est 0.3):

A = nx.to_agraph(G)
A.Edge_attr.update(len=3)
A.write(gv_file_name)

Deux commentaires:

  1. Il est normalement conseillé d'ajuster len avec le nombre de nœuds dans le graphique.
  2. L'attribut len n'est reconnu que par l'algorithme fdp et neato, mais pas par ex. par l'algorithme sfdp.
3
halloleo