libreria - Mejorando el diseño gráfico de Python NetworkX
update networkx version (4)
Estoy teniendo algunos problemas para visualizar los gráficos creados con python-networkx, quiero poder reducir el desorden y regular la distancia entre los nodos (también he intentado spring_layout, simplemente establece los nodos de manera elíptica). Por favor avise.
Partes del código:
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)
En networkx, vale la pena revisar los algoritmos de dibujo de gráficos proporcionados por graphviz través de nx.graphviz_layout
.
He tenido buenos resultados con neato
pero los otros posibles insumos son
dot
- dibujos "jerárquicos" o en capas de gráficos dirigidos. Esta es la herramienta predeterminada para usar si los bordes tienen direccionalidad.neato
- "diseños de modelo de resorte". Esta es la herramienta predeterminada que se debe usar si el gráfico no es demasiado grande (unos 100 nodos) y no se sabe nada más sobre él. Neato intenta minimizar una función de energía global, que es Equivalente a la escala estadística multidimensional.fdp
:fdp
"modelos de resorte" similares a los de neato, pero lo hace reduciendo fuerzas en lugar de trabajar con energía.sfdp
- versión multiescala de fdp para el diseño de gráficos grandes.twopi
- diseños radiales, después de Graham Wills 97. Los nodos se colocan en círculos concéntricos dependiendo de su distancia desde un nodo raíz dado.circo
- diseño circular, después de Six y Tollis 99, Kauffman y Wiese 02. Esto es adecuado para ciertos diagramas de múltiples estructuras cíclicas, como ciertas redes de telecomunicaciones.
En general, el dibujo gráfico es un problema difícil. Si estos algoritmos no son suficientes, deberá escribir los suyos propios o tener partes de dibujo de networkx individualmente.
Encontré que esto es útil para visualizar rápidamente los datos de interacción obtenidos como un archivo CSV de PostgreSQL. [Salida abajo reformateada para facilitar la lectura.]
## 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
Es difícil disminuir la congestión en estas parcelas estáticas de networkx / matplotlib; una solución es aumentar el tamaño de la figura, según este P / R de : Imagen de alta resolución de un gráfico utilizando NetworkX y 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>
Bono - camino más corto:
>>> nx.dijkstra_path(G, ''CDKN1A'', ''MLH3'')
[''CDKN1A'', ''CDK2'', ''CHEK2'', ''BRCA1'', ''PTEN'', ''MLH3'']
Para responder a su pregunta sobre cómo regular la distancia entre nodos, amplío la respuesta de Hooked :
Si dibuja el gráfico a través del backend de Graphviz y luego usa el algoritmo fdp
, puede ajustar la distancia entre nodos por el atributo de borde len
.
Aquí hay un ejemplo de código, cómo dibujar un gráfico G
y guardar en el archivo gvfile
archivo Graphviz con una distancia más amplia entre nodos (la distancia predeterminada para fdp
es 0.3
):
A = nx.to_agraph(G)
A.edge_attr.update(len=3)
A.write(gv_file_name)
Dos comentarios:
- Normalmente, es recomendable ajustar
len
con el número de nodos en el gráfico. - El atributo
len
solo es reconocido por el algoritmofdp
yneato
, pero no por ejemplo por el algoritmosfdp
.
Tiene una gran cantidad de datos en su gráfico, por lo que será difícil eliminar el desorden.
Le sugiero que utilice cualquier diseño estándar. Dijiste que spring_layout
. Le sugiero que lo intente de nuevo, pero esta vez use el atributo de weight
al agregar los bordes.
Por ejemplo:
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()
Además, puede utilizar la scale
parámetros para aumentar la distancia global entre los nodos.