Pasando una cuerda a agege en agraph.py. Problema con networkx y pygraphviz
Dado este gráfico inicial:
import networkx as nx
G=nx.MultiGraph()
fromnodes=[0,0,1,1,1,1,1,2,3,4,5,5,5,7,8,9,10]
tonodes=[1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
dupedgeind=0
for x,y in zip(fromnodes,tonodes):
if G.has_edge(x,y):
dupedgeind=dupedgeind+1
G.add_edge(x,y,key=dupedgeind)
else:
dupedgeind=0
G.add_edge(x,y,key=dupedgeind)
¿Alguien puede recrear este error?
pos=nx.nx_agraph.pygraphviz_layout(G,prog='sfdp')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\networkx\drawing\nx_agraph.py", line 262, in pygraphviz_layout
A=to_agraph(G)
File "C:\Python27\lib\site-packages\networkx\drawing\nx_agraph.py", line 155, in to_agraph
A.add_edge(u,v,key=str(key),**str_edgedata)
File "C:\Python27\lib\site-packages\pygraphviz\agraph.py", line 484, in add_edge
eh = gv.agedge(self.handle, uh, vh, key, _Action.find)
KeyError: 'agedge: no key'
El problema tiene algo que ver con la llamada a la función de envejecimiento de graphviz, parece que no le gusta el formato dekey
parámetro; cuando cambio (línea 480 deagraph.py
):
...
eh = gv.agedge(self.handle, uh, vh, key , _Action.create)
...
a
...
eh = gv.agedge(self.handle, uh, vh, "a_string" , _Action.create)
...
ya no falla (pero pierde las etiquetas clave).
¿Hay una manera obvia de arreglar esto? (así que esokey
los valores de los parámetros se retienen)? - Nada de lo que intento parece funcionar.
¿Cuáles son los próximos pasos de depuración más razonables?
Deaquí, parece que elc
La función envejecida (que no puedo ver ya que está en un binario .pyd) tiene el siguiente formato:
*agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
donde elchar *name
es la llave.
No puedo entender por qué no acepta unstr
dtype como en el error inicial.
Nota versiones:
networkx - 1.11, pygraphviz - 1.3.1 (instalado desdehttp://www.lfd.uci.edu/~gohlke/pythonlibs/#pygraphviz) Python 2.7 (32 bits - instalado a través de python (x, y)) en Windows 7 (64 bits), GraphViz - 2.38
También he visto surgir este problema en estas preguntas:
Gráfico jerárquico con aristas paralelas.
Cómo dibujar bordes paralelos en Networkx / Graphviz
ACTUALIZACIÓN 1
He intentado ajustar elkey
entrada a la función envejecida a una serie de variantes de matrices de caracteres (p. ej.(ct.c_char_p * len(key))(key)
(ct es el módulo ctypes) basado enesta) Esto cambia el error a:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\networkx\drawing\nx_agraph.py", line 262, in pygraphviz_layout
A=to_agraph(G)
File "C:\Python27\lib\site-packages\networkx\drawing\nx_agraph.py", line 155, in to_agraph
A.add_edge(u,v,str(key),**str_edgedata)
File "C:\Python27\lib\site-packages\pygraphviz\agraph.py", line 482, in add_edge
eh = gv.agedge(self.handle, uh, vh, (ct.c_char_p * len(key))(key), _Action.create)
TypeError: in method 'agedge', argument 4 of type 'char *'
ACTUALIZACIÓN 2
Puedo hacer que se ejecute (pero no devolver un multigrafo) si hago esto:
Enagraph.py
reemplazando la línea
eh = gv.agedge(self.handle, uh, vh, key , _Action.create)
con
try:
# new
if key==0:
eh = gv.agedge(self.handle, uh, vh, str(0), _Action.create)
else:
eh = gv.agedge(self.handle, uh, vh, str(1), _Action.create)
No sé por qué simplemente lanzar a una cuerdastr(key)
No funciona.
ACTUALIZACIÓN 3 - EDITAR con la función
Encontré la función aquí:https://github.com/ellson/graphviz/blob/master/lib/cgraph/edge.c
Agedge_t *agedge(Agraph_t * g, Agnode_t * t, Agnode_t * h, char *name,
int cflag)
{
Agedge_t *e;
IDTYPE id;
int have_id;
have_id = agmapnametoid(g, AGEDGE, name, &id, FALSE);
if (have_id || ((name == NILstr) && (NOT(cflag) || agisstrict(g)))) {
/* probe for pre-existing edge */
Agtag_t key;
key = Tag;
if (have_id) {
key.id = id;
key.objtype = AGEDGE;
} else {
key.id = key.objtype = 0;
}
/* might already exist locally */
e = agfindedge_by_key(g, t, h, key);
if ((e == NILedge) && agisundirected(g))
e = agfindedge_by_key(g, h, t, key);
if (e)
return e;
if (cflag) {
e = agfindedge_by_key(agroot(g), t, h, key);
if ((e == NILedge) && agisundirected(g))
e = agfindedge_by_key(agroot(g), h, t, key);
if (e) {
subedge(g,e);
return e;
}
}
}
ACTUALIZACIÓN 4:
La fuente del error está dentro deesta archivo pygraphviz, graphviz_wrap.c, línea 3921:
SWIGINTERN PyObject *_wrap_agedge(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0;
Agraph_t *arg1 = (Agraph_t *) 0 ;
Agnode_t *arg2 = (Agnode_t *) 0 ;
Agnode_t *arg3 = (Agnode_t *) 0 ;
char *arg4 = (char *) 0 ;
int arg5 ;
void *argp1 = 0 ;
int res1 = 0 ;
void *argp2 = 0 ;
int res2 = 0 ;
void *argp3 = 0 ;
int res3 = 0 ;
int res4 ;
char *buf4 = 0 ;
int alloc4 = 0 ;
int val5 ;
int ecode5 = 0 ;
PyObject * obj0 = 0 ;
PyObject * obj1 = 0 ;
PyObject * obj2 = 0 ;
PyObject * obj3 = 0 ;
PyObject * obj4 = 0 ;
Agedge_t *result = 0 ;
if (!PyArg_ParseTuple(args, char*)"OOOOO:agedge",&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Agraph_t, 0 | 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "in method '""agedge" "', argument " "1"" of type '" "Agraph_t *""'");
}
arg1 = (Agraph_t *)(argp1);
res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_Agnode_t, 0 | 0 );
if (!SWIG_IsOK(res2)) {
SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "agedge" "', argument " "2"" of type '" "Agnode_t *""'");
}
arg2 = (Agnode_t *)(argp2);
res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_Agnode_t, 0 | 0 );
if (!SWIG_IsOK(res3)) {
SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "agedge" "', argument " "3"" of type '" "Agnode_t *""'");
}
arg3 = (Agnode_t *)(argp3);
res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4);
if (!SWIG_IsOK(res4)) {
SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "agedge" "', argument " "4"" of type '" "char *""'");
}
arg4 = (char *)(buf4);
ecode5 = SWIG_AsVal_int(obj4, &val5);
if (!SWIG_IsOK(ecode5)) {
SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "agedge" "', argument " "5"" of type '" "int""'");
}
arg5 = (int)(val5);
{
result = (Agedge_t *)agedge(arg1,arg2,arg3,arg4,arg5);
if (!result) {
PyErr_SetString(PyExc_KeyError,"agedge: no key");
return NULL;
}
}
resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Agedge_t, 0 | 0 );
if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
return resultobj;
fail:
if (alloc4 == SWIG_NEWOBJ) free((char*)buf4);
return NULL;
}
O está dentroéste, graphviz.i, línea 68.
De cualquier manera, parece que la cadena de error "envejecido: sin clave" se devuelve siagedge
falla por alguna razón ... Quizás sea algo relacionado con SWIG.