Graphviz 16.0.0~dev.20260810.2334
Loading...
Searching...
No Matches
DotIO.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#define STANDALONE
14#include <assert.h>
15#include <cgraph/cgraph.h>
16#include <limits.h>
17#include <math.h>
18#include <sparse/DotIO.h>
19#include <sparse/clustering.h>
21#include <sparse/colorutil.h>
22#include <sparse/general.h>
23#include <sparse/mq.h>
24#include <stdbool.h>
25#include <stddef.h>
26#include <string.h>
27#include <util/agxbuf.h>
28#include <util/alloc.h>
29#include <util/itos.h>
30#include <util/startswith.h>
31#include <util/unreachable.h>
32
33typedef struct {
34 Agrec_t h;
35 int id;
37
38#define ND_id(n) (((Agnodeinfo_t *)((n)->base.data))->id)
39
40static void color_string(agxbuf *buf, size_t dim, double *color) {
41 if (dim > 3 || dim < 1) {
42 fprintf(stderr, "can only 1, 2 or 3 dimensional color space. with color "
43 "value between 0 to 1\n");
44 assert(0);
45 }
46 if (dim == 3) {
47 agxbprint(buf, "#%02x%02x%02x", MIN((unsigned int)(color[0] * 255), 255),
48 MIN((unsigned int)(color[1] * 255), 255),
49 MIN((unsigned int)(color[2] * 255), 255));
50 } else if (dim == 1) {
51 agxbprint(buf, "#%02x%02x%02x", MIN((unsigned int)(color[0] * 255), 255),
52 MIN((unsigned int)(color[0] * 255), 255),
53 MIN((unsigned int)(color[0] * 255), 255));
54 } else if (dim == 2) {
55 agxbprint(buf, "#%02x%02x%02x", MIN((unsigned int)(color[0] * 255), 255), 0,
56 MIN((unsigned int)(color[1] * 255), 255));
57 }
58}
59
60void attach_edge_colors(Agraph_t *g, size_t dim, double *colors) {
61 /* colors is array of dim*nedges, with color for edge i at colors[dim*i,
62 * dim(i+1))
63 */
64 Agsym_t *sym = agattr_text(g, AGEDGE, "color", 0);
65 Agedge_t *e;
66 Agnode_t *n;
67 agxbuf buf = {0};
68 size_t ie = 0;
69
70 if (!sym)
71 sym = agattr_text(g, AGEDGE, "color", "");
72
73 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
74 const int row = ND_id(n);
75 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
76 const int col = ND_id(aghead(e));
77 if (row == col)
78 continue;
79 color_string(&buf, dim, colors + ie * dim);
80 agxset(e, sym, agxbuse(&buf));
81 ie++;
82 }
83 }
84 agxbfree(&buf);
85}
86
87/* SparseMatrix_import_dot:
88 * Assumes g is connected and simple, i.e., we can have a->b and b->a
89 * but not a->b and a->b
90 */
92 assert(x != NULL);
93 enum { DIM = 2 };
94 SparseMatrix A = 0;
95 Agsym_t *psym;
96 int *I;
97 int *J;
98 double *val;
99 double v;
101
102 if (!g)
103 return NULL;
104 const size_t nnodes = agnnodes_z(g);
105 const size_t nedges = (size_t)agnedges(g);
106 assert(format == FORMAT_CSR || format == FORMAT_COORD);
107
108 /* Assign node ids */
109 int i = 0;
110 for (Agnode_t *n = agfstnode(g); n; n = agnxtnode(g, n))
111 ND_id(n) = i++;
112
113 if (format == FORMAT_COORD) {
115 A->nz = nedges;
116 I = A->ia;
117 J = A->ja;
118 val = A->a;
119 } else {
120 I = gv_calloc(nedges, sizeof(int));
121 J = gv_calloc(nedges, sizeof(int));
122 val = gv_calloc(nedges, sizeof(double));
123 }
124
125 Agsym_t *const sym = agattr_text(g, AGEDGE, "weight", NULL);
126 i = 0;
127 for (Agnode_t *n = agfstnode(g); n; n = agnxtnode(g, n)) {
128 const int row = ND_id(n);
129 for (Agedge_t *e = agfstout(g, n); e; e = agnxtout(g, e)) {
130 I[i] = row;
131 J[i] = ND_id(aghead(e));
132
133 /* edge weight */
134 if (sym) {
135 if (sscanf(agxget(e, sym), "%lf", &v) != 1)
136 v = 1;
137 } else {
138 v = 1;
139 }
140 val[i] = v;
141
142 i++;
143 }
144 }
145
146 if ((psym = agattr_text(g, AGNODE, "pos", NULL))) {
147 bool has_positions = true;
148 char *pval;
149 *x = gv_calloc(DIM * nnodes, sizeof(double));
150 for (Agnode_t *n = agfstnode(g); n && has_positions; n = agnxtnode(g, n)) {
151 double xx, yy;
152 i = ND_id(n);
153 if ((pval = agxget(n, psym)) && *pval) {
154 const int nitems = sscanf(pval, "%lf,%lf", &xx, &yy);
155 if (nitems != 2) {
156 has_positions = false;
157 agerrorf("Node \"%s\" pos has %d < 2 values", agnameof(n), nitems);
158 }
159 (*x)[i * DIM] = xx;
160 (*x)[i * DIM + 1] = yy;
161 } else {
162 has_positions = false;
163 agerrorf("Node \"%s\" lacks position info", agnameof(n));
164 }
165 }
166 if (!has_positions) {
167 free(*x);
168 *x = NULL;
169 }
170 } else
171 agerrorf("Error: graph %s has missing \"pos\" information", agnameof(g));
172
173 size_t sz = sizeof(double);
174 if (format == FORMAT_CSR) {
175 assert(nnodes <= INT_MAX);
176 A = SparseMatrix_from_coordinate_arrays(nedges, nnodes, (int)nnodes, I, J,
177 val, type, sz);
178 }
179
180 if (format != FORMAT_COORD) {
181 free(I);
182 free(J);
183 free(val);
184 }
185
186 return A;
187}
188
189/* get spline info */
190int Import_dot_splines(Agraph_t *g, int *ne, char ***xsplines) {
191 /* get the list of splines for the edges in the order they appear, and store
192 as a list of strings in xspline. If *xsplines = NULL, it will be allocated.
193 On exit (*xsplines)[i] is the control point string for the i-th edge. This
194 string is of the form "x1,y1 x2,y2...", the two end points of the edge is
195 not included per Dot format Return 1 if success. 0 if not.
196 */
197 Agnode_t *n;
198 Agedge_t *e;
199 Agsym_t *sym;
200 int nedges;
201
202 if (!g) {
203 return 0;
204 }
205
206 *ne = nedges = agnedges(g);
207
208 /* Assign node ids */
209 int i = 0;
210 for (n = agfstnode(g); n; n = agnxtnode(g, n))
211 ND_id(n) = i++;
212
213 sym = agattr_text(g, AGEDGE, "pos", 0);
214 if (!sym)
215 return 0;
216
217 *xsplines = gv_calloc(nedges, sizeof(char *));
218
219 i = 0;
220 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
221 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
222 /* edge weight */
223 char *pos = agxget(e, sym);
224 (*xsplines)[i] = strdup(pos);
225 i++;
226 }
227 }
228 return 1;
229}
230
231static int hex2int(char h) {
232 if (h >= '0' && h <= '9')
233 return h - '0';
234 if (h >= 'a' && h <= 'f')
235 return 10 + h - 'a';
236 if (h >= 'A' && h <= 'F')
237 return 10 + h - 'A';
238 return 0;
239}
240
241static float hexcol2rgb(const char *h) {
242 return (float)(hex2int(h[0]) * 16 + hex2int(h[1])) / 255.0f;
243}
244
245void Dot_SetClusterColor(Agraph_t *g, float *rgb_r, float *rgb_g, float *rgb_b,
246 int *clusters) {
247
248 Agnode_t *n;
249 agxbuf scluster = {0};
250 Agsym_t *clust_clr_sym = agattr_text(g, AGNODE, "clustercolor", NULL);
251
252 if (!clust_clr_sym)
253 clust_clr_sym = agattr_text(g, AGNODE, "clustercolor", "-1");
254 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
255 const int i = ND_id(n);
256 if (rgb_r && rgb_g && rgb_b) {
257 rgb2hex(rgb_r[clusters[i]], rgb_g[clusters[i]], rgb_b[clusters[i]],
258 &scluster, NULL);
259 }
260 agxset(n, clust_clr_sym, agxbuse(&scluster));
261 }
262 agxbfree(&scluster);
263}
264
266 Agraph_t *g, int maxcluster, int *nn, double **label_sizes, double **x,
267 int **clusters, float **rgb_r, float **rgb_g, float **rgb_b,
268 int default_color_scheme, int clustering_scheme, int useClusters) {
269 const int dim = 2;
270 SparseMatrix A = 0;
271 Agnode_t *n;
272 Agedge_t *e;
273 Agsym_t *sym;
274 Agsym_t *clust_sym;
275 Agsym_t *clust_clr_sym;
276 int nnodes;
277 int nedges;
278 int i, row, ic, nc, j;
279 double v;
281
282 int MAX_GRPS, MIN_GRPS;
283 bool noclusterinfo = false;
284 bool first = true;
285 const float *pal;
286 int max_color = MAX_COLOR;
287
288 switch (default_color_scheme) {
290 pal = &palette_blue_to_yellow[0][0];
291 break;
293 pal = &palette_white_to_red[0][0];
294 break;
296 pal = &palette_grey_to_red[0][0];
297 break;
299 pal = &palette_grey[0][0];
300 break;
302 pal = &palette_pastel[0][0];
303 break;
306 break;
309 break;
311 pal = &palette_primary[0][0];
312 break;
314 pal = &palette_adam_blend[0][0];
315 break;
317 pal = &palette_adam[0][0];
318 max_color = 11;
319 break;
321 pal = NULL;
322 break;
323 default:
324 pal = &palette_pastel[0][0];
325 break;
326 }
327
328 if (!g)
329 return NULL;
330 nnodes = agnnodes(g);
331 nedges = agnedges(g);
332 *nn = nnodes;
333
334 /* Assign node ids */
335 i = 0;
336 for (n = agfstnode(g); n; n = agnxtnode(g, n))
337 ND_id(n) = i++;
338
339 /* form matrix */
340 int *I = gv_calloc(nedges, sizeof(int));
341 int *J = gv_calloc(nedges, sizeof(int));
342 double *val = gv_calloc(nedges, sizeof(double));
343
344 sym = agattr_text(g, AGEDGE, "weight", NULL);
345 clust_sym = agattr_text(g, AGNODE, "cluster", NULL);
346 clust_clr_sym = agattr_text(g, AGNODE, "clustercolor", NULL);
347 i = 0;
348 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
349 row = ND_id(n);
350 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
351 I[i] = row;
352 J[i] = ND_id(aghead(e));
353 if (sym) {
354 if (sscanf(agxget(e, sym), "%lf", &v) != 1)
355 v = 1;
356 } else
357 v = 1;
358 val[i] = v;
359 i++;
360 }
361 }
363 (size_t)nedges, (size_t)nnodes, nnodes, I, J, val, type, sizeof(double));
364
365 /* get clustering info */
366 *clusters = gv_calloc(nnodes, sizeof(int));
367 nc = 1;
368 MIN_GRPS = 0;
369 /* if useClusters, the nodes in each top-level cluster subgraph are assigned
370 * to clusters 2, 3, .... Any nodes not in a cluster subgraph are tossed into
371 * cluster 1.
372 */
373 if (useClusters) {
374 Agraph_t *sg;
375 int gid = 1;
376 memset(*clusters, 0, sizeof(int) * nnodes);
377 for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
378 if (!startswith(agnameof(sg), "cluster"))
379 continue;
380 gid++;
381 for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) {
382 i = ND_id(n);
383 if ((*clusters)[i])
384 fprintf(stderr, "Warning: node %s appears in multiple clusters.\n",
385 agnameof(n));
386 else
387 (*clusters)[i] = gid;
388 }
389 }
390 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
391 i = ND_id(n);
392 if ((*clusters)[i] == 0)
393 (*clusters)[i] = 1;
394 }
395 MIN_GRPS = 1;
396 nc = gid;
397 } else if (clust_sym) {
398 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
399 i = ND_id(n);
400 if (sscanf(agxget(n, clust_sym), "%d", &ic) > 0) {
401 if (ic < 0) {
402 fprintf(stderr, "WARNING: ignoring \"cluster\" attributes due to "
403 "negative value\n");
404 noclusterinfo = true;
405 break;
406 }
407 (*clusters)[i] = ic;
408 nc = MAX(nc, ic);
409 if (first) {
410 MIN_GRPS = ic;
411 first = false;
412 } else {
413 MIN_GRPS = MIN(MIN_GRPS, ic);
414 }
415 } else {
416 noclusterinfo = true;
417 break;
418 }
419 }
420 } else
421 noclusterinfo = true;
422 MAX_GRPS = nc;
423
424 if (noclusterinfo) {
425 double modularity;
426 if (!clust_sym)
427 clust_sym = agattr_text(g, AGNODE, "cluster", "-1");
428
429 if (clustering_scheme == CLUSTERING_MQ) {
430 mq_clustering(A, maxcluster, &nc, clusters, &modularity);
431 } else if (clustering_scheme == CLUSTERING_MODULARITY) {
432 modularity_clustering(A, false, maxcluster, &nc, clusters, &modularity);
433 } else {
434 UNREACHABLE();
435 }
436 for (i = 0; i < nnodes; i++)
437 (*clusters)[i]++; /* make into 1 based */
438 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
439 i = ND_id(n);
440 agxset(n, clust_sym, ITOS((*clusters)[i]));
441 }
442 MIN_GRPS = 1;
443 MAX_GRPS = nc;
444 if (Verbose) {
445 fprintf(stderr,
446 " no complement clustering info in dot file, using modularity "
447 "clustering. Modularity = %f, ncluster=%d\n",
448 modularity, nc);
449 }
450 }
451
452 *label_sizes = gv_calloc(dim * nnodes, sizeof(double));
453 if (pal || (!noclusterinfo && clust_clr_sym)) {
454 *rgb_r = gv_calloc(1 + MAX_GRPS, sizeof(float));
455 *rgb_g = gv_calloc(1 + MAX_GRPS, sizeof(float));
456 *rgb_b = gv_calloc(1 + MAX_GRPS, sizeof(float));
457 } else {
458 *rgb_r = NULL;
459 *rgb_g = NULL;
460 *rgb_b = NULL;
461 }
462
463 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
465 double sz;
466 i = ND_id(n);
467 if (agget(n, "width") && agget(n, "height")) {
468 sscanf(agget(n, "width"), "%lf", &sz);
469 (*label_sizes)[i * 2] = POINTS(sz * 0.5);
470 sscanf(agget(n, "height"), "%lf", &sz);
471 (*label_sizes)[i * 2 + 1] = POINTS(sz * 0.5);
472 } else {
473 (*label_sizes)[i * 2] = POINTS(0.75 / 2);
474 (*label_sizes)[i * 2 + 1] = POINTS(0.5 * 2);
475 }
476
477 j = (*clusters)[i];
478 if (MAX_GRPS - MIN_GRPS < max_color) {
479 j = (j - MIN_GRPS) *
480 ((int)((max_color - 1) / MAX((MAX_GRPS - MIN_GRPS), 1)));
481 } else {
482 j = (j - MIN_GRPS) % max_color;
483 }
484
485 if (pal) {
486 (*rgb_r)[(*clusters)[i]] = pal[3 * j + 0];
487 (*rgb_g)[(*clusters)[i]] = pal[3 * j + 1];
488 (*rgb_b)[(*clusters)[i]] = pal[3 * j + 2];
489 }
490
491 if (!noclusterinfo && clust_clr_sym &&
492 (colorxlate(agxget(n, clust_clr_sym), &color, RGBA_DOUBLE) ==
493 COLOR_OK)) {
494 (*rgb_r)[(*clusters)[i]] = (float)color.u.RGBA[0];
495 (*rgb_g)[(*clusters)[i]] = (float)color.u.RGBA[1];
496 (*rgb_b)[(*clusters)[i]] = (float)color.u.RGBA[2];
497 }
498
499 const char *cc = agget(n, "clustercolor");
500 if (!noclusterinfo && agget(n, "cluster") && cc && strlen(cc) >= 7 && pal) {
501 (*rgb_r)[(*clusters)[i]] = hexcol2rgb(cc + 1);
502 (*rgb_g)[(*clusters)[i]] = hexcol2rgb(cc + 3);
503 (*rgb_b)[(*clusters)[i]] = hexcol2rgb(cc + 5);
504 }
505 }
506
507 assert(x != NULL);
508 bool has_position = false;
509 *x = gv_calloc(dim * nnodes, sizeof(double));
510 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
511 double xx, yy;
512 i = ND_id(n);
513 if (agget(n, "pos")) {
514 has_position = true;
515 sscanf(agget(n, "pos"), "%lf,%lf", &xx, &yy);
516 (*x)[i * dim] = xx;
517 (*x)[i * dim + 1] = yy;
518 } else {
519 fprintf(stderr, "WARNING: pos field missing for node %d, set to origin\n",
520 i);
521 (*x)[i * dim] = 0;
522 (*x)[i * dim + 1] = 0;
523 }
524 }
525 if (!has_position) {
526 free(*x);
527 *x = NULL;
528 }
529
530 free(I);
531 free(J);
532 free(val);
533
534 return A;
535}
536
537void attached_clustering(Agraph_t *g, int maxcluster, int clustering_scheme) {
538 SparseMatrix A = 0;
539 Agnode_t *n;
540 Agedge_t *e;
541 Agsym_t *sym, *clust_sym;
542 int nnodes;
543 int nedges;
544 int i, row, nc;
545 double v;
547 size_t sz = sizeof(double);
548
549 if (!g)
550 return;
551 nnodes = agnnodes(g);
552 nedges = agnedges(g);
553
554 /* Assign node ids */
555 i = 0;
556 for (n = agfstnode(g); n; n = agnxtnode(g, n))
557 ND_id(n) = i++;
558
559 /* form matrix */
560 int *I = gv_calloc(nedges, sizeof(int));
561 int *J = gv_calloc(nedges, sizeof(int));
562 double *val = gv_calloc(nedges, sizeof(double));
563
564 sym = agattr_text(g, AGEDGE, "weight", NULL);
565 clust_sym = agattr_text(g, AGNODE, "cluster", NULL);
566
567 i = 0;
568 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
569 row = ND_id(n);
570 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
571 I[i] = row;
572 J[i] = ND_id(aghead(e));
573 if (sym) {
574 if (sscanf(agxget(e, sym), "%lf", &v) != 1)
575 v = 1;
576 } else
577 v = 1;
578 val[i] = v;
579 i++;
580 }
581 }
582 A = SparseMatrix_from_coordinate_arrays((size_t)nedges, (size_t)nnodes,
583 nnodes, I, J, val, type, sz);
584
585 int *clusters = gv_calloc(nnodes, sizeof(int));
586
587 {
588 double modularity;
589 if (!clust_sym)
590 clust_sym = agattr_text(g, AGNODE, "cluster", ITOS(NO_GROUP));
591
592 if (clustering_scheme == CLUSTERING_MQ) {
593 mq_clustering(A, maxcluster, &nc, &clusters, &modularity);
594 } else if (clustering_scheme == CLUSTERING_MODULARITY) {
595 modularity_clustering(A, false, maxcluster, &nc, &clusters, &modularity);
596 } else {
597 UNREACHABLE();
598 }
599 for (i = 0; i < nnodes; i++)
600 (clusters)[i]++; /* make into 1 based */
601 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
602 i = ND_id(n);
603 agxset(n, clust_sym, ITOS(clusters[i]));
604 }
605 if (Verbose) {
606 fprintf(stderr,
607 " no complement clustering info in dot file, using modularity "
608 "clustering. Modularity = %f, ncluster=%d\n",
609 modularity, nc);
610 }
611 }
612
613 free(I);
614 free(J);
615 free(val);
616 free(clusters);
617
619}
620
622 aginit(g, AGNODE, "info", sizeof(Agnodeinfo_t), true);
623}
624
625void setDotNodeID(Agnode_t *n, int v) { ND_id(n) = v; }
626
627int getDotNodeID(Agnode_t *n) { return ND_id(n); }
static void color_string(agxbuf *buf, size_t dim, double *color)
Definition DotIO.c:40
#define ND_id(n)
Definition DotIO.c:38
void Dot_SetClusterColor(Agraph_t *g, float *rgb_r, float *rgb_g, float *rgb_b, int *clusters)
Definition DotIO.c:245
SparseMatrix Import_coord_clusters_from_dot(Agraph_t *g, int maxcluster, int *nn, double **label_sizes, double **x, int **clusters, float **rgb_r, float **rgb_g, float **rgb_b, int default_color_scheme, int clustering_scheme, int useClusters)
Definition DotIO.c:265
int getDotNodeID(Agnode_t *n)
Definition DotIO.c:627
SparseMatrix SparseMatrix_import_dot(Agraph_t *g, double **x, int format)
Definition DotIO.c:91
void initDotIO(Agraph_t *g)
Definition DotIO.c:621
static float hexcol2rgb(const char *h)
Definition DotIO.c:241
void attach_edge_colors(Agraph_t *g, size_t dim, double *colors)
Definition DotIO.c:60
void setDotNodeID(Agnode_t *n, int v)
Definition DotIO.c:625
static int hex2int(char h)
Definition DotIO.c:231
void attached_clustering(Agraph_t *g, int maxcluster, int clustering_scheme)
Definition DotIO.c:537
int Import_dot_splines(Agraph_t *g, int *ne, char ***xsplines)
Definition DotIO.c:190
@ COLOR_SCHEME_ADAM_BLEND
Definition DotIO.h:30
@ COLOR_SCHEME_PASTEL
Definition DotIO.h:23
@ COLOR_SCHEME_ADAM
Definition DotIO.h:29
@ COLOR_SCHEME_GREY_RED
Definition DotIO.h:26
@ COLOR_SCHEME_SEQUENTIAL_SINGLEHUE_RED
Definition DotIO.h:28
@ COLOR_SCHEME_NONE
Definition DotIO.h:22
@ COLOR_SCHEME_SEQUENTIAL_SINGLEHUE_RED_LIGHTER
Definition DotIO.h:31
@ COLOR_SCHEME_GREY
Definition DotIO.h:32
@ COLOR_SCHEME_WHITE_RED
Definition DotIO.h:25
@ COLOR_SCHEME_PRIMARY
Definition DotIO.h:27
@ COLOR_SCHEME_BLUE_YELLOW
Definition DotIO.h:24
@ NO_GROUP
inherited the default (invalid) group
Definition DotIO.h:60
SparseMatrix SparseMatrix_new(size_t m, int n, size_t nz, int type, int format)
SparseMatrix SparseMatrix_from_coordinate_arrays(size_t nz, size_t m, int n, int *irn, int *jcn, const void *val, int type, size_t sz)
void SparseMatrix_delete(SparseMatrix A)
@ MATRIX_TYPE_REAL
@ FORMAT_COORD
@ FORMAT_CSR
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define MIN(a, b)
Definition arith.h:28
#define MAX(a, b)
Definition arith.h:33
abstract graph C library, Cgraph API
void modularity_clustering(SparseMatrix A, bool inplace, int ncluster_target, int *nclusters, int **assignment, double *modularity)
Definition clustering.c:343
@ CLUSTERING_MODULARITY
Definition clustering.h:39
@ CLUSTERING_MQ
Definition clustering.h:39
static bool useClusters
Definition ccomps.c:67
@ RGBA_DOUBLE
Definition color.h:27
#define COLOR_OK
Definition color.h:44
const float palette_sequential_singlehue_red[1001][3]
const float palette_grey[1001][3]
const float palette_sequential_singlehue_red_lighter[1001][3]
const float palette_blue_to_yellow[1001][3]
const float palette_grey_to_red[1001][3]
const float palette_adam[11][3]
const float palette_white_to_red[1001][3]
const float palette_adam_blend[1001][3]
const float palette_pastel[1001][3]
const float palette_primary[1001][3]
@ MAX_COLOR
void rgb2hex(float r, float g, float b, agxbuf *cstring, const char *opacity)
Definition colorutil.c:23
void colorxlate(char *str, agxbuf *buf)
Definition colxlate.c:48
expr procedure type
Definition exparse.y:208
#define A(n, t)
Definition expr.h:76
#define I
Definition expr.h:71
#define POINTS(a_inches)
Definition geom.h:62
static bool Verbose
Definition gml2gv.c:26
void free(void *)
node NULL
Definition grammar.y:181
int agnedges(Agraph_t *g)
Definition graph.c:165
int agnnodes(Agraph_t *g)
Definition graph.c:159
size_t agnnodes_z(const Agraph_t *g)
Definition graph.c:157
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:333
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:521
char * agget(void *obj, char *name)
Definition attr.c:447
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:457
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:28
#define aghead(e)
Definition cgraph.h:980
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:43
void agerrorf(const char *fmt,...)
Definition agerror.c:167
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:50
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:43
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:145
@ AGEDGE
Definition cgraph.h:207
@ AGNODE
Definition cgraph.h:207
void aginit(Agraph_t *g, int kind, const char *rec_name, int rec_size, int move_to_front)
attach new records to objects of specified kind
Definition rec.c:172
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:72
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:77
static uint64_t id
Definition gv2gml.c:42
static void color(Agraph_t *g)
Definition gvcolor.c:118
GVIO_API const char * format
Definition gvio.h:51
rows row
Definition htmlparse.y:320
#define ITOS(i)
Definition itos.h:43
void mq_clustering(SparseMatrix A, int maxcluster, int *nclusters, int **assignment, double *mq)
Definition mq.c:585
static const int dim
static int nedges
total no. of edges used in routing
Definition routespl.c:32
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
Definition startswith.h:11
graph or subgraph
Definition cgraph.h:424
implementation of Agrec_t
Definition cgraph.h:172
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:638
#define UNREACHABLE()
Definition unreachable.h:30