tcldot good for single shot rendering, but cannot interact and refresh

Hello,
I am using GraphViz with Tcl/Tk and found some issues that I posted on comp.lang.tcl.
This seems the better places for details on that. Unfortunately, I have no time to file the corresponding bug reports.
I hope the feedback and patches are as valuable as the length and complexity of this message... it lists 3 issues marked with "> #1~3".

On Thursday, January 14, 2016 at 6:44:11 PM UTC+1, heinrichmartin wrote:
> On Tuesday, January 12, 2016 at 12:46:15 PM UTC+1, Rich wrote:
> > You can also take a look at GraphViz (http://www.graphviz.org/). It is
> > very good at automatic graph layout, and it includes an output to Tk
> > canvas mode.
>
> Very good, indeed.
>
> > Your work will come then in interfacing your desired
> > interactivity to the output from GraphViz.
>
> Juggling workarounds come in, too.
>
> #1 neither attribute -tags nor tags is copied to the canvas items.

Nodes' meta info is not available in the canvas after rendering. So, I am forced to keep the Tcldot graph in memory and I cannot bind Tk-events to some of the nodes only.
As a workaround you can hook the interaction with the canvas "the Tcl way":


proc render_hook {g args} {
set tagi [lsearch -exact $args -tags]
incr tagi ;# value after key
set tags [dict get $args -tags]
if {[regexp {^([01])((edge|node)(\d+))$} $tags -> shape name type index]} {
# XXX retrieve the handle - unconfirmed whether the index is correct! see #2!
set handle [lindex [$g list${type}s] $index-1]
# custom tags
lset args $tagi [list \
$handle $name $type \
[if {$shape} {string cat shape} {string cat label}] \
{*}[lindex [$handle queryattributes -tags] 0]
]
}
{*}$args
}
eval [$g render [list render_hook $g $c]]

> #2 canvas items should be tagged with "(0|1)" according to tcldot(3tcl), but it is rather "(0|1)" which requires an ugly extra [lindex [$g listnodes] $idx-1] - unfortunately, I could not verify whether my assumption on the index is correct.

Unresolved. What happens when nodes or edges are deleted???

> #3 I am adding more nodes and edges interactively. When I try to call [$g write] or [$g render] once more, then tclsh coredumps with "emit.c:3899: init_splines_bb: Assertion `spl->size > 0' failed.". Note, that the problem is neither [$g layout] nor [eval $output_of_render].
>
> If anybody is interested:
> % package require Tcl
> 8.6.4
> % package require Tk
> 8.6.4
> % package require Tcldot
> 2.38.0

It turns out that neither layouting nor gvFreeLayout can handle graphs with layout info on some nodes only. (So forcing a layout before rendering is not enough as a workaround!)
The patch below removes all layout info whenever nodes or edges are added. Provided as-is with no warranty.

[can't get the formatting right; and .patch or .diff are not allowed as attachment]

--- tcldot-graphcmd.c.orig 2016-01-15 14:38:26.035818162 +0100
+++ ./tclpkg/tcldot/tcldot-graphcmd.c 2016-01-15 14:58:36.294817208 +0100
@@ -10,6 +10,7 @@
*
* Contributors: See CVS logs. Details at http://www.graphviz.org/
*************************************************************************/
+/* Patches by martin.heinrich@frequentis.com marked with PATCH_MHN. */

#include "tcldot.h"

@@ -75,12 +76,14 @@
Tcl_AppendResult(interp, "Head node ", argv[3], " is not in the graph.", NULL);
return TCL_ERROR;
}
+ gvFreeLayout(gvc, g); /* PATCH_MHN: neither layout nor freeLayout can handle partly layouted graphs */
e = agedge(g, tail, head, NULL, 1);
Tcl_AppendResult(interp, obj2cmd(e), NULL);
setedgeattributes(agroot(g), e, &argv[4], argc - 4);
return TCL_OK;

} else if ((c == 'a') && (strncmp(argv[1], "addnode", length) == 0)) {
+ gvFreeLayout(gvc, g); /* PATCH_MHN: neither layout nor freeLayout can handle partly layouted graphs */
if (argc % 2) {
/* if odd number of args then argv[2] is name */
n = agnode(g, argv[2], 1);
@@ -100,6 +103,7 @@
"\" addsubgraph ?name? ?attributename attributevalue? ?...?",
NULL);
}
+ gvFreeLayout(gvc, g); /* PATCH_MHN: neither layout nor freeLayout can handle partly layouted graphs */
if (argc % 2) {
/* if odd number of args then argv[2] is name */
sg = agsubg(g, argv[2], 1);
--- tcldot-nodecmd.c.orig 2016-01-15 14:57:57.217817228 +0100
+++ ./tclpkg/tcldot/tcldot-nodecmd.c 2016-01-15 15:08:29.569816725 +0100
@@ -10,6 +10,7 @@
*
* Contributors: See CVS logs. Details at http://www.graphviz.org/
*************************************************************************/
+/* Patches by martin.heinrich@frequentis.com marked with PATCH_MHN. */

#include "tcldot.h"

@@ -60,6 +61,7 @@
Tcl_AppendResult(interp, "Nodes ", argv[0], " and ", argv[2], " are not in the same graph.", NULL);
return TCL_ERROR;
}
+ gvFreeLayout(gctx->ictx->gvc, g); /* PATCH_MHN: neither layout nor freeLayout can handle partly layouted graphs */
e = agedge(g, n, head, NULL, 1);
Tcl_AppendResult(interp, obj2cmd(e), NULL);
setedgeattributes(agroot(g), e, &argv[3], argc - 3);

Recent comments