I'm using graphviz cgraph library to generate a dot file on macbook.
Here's a simple case in c:
#include "graphviz/cgraph.h"
#include <stdio.h>
int main(void) {
Agraph_t *g = agopen("Graph", Agdirected, NULL);
Agsym_t *s = agattr(g, AGNODE, "shape", "record");
Agnode_t *n = agnode(g, "case", TRUE);
char *l = "<<TABLE><TR><TD>Integer</TD></TR></TABLE>>";
agset(n, "label", agstrdup_html(g, l));
FILE *fp = fopen("test.dot", "w");
agwrite(g, fp);
fclose(fp);
agclose(g);
return 0;
}
Compile with clang test.c -o test.exe -lcgraph
, I expect it output dot file contains:
digraph {
node [shape=record];
case [label=<<TABLE><TR><TD>Integer</TD></TR></TABLE>>];
But it gives me:
digraph "Graph" {
node [shape=record];
case;
}
How sould I fix it ?
You need to define the attribute label
before you can assign it to a node. From the CGraph documentation included in the Graphviz distribution (p. 11):
Setting attributes is a bit more complex. Before attaching an attribute to a graph component, the code must first set up the default case. This is accomplished by a call to
agattr
. It takes a graph, an object type (AGRAPH
,AGNODE
,AGEDGE
), and two strings as arguments, and return a representation of the attribute. The first string gives the name of the attribute; the second supplies the default value. The graph must be the root graph.
This is true even for attributes normally defined by Graphviz, since the CGraph library is an independent component. In many use cases (including the ones in the Graphviz documentation), the graph is initialised from a base graph. Reading and parsing the base graph with agread
will normally populate the standard attributes, so it may not always be necessary to use agattr
. But in this case, you're defining the graph from scratch, so you need to define all of your attributes, even label
.
I made a few changes to your code; see the comments below for an explanation.
#include "graphviz/cgraph.h"
#include <stdio.h>
int main(void) {
Agraph_t *g = agopen("Graph", Agdirected, NULL);
Agsym_t *attr_shape = agattr(g, AGNODE, "shape", "record");
/* The following is needed before you can use attribute label */
Agsym_t *attr_label = agattr(g, AGNODE, "label", "");
Agnode_t *n = agnode(g, "case", TRUE);
/* Fixed the label. The outer angle brackets are part of the Graphviz
* syntax, not part of the label's value. (Just like quotes for normal
* labels, as the Graphviz documentation says.)
*/
char *label = "<TABLE><TR><TD>Integer</TD></TR></TABLE>";
/* Changed agset to agxset since we have the attribute's descriptor.
* The agset call would have worked, too, but this is a tad more efficient.
*/
agxset(n, attr_label, agstrdup_html(g, label));
agwrite(g, stdout);
agclose(g);
return 0;
}
This produces: