How to use Graphviz as library in C++ project

Hi,

I want to use Graphviz as library in C++ project.
The function I want to realize is that firstly generate a svg file from an existing dot file,
then modify some atrribute in the svg file,such as modify the color of some nodes.

I would highly appreciate it if someone could inform me how to do with it.

Thanks a lot

Is it possible to

Is it possible to perform

 system ("dot -Tsvg -omygraph.svg mygraph.gv");

or equivalent action by explicitly calling function from one of GraphViz dll?

What's the name of function, which can do it?

I've been looking it in manual http://www.graphviz.org/doc/libguide/libguide.pdf almost for 2 days, but I've not found it.

This is explained in section

This is explained in section 2 of the libguide. See, for example, figure 2. An equivalent to the system() use above is

 

GVC_t* gvc = gvContext(); 

Agraph_t* G = agread ("mygraph.gv");  // Slightly different if you are using 2.30 or later

gvLayout (gvc, G, "dot");

gvRenderFilename (gvc, G, "svg", "mygraph.svg");
gvFreeLayout(gvc, g);    

agclose (G);    

gvFreeContext(gvc);

How does it work with 2.30

I tried this with 2.30. My code is compile with MinGW 4.7.2, and it crashes at the line where you mention this. I went through the libguide documentation and didn't see anything there.

I noticed that graph.lib is no longer availiable, but I substituted with cgraph.lib - is that acceptable.

This is my main

GVC_t *gvc;
Agraph_t *g;
FILE *fp;

gvc = gvContext();

if (argc > 1) {
std::cout << "File " << argv[1] << std::endl;
fp = fopen(argv[1], "r");
}
else {
fp = stdin;
}
g = agread(fp);

gvLayout(gvc, g, "dot");
gvRender(gvc, g, "plain", stdout);
gvFreeLayout(gvc, g);
agclose(g);

return (gvFreeContext(gvc));

Also agread() now seems to take only one parameter

The problem is that the

The problem is that the Windows version is built using Visual Studio where you are compiling your main program with MinGW. The two systems use incompatible implementations of stdio. Fortunately, the replacement of graph.dll with cgraph.dll makes it fairly easy to get around this. (You should find that agread() takes two arguments, for this reason.) You just need to supply your own reading function. Instead of calling agread directly, use

static int
mingwfread(void *chan, char *buf, int bufsize)
{
    return fread(buf, 1, bufsize, (FILE*)chan);
}

static Agraph_t*
readGraph (FILE* fp)
{
    Agiodisc_t mingwIoDiscr;
    Agdisc_t disc;

    mingwIoDisc.fread = mingwfread;
    mingwIoDisc.putstr = AgIoDisc.putstr;
    mingwIoDisc.flush = AgIoDisc.flush;
    disc.mem = &AgMemDisc;
    disc.id = &AgIdDisc;
    disc.io = &mingwIoDisc;
    return agread (fp, &disc);
}

Obviously, if you are going to agwrite() or gvcRender(), you'll to need to modify the write functions similarly.

 

Crashes Later

Thanks for the pointers. I've been given this problem to make a little progress on. I've gotten past the IO and now the library simply crashes later. I've stepped through the code and I know that the reads have completed. I belive the library is now about the business of parsing the graph. At this point, the code appears to jump to an invalid address:

Here's a portion of the output from WinDBG

0:000> g
(740.b8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=616425ff ebx=7efde000 ecx=0028fefc edx=004014c0 esi=00000000 edi=00000000
eip=616425ff esp=0028f93c ebp=0028f95c iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
616425ff ?? ???

0:000> kv
ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
0028f938 10005496 0028fefc 006d1a68 00000001 0x616425ff
0028f95c 1000538f 0028fefc 00000000 00000013 cgraph!agopen+0x116
0028f974 100051df 006d1a78 00000009 0028fefc cgraph!agopen+0xf
0028f988 10003f48 006d1a78 00000001 00000000 cgraph!agnotflat+0x172f
0028feb8 1000532b 0028fefc 0028fed8 10005372 cgraph!agnotflat+0x498
0028fec4 10005372 00000000 750b2960 0028fefc cgraph!agnotflat+0x187b
0028fed8 00401487 750b2960 0028fefc 0028ff08 cgraph!agread+0x12
0028ff28 004010fd 00000001 005719f8 00571d28 image00400000+0x1487
0028ff94 778a9ef2 7efde000 7eb9b671 00000000 image00400000+0x10fd
0028ffd4 778a9ec5 00401280 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
0028ffec 00000000 00401280 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

0:000> da 006d1a78
006d1a78 "g"

 

The 1st argument to aopen appers to be the 2nd token in the dot file.  Here's the DOT file I'm working with:

digraph g {
A -> B;
B -> C;
}

Any idea what is causing the crash?

Gets past the read using CRT and then crashes later

Hello, I got passed this issue to spend some time on. Thanks for the pointers, it really helped.

I've gotten past the CRT and the file reading portion and now the library just AV's a bit later.  It seems the code jumps into oblivion.

0:000> g
(12f4.55c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=616825ff ebx=7efde000 ecx=0028fefc edx=00401514 esi=00000000 edi=00000000
eip=616825ff esp=0028f93c ebp=0028f95c iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
616825ff ?? ???

0:000> kv
ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
0028f938 10005496 0028fefc 00731a80 00000001 0x616825ff
0028f95c 1000538f 0028fefc 00000000 00000013 cgraph!agopen+0x116
0028f974 100051df 00731a90 00000009 0028fefc cgraph!agopen+0xf
0028f988 10003f48 00731a90 00000001 00000000 cgraph!agnotflat+0x172f
0028feb8 1000532b 0028fefc 0028fed8 10005372 cgraph!agnotflat+0x498
0028fec4 10005372 00000000 750b2960 0028fefc cgraph!agnotflat+0x187b
0028fed8 004014d8 750b2960 0028fefc 0028ff08 cgraph!agread+0x12
0028ff28 004010fd 00000001 006919f8 00691d40 image00400000+0x14d8
0028ff94 778a9ef2 7efde000 7f468c10 00000000 image00400000+0x10fd
0028ffd4 778a9ec5 00401280 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
0028ffec 00000000 00401280 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

As near as I can tell, some internal funciton is parsing through the file and it gets otthe 2nd token. Here's my DOT file:

digraph g {
   A -> B;
   B -> C;
}

And dumping the arguments to cgraph!agopen we see that the argument is the null terminated string "g" .

0:000> db 00731a90 l 3
00731a90 67 00 ad g..

Any idea what is inducing the crash?

Thanks for the help.

 

I don't know what to say

I don't know what to say about the tracebacks you are getting, but first try fixing the rendering step. In the same way that you can't use stdin for reading, you can't use stdout for writing.

You can either fix this as we did with reading by supplying mingw write functions, or you can replace gvRender() with gvRenderFilename().

How to use Graphviz as

Take a look at the manual http://www.graphviz.org/doc/libguide/libguide.pdf. This explains how to do this at various levels. As you already have a dot file, and just want to tweak the svg file, the simplest approach is to use graphviz as a black-box filter. Suppose your dot file is called mygraph.gv. Then your C++ code could run
 
    system ("dot -Tsvg -omygraph.svg mygraph.gv");
 
You could then read in the mygraph.svg file and process it to your heart's content. If this doesn't give you adequate control, you can explore the manual for more complex solutions.

Recent comments