Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
gvmap.c
Go to the documentation of this file.
1
6/*************************************************************************
7 * Copyright (c) 2011 AT&T Intellectual Property
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License v1.0
10 * which accompanies this distribution, and is available at
11 * https://www.eclipse.org/legal/epl-v10.html
12 *
13 * Contributors: Details at https://graphviz.org
14 *************************************************************************/
15
16#include "config.h"
17#include "../tools/openFile.h"
18#include <stdbool.h>
19#include <stdio.h>
20#include <stdlib.h>
21#define STANDALONE
22#include <sparse/general.h>
23#include <sparse/QuadTree.h>
24#include <time.h>
25#include <sparse/SparseMatrix.h>
26#include <getopt.h>
27#include <string.h>
28#include "make_map.h"
31#include <neatogen/overlap.h>
32#include <sparse/clustering.h>
33#include <cgraph/ingraphs.h>
34#include <sparse/DotIO.h>
35#include <sparse/colorutil.h>
37#include <util/startswith.h>
38#include <util/unreachable.h>
39
40typedef struct {
41 char* cmd;
42 char **infiles;
43 FILE* outfile;
44 int dim;
46 int nrandom;
52 double line_width;
54 const char *opacity;
56 int nart;
59 int nedgep;
60 const char *line_color;
63 int seed; /* seed used to calculate Fiedler vector */
64} params_t;
65
66static const char usestr[] =
67" where graphfile must contain node positions, and widths and heights for each node. No overlap between nodes should be present. Acceptable options are: \n\
68 -a k - average number of artificial points added along the bounding box of the labels. If < 0, a suitable value is selected automatically. (-1)\n\
69 -b v - polygon line width, with v < 0 for no line. (0)\n\
70 -c k - polygon color scheme (1)\n\
71 0 : no polygons\n\
72 1 : pastel (default)\n\
73 2 : blue to yellow\n\
74 3 : white to red\n\
75 4 : light grey to red\n\
76 5 : primary colors\n\
77 6 : sequential single hue red \n\
78 7 : Adam color scheme\n\
79 8 : Adam blend\n\
80 9 : sequential single hue lighter red \n\
81 10 : light grey\n\
82 -c_opacity=xx - 2-character hex string for opacity of polygons\n\
83 -C k - generate at most k clusters. (0)\n\
84 -d s - seed used to calculate Fiedler vector for optimal coloring\n\
85 -D - use top-level cluster subgraphs to specify clustering\n\
86 -e - show edges\n\
87 -g c - bounding box color. If not specified, a bounding box is not drawn.\n\
88 -h k - number of artificial points added to maintain bridge between endpoints (0)\n\
89 -highlight=k - only draw cluster k\n\
90 -k - increase randomness of boundary\n\
91 -l s - specify label\n\
92 -m v - bounding box margin. If 0, auto-assigned (0)\n\
93 -o <file> - put output in <file> (stdout)\n\
94 -O - do NOT do color assignment optimization that maximizes color difference between neighboring countries\n\
95 -p k - ignored\n\
96 -r k - number of random points k used to define sea and lake boundaries. If 0, auto assigned. (0)\n\
97 -s v - depth of the sea and lake shores in points. If < 0, auto assigned. (0)\n\
98 -t n - improve contiguity up to n times. (0)\n\
99 -v - verbose\n\
100 -z c - polygon line color (black)\n";
101
102/*
103
104 -q f - output format (3)\n\
105 0 : Mathematica\n\
106 1 : PostScript\n\
107 2 : country map\n\
108 3 : dot format\n\
109*/
110 /* e.g.,
111 1 [cluster=10, clustercolor="#ff0000"]
112 2 [cluster=10]
113 (and no other nodes are in cluster10)
114
115 then since we can only use 1 color for the cluster 10, both 1 and 2 will be colored based on the color of node 2. However if you have
116
117 2 [cluster=10]
118 1 [cluster=10, clustercolor="#ff0000"]
119
120 then you get both colored red.
121
122 */
123
124static void usage(char* cmd, int eval)
125{
126 fprintf(stderr, "Usage: %s <options> graphfile\n", cmd);
127 fputs (usestr, stderr);
129}
130
131#define HLPFX "ighlight="
132#define N_HLPFX (sizeof(HLPFX)-1)
133
134static void
135init(int argc, char **argv, params_t* pm)
136{
137 char* cmd = argv[0];
138 int c;
139 double s;
140 int v, r;
141 char stmp[3]; /* two character string plus '\0' */
142
143 pm->outfile = NULL;
144 pm->opacity = NULL;
146 pm->nrandom = -1;
147 pm->dim = 2;
148 pm->shore_depth_tol = 0;
149 pm->highlight_cluster = 0;
150 pm->useClusters = 0;
152 pm->plotedges = false;
154 pm->line_width = 0;
155 pm->improve_contiguity_n = 0;
156 pm->nart = -1;
157 pm->color_optimize = true;
158 pm->maxcluster = 0;
159 pm->nedgep = 0;
160
161 pm->cmd = cmd;
162 pm->infiles = NULL;
163 pm->line_color = "#000000";
164 pm->include_OK_points = false;
165 pm->seed = 123;
166
167 pm->bbox_margin = 0;
168
169 opterr = 0;
170 while ((c = getopt(argc, argv, ":evODQko:m:s:r:p:c:C:l:b:g:t:a:h:z:d:?")) != -1) {
171 switch (c) {
172 case 'm':
173 if (sscanf(optarg, "%lf", &s) > 0 && s != 0) {
174 pm->bbox_margin = s;
175 } else {
176 usage(cmd, 1);
177 }
178 break;
179 case 'Q':
181 break;
182 case 's':
183 if (sscanf(optarg, "%lf", &s) > 0) {
184 pm->shore_depth_tol = s;
185 } else {
186 usage(cmd,1);
187 }
188 break;
189 case 'h':
190 if (sscanf(optarg, "%d", &v) > 0) {
191 pm->nedgep = MAX(0, v);
192 } else if (startswith(optarg, HLPFX) &&
193 sscanf(optarg + N_HLPFX, "%d", &v) > 0) {
194 pm->highlight_cluster = MAX(0, v);
195 } else {
196 usage(cmd,1);
197 }
198 break;
199 case 'r':
200 if (sscanf(optarg, "%d", &r) > 0) {
201 pm->nrandom = r;
202 }
203 break;
204 case 't':
205 if (sscanf(optarg, "%d", &r) > 0 && r > 0) {
206 pm->improve_contiguity_n = r;
207 }
208 break;
209 case 'p': // ignored
210 break;
211 case 'k':
212 pm->include_OK_points = true;
213 break;
214 case 'v':
215 Verbose = 1;
216 break;
217 case 'D':
218 pm->useClusters = 1;
219 break;
220 case 'e':
221 pm->plotedges = true;
222 break;
223 case 'o':
224 pm->outfile = openFile(pm->cmd, optarg, "w");
225 break;
226 case 'O':
227 pm->color_optimize = false;
228 break;
229 case 'a':
230 if (sscanf(optarg, "%d", &r) > 0) {
231 pm->nart = r;
232 } else {
233 usage(cmd,1);
234 }
235 break;
236 case 'c':
237 if (sscanf(optarg,"_opacity=%2s", stmp) > 0 && strlen(stmp) == 2){
238 pm->opacity = stmp;
239 } else if (sscanf(optarg, "%d", &r) > 0 && r >= COLOR_SCHEME_NONE &&
240 r <= COLOR_SCHEME_GREY) {
241 pm->color_scheme = r;
242 } else if (knownColorScheme(optarg)) {
244 pm->color_scheme_str = optarg;
245 } else {
246 fprintf(stderr,"-c option %s is invalid, must be a valid integer or string\n", optarg);
247 usage(cmd, 1);
248 }
249 break;
250 case 'd':
251 if (sscanf(optarg,"%d",&v) <= 0){
252 usage(cmd,1);
253 }
254 else
255 pm->seed = v;
256 break;
257 case 'C':
258 if (!(sscanf(optarg, "%d", &v) > 0 && v >= 0)) {
259 usage(cmd,1);
260 }
261 else
262 pm->maxcluster = v;
263 break;
264 case 'g':
265 // ignored
266 break;
267 case 'z': {
268 pm->line_color = optarg;
269 break;
270 }
271 case 'b':
272 if (sscanf(optarg,"%lf",&s) > 0) {
273 pm->line_width = s;
274 } else {
275 fprintf (stderr, "%s: unexpected argument \"%s\" for -b flag\n", cmd, optarg);
276 }
277 break;
278 case 'l':
279 // ignored
280 break;
281 case ':':
282 fprintf(stderr, "gvpack: option -%c missing argument - ignored\n", optopt);
283 break;
284 case '?':
285 if (optopt == '\0' || optopt == '?')
286 usage(cmd, 0);
287 else {
288 fprintf(stderr, " option -%c unrecognized\n", optopt);
289 usage(cmd, 1);
290 }
291 break;
292 default:
293 UNREACHABLE();
294 }
295 }
296
297 argv += optind;
298 argc -= optind;
299 if (argc)
300 pm->infiles = argv;
301 if (!pm->outfile)
302 pm->outfile = stdout;
303}
304
305static int
306validateCluster (int n, int* grouping, int clust_num)
307{
308 int i;
309 for (i = 0; i < n; i++) {
310 if (grouping[i] == clust_num) return clust_num;
311 }
312 fprintf (stderr, "Highlighted cluster %d not found - ignored\n", clust_num);
313 return 0;
314}
315
317static int makeMap(SparseMatrix graph, int n, double *x, double *width,
318 int *grouping, char **labels, float *fsz, float *rgb_r,
319 float *rgb_g, float *rgb_b, params_t *pm, Agraph_t *g) {
320 int dim = pm->dim;
321 int i;
322 SparseMatrix poly_lines, polys, poly_point_map;
323 int nverts, *polys_groups;
324 double *x_poly;
325 SparseMatrix country_graph;
326 int improve_contiguity_n = pm->improve_contiguity_n;
327#ifdef TIME
328 clock_t cpu;
329#endif
330 int nart0;
331 int nart, nrandom;
332
333#ifdef TIME
334 cpu = clock();
335#endif
336 nrandom = pm->nrandom; nart0 = nart = pm->nart;
337 if (pm->highlight_cluster) {
338 pm->highlight_cluster = validateCluster (n, grouping, pm->highlight_cluster);
339 }
341 grouping, graph, pm->bbox_margin, nrandom,
342 &nart, pm->nedgep, pm->shore_depth_tol,
343 &nverts, &x_poly, &poly_lines, &polys,
344 &polys_groups, &poly_point_map,
345 &country_graph, pm->highlight_cluster)
346 != 0) {
347 return -1;
348 }
349
350 if (Verbose) fprintf(stderr,"nart = %d\n",nart);
351 /* compute a good color permutation */
352 if (pm->color_optimize && country_graph && rgb_r && rgb_g && rgb_b)
353 map_optimal_coloring(pm->seed, country_graph, rgb_r, rgb_g, rgb_b);
354 else if (pm->color_scheme_str){
356 &rgb_r, &rgb_g, &rgb_b);
357 }
358
359#ifdef TIME
360 fprintf(stderr, "map making time = %f\n",((double) (clock() - cpu)) / CLOCKS_PER_SEC);
361#endif
362
363
364 /* now we check to see if all points in the same group are also in the same polygon, if not, the map is not very
365 contiguous so we move point positions to improve contiguity */
366 if (graph && improve_contiguity_n) {
367 for (i = 0; i < improve_contiguity_n; i++){
368 improve_contiguity(n, dim, grouping, poly_point_map, x, graph);
369 nart = nart0;
371 n, dim, x, width, grouping, graph, pm->bbox_margin, nrandom, &nart, pm->nedgep,
372 pm->shore_depth_tol, &nverts, &x_poly, &poly_lines,
373 &polys, &polys_groups, &poly_point_map, &country_graph, pm->highlight_cluster);
374 }
375 {
377 remove_overlap(dim, D, x, width, 1000, 5000.,
378 ELSCHEME_NONE, 0, NULL, NULL, true);
380
381 nart = nart0;
383 n, dim, x, width, grouping, graph, pm->bbox_margin, nrandom, &nart, pm->nedgep,
384 pm->shore_depth_tol, &nverts, &x_poly, &poly_lines,
385 &polys, &polys_groups, &poly_point_map, &country_graph, pm->highlight_cluster);
386 }
387
388 }
389
390 Dot_SetClusterColor(g, rgb_r, rgb_g, rgb_b, grouping);
391 plot_dot_map(g, n, dim, x, polys, poly_lines, pm->line_width, pm->line_color, x_poly, polys_groups, labels, fsz, rgb_r, rgb_g, rgb_b, pm->opacity,
392 (pm->plotedges?graph:NULL), pm->outfile);
393 SparseMatrix_delete(polys);
394 SparseMatrix_delete(poly_lines);
395 SparseMatrix_delete(poly_point_map);
396 free(x_poly);
397 free(polys_groups);
398 return 0;
399}
400
402static int mapFromGraph(Agraph_t *g, params_t *pm) {
404 int n;
405 double* width = NULL;
406 double* x;
407 char** labels = NULL;
408 int* grouping;
409 float* rgb_r = NULL;
410 float* rgb_g = NULL;
411 float* rgb_b = NULL;
412 float* fsz;
413
414 initDotIO(g);
415 graph = Import_coord_clusters_from_dot(g, pm->maxcluster, pm->dim, &n, &width, &x, &grouping,
416 &rgb_r, &rgb_g, &rgb_b, &fsz, &labels, pm->color_scheme, pm->clusterMethod, pm->useClusters);
417 const int rc = makeMap(graph, n, x, width, grouping, labels, fsz, rgb_r,
418 rgb_g, rgb_b, pm, g);
419 free(rgb_r);
420 free(rgb_g);
421 free(rgb_b);
422 return rc;
423}
424
425int main(int argc, char *argv[])
426{
427 params_t pm;
428 Agraph_t* g;
429 Agraph_t* prevg = NULL;
430 ingraph_state ig;
431
432 init(argc, argv, &pm);
433
434 newIngraph(&ig, pm.infiles);
435 while ((g = nextGraph (&ig)) != 0) {
436 if (prevg) agclose (prevg);
437 if (mapFromGraph(g, &pm) != 0) {
438 graphviz_exit(EXIT_FAILURE);
439 }
440 prevg = g;
441 }
442
443 graphviz_exit(0);
444}
445
void Dot_SetClusterColor(Agraph_t *g, float *rgb_r, float *rgb_g, float *rgb_b, int *clusters)
Definition DotIO.c:268
void initDotIO(Agraph_t *g)
Definition DotIO.c:652
SparseMatrix Import_coord_clusters_from_dot(Agraph_t *g, int maxcluster, int dim, int *nn, double **label_sizes, double **x, int **clusters, float **rgb_r, float **rgb_g, float **rgb_b, float **fsz, char ***labels, int default_color_scheme, int clustering_scheme, int useClusters)
Definition DotIO.c:287
@ COLOR_SCHEME_PASTEL
Definition DotIO.h:20
@ COLOR_SCHEME_NONE
Definition DotIO.h:20
@ COLOR_SCHEME_GREY
Definition DotIO.h:20
void SparseMatrix_delete(SparseMatrix A)
SparseMatrix SparseMatrix_get_real_adjacency_matrix_symmetrized(SparseMatrix A)
@ CLUSTERING_MODULARITY
Definition clustering.h:39
@ CLUSTERING_MQ
Definition clustering.h:39
static char * cmd
Definition acyclic.c:40
bool knownColorScheme(const char *name)
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
static int eval(Agraph_t *g, int root)
Definition gc.c:270
static bool Verbose
Definition gml2gv.c:23
void free(void *)
node NULL
Definition grammar.y:163
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:102
Agraph_t * graph(char *name)
Definition gv.cpp:30
static void init(int argc, char **argv, params_t *pm)
Definition gvmap.c:135
static const char usestr[]
Definition gvmap.c:66
#define N_HLPFX
Definition gvmap.c:132
static int mapFromGraph(Agraph_t *g, params_t *pm)
Definition gvmap.c:402
static int validateCluster(int n, int *grouping, int clust_num)
Definition gvmap.c:306
#define HLPFX
Definition gvmap.c:131
static int makeMap(SparseMatrix graph, int n, double *x, double *width, int *grouping, char **labels, float *fsz, float *rgb_r, float *rgb_g, float *rgb_b, params_t *pm, Agraph_t *g)
Definition gvmap.c:317
static const char * usage
Definition gvpr.c:51
#define D
Definition hierarchy.c:119
Agraph_t * nextGraph(ingraph_state *sp)
Definition ingraphs.c:61
ingraph_state * newIngraph(ingraph_state *sp, char **files)
Definition ingraphs.c:140
supports user-supplied data
void map_palette_optimal_coloring(char *color_scheme, SparseMatrix A0, float **rgb_r, float **rgb_g, float **rgb_b)
Definition make_map.c:34
int make_map_from_rectangle_groups(bool include_OK_points, int n, int dim, double *x, double *sizes, int *grouping, SparseMatrix graph, double bounding_box_margin, int nrandom, int *nart, int nedgep, double shore_depth_tol, int *nverts, double **x_poly, SparseMatrix *poly_lines, SparseMatrix *polys, int **polys_groups, SparseMatrix *poly_point_map, SparseMatrix *country_graph, int highlight_cluster)
Definition make_map.c:1231
void map_optimal_coloring(int seed, SparseMatrix A, float *rgb_r, float *rgb_g, float *rgb_b)
Definition make_map.c:93
void plot_dot_map(Agraph_t *gr, int n, int dim, double *x, SparseMatrix polys, SparseMatrix poly_lines, double line_width, const char *line_color, double *x_poly, int *polys_groups, char **labels, float *fsz, float *r, float *g, float *b, const char *opacity, SparseMatrix A, FILE *f)
Definition make_map.c:326
void improve_contiguity(int n, int dim, int *grouping, SparseMatrix poly_point_map, double *x, SparseMatrix graph)
Definition make_map.c:115
static const int dim
static FILE * openFile(const char *argv0, const char *name, const char *mode)
Definition openFile.h:8
void remove_overlap(int dim, SparseMatrix A, double *x, double *label_sizes, int ntry, double initial_scaling, int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes, SparseMatrix A_constr, bool do_shrinking)
Definition overlap.c:584
@ ELSCHEME_NONE
Definition overlap.h:29
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:425
char * color_scheme_str
Definition gvmap.c:53
const char * line_color
Definition gvmap.c:60
int highlight_cluster
Definition gvmap.c:62
int clusterMethod
Definition gvmap.c:49
int dim
Definition gvmap.c:44
int color_scheme
Definition gvmap.c:51
bool color_optimize
Definition gvmap.c:57
char * cmd
Definition gvmap.c:41
bool plotedges
Definition gvmap.c:50
int useClusters
Definition gvmap.c:48
int nrandom
Definition gvmap.c:46
char ** infiles
Definition gvmap.c:42
double shore_depth_tol
Definition gvmap.c:45
int nart
Definition gvmap.c:56
const char * opacity
Definition gvmap.c:54
double bbox_margin
Definition gvmap.c:47
int improve_contiguity_n
Definition gvmap.c:55
FILE * outfile
Definition gvmap.c:43
int maxcluster
Definition gvmap.c:58
int nedgep
Definition gvmap.c:59
int seed
Definition gvmap.c:63
bool include_OK_points
Definition gvmap.c:61
double line_width
Definition gvmap.c:52
int main()
Definition grammar.c:93
#define UNREACHABLE()
Definition unreachable.h:30
#define MAX(a, b)
Definition write.c:31