Graphviz 14.1.2~dev.20260111.0532
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 char opacity[3];
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
142 pm->outfile = NULL;
143 pm->opacity[0] = '\0';
145 pm->nrandom = -1;
146 pm->dim = 2;
147 pm->shore_depth_tol = 0;
148 pm->highlight_cluster = 0;
149 pm->useClusters = 0;
151 pm->plotedges = false;
153 pm->line_width = 0;
154 pm->improve_contiguity_n = 0;
155 pm->nart = -1;
156 pm->color_optimize = true;
157 pm->maxcluster = 0;
158 pm->nedgep = 0;
159
160 pm->cmd = cmd;
161 pm->infiles = NULL;
162 pm->line_color = "#000000";
163 pm->include_OK_points = false;
164 pm->seed = 123;
165
166 pm->bbox_margin = 0;
167
168 opterr = 0;
169 while ((c = getopt(argc, argv, ":evODQko:m:s:r:p:c:C:l:b:g:t:a:h:z:d:?")) != -1) {
170 switch (c) {
171 case 'm':
172 if (sscanf(optarg, "%lf", &s) > 0 && s != 0) {
173 pm->bbox_margin = s;
174 } else {
175 usage(cmd, 1);
176 }
177 break;
178 case 'Q':
180 break;
181 case 's':
182 if (sscanf(optarg, "%lf", &s) > 0) {
183 pm->shore_depth_tol = s;
184 } else {
185 usage(cmd,1);
186 }
187 break;
188 case 'h':
189 if (sscanf(optarg, "%d", &v) > 0) {
190 pm->nedgep = MAX(0, v);
191 } else if (startswith(optarg, HLPFX) &&
192 sscanf(optarg + N_HLPFX, "%d", &v) > 0) {
193 pm->highlight_cluster = MAX(0, v);
194 } else {
195 usage(cmd,1);
196 }
197 break;
198 case 'r':
199 if (sscanf(optarg, "%d", &r) > 0) {
200 pm->nrandom = r;
201 }
202 break;
203 case 't':
204 if (sscanf(optarg, "%d", &r) > 0 && r > 0) {
205 pm->improve_contiguity_n = r;
206 }
207 break;
208 case 'p': // ignored
209 break;
210 case 'k':
211 pm->include_OK_points = true;
212 break;
213 case 'v':
214 Verbose = 1;
215 break;
216 case 'D':
217 pm->useClusters = 1;
218 break;
219 case 'e':
220 pm->plotedges = true;
221 break;
222 case 'o':
223 pm->outfile = openFile(pm->cmd, optarg, "w");
224 break;
225 case 'O':
226 pm->color_optimize = false;
227 break;
228 case 'a':
229 if (sscanf(optarg, "%d", &r) > 0) {
230 pm->nart = r;
231 } else {
232 usage(cmd,1);
233 }
234 break;
235 case 'c': {
236 char stmp[3]; // two character string plus '\0'
237 if (sscanf(optarg,"_opacity=%2s", stmp) > 0 && strlen(stmp) == 2){
238 memcpy(pm->opacity, stmp, sizeof(pm->opacity));
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 }
251 case 'd':
252 if (sscanf(optarg,"%d",&v) <= 0){
253 usage(cmd,1);
254 }
255 else
256 pm->seed = v;
257 break;
258 case 'C':
259 if (!(sscanf(optarg, "%d", &v) > 0 && v >= 0)) {
260 usage(cmd,1);
261 }
262 else
263 pm->maxcluster = v;
264 break;
265 case 'g':
266 // ignored
267 break;
268 case 'z': {
269 pm->line_color = optarg;
270 break;
271 }
272 case 'b':
273 if (sscanf(optarg,"%lf",&s) > 0) {
274 pm->line_width = s;
275 } else {
276 fprintf (stderr, "%s: unexpected argument \"%s\" for -b flag\n", cmd, optarg);
277 }
278 break;
279 case 'l':
280 // ignored
281 break;
282 case ':':
283 fprintf(stderr, "gvpack: option -%c missing argument - ignored\n", optopt);
284 break;
285 case '?':
286 if (optopt == '\0' || optopt == '?')
287 usage(cmd, 0);
288 else {
289 fprintf(stderr, " option -%c unrecognized\n", optopt);
290 usage(cmd, 1);
291 }
292 break;
293 default:
294 UNREACHABLE();
295 }
296 }
297
298 argv += optind;
299 argc -= optind;
300 if (argc)
301 pm->infiles = argv;
302 if (!pm->outfile)
303 pm->outfile = stdout;
304}
305
306static int
307validateCluster (int n, int* grouping, int clust_num)
308{
309 int i;
310 for (i = 0; i < n; i++) {
311 if (grouping[i] == clust_num) return clust_num;
312 }
313 fprintf (stderr, "Highlighted cluster %d not found - ignored\n", clust_num);
314 return 0;
315}
316
318static int makeMap(SparseMatrix graph, int n, double *x, double *width,
319 int *grouping, char **labels, float *fsz, float *rgb_r,
320 float *rgb_g, float *rgb_b, params_t *pm, Agraph_t *g) {
321 int dim = pm->dim;
322 int i;
323 SparseMatrix poly_lines, polys, poly_point_map;
324 int nverts, *polys_groups;
325 double *x_poly;
326 SparseMatrix country_graph;
327 int improve_contiguity_n = pm->improve_contiguity_n;
328#ifdef TIME
329 clock_t cpu;
330#endif
331 int nart0;
332 int nart, nrandom;
333
334#ifdef TIME
335 cpu = clock();
336#endif
337 nrandom = pm->nrandom; nart0 = nart = pm->nart;
338 if (pm->highlight_cluster) {
339 pm->highlight_cluster = validateCluster (n, grouping, pm->highlight_cluster);
340 }
342 grouping, graph, pm->bbox_margin, nrandom,
343 &nart, pm->nedgep, pm->shore_depth_tol,
344 &nverts, &x_poly, &poly_lines, &polys,
345 &polys_groups, &poly_point_map,
346 &country_graph, pm->highlight_cluster)
347 != 0) {
348 return -1;
349 }
350
351 if (Verbose) fprintf(stderr,"nart = %d\n",nart);
352 /* compute a good color permutation */
353 if (pm->color_optimize && country_graph && rgb_r && rgb_g && rgb_b)
354 map_optimal_coloring(pm->seed, country_graph, rgb_r, rgb_g, rgb_b);
355 else if (pm->color_scheme_str){
357 &rgb_r, &rgb_g, &rgb_b);
358 }
359
360#ifdef TIME
361 fprintf(stderr, "map making time = %f\n",((double) (clock() - cpu)) / CLOCKS_PER_SEC);
362#endif
363
364
365 /* 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
366 contiguous so we move point positions to improve contiguity */
367 if (graph && improve_contiguity_n) {
368 for (i = 0; i < improve_contiguity_n; i++){
369 improve_contiguity(n, dim, grouping, poly_point_map, x, graph);
370 nart = nart0;
372 n, dim, x, width, grouping, graph, pm->bbox_margin, nrandom, &nart, pm->nedgep,
373 pm->shore_depth_tol, &nverts, &x_poly, &poly_lines,
374 &polys, &polys_groups, &poly_point_map, &country_graph, pm->highlight_cluster);
375 }
376 {
378 remove_overlap(dim, D, x, width, 1000, 5000.,
379 ELSCHEME_NONE, 0, NULL, NULL, true);
381
382 nart = nart0;
384 n, dim, x, width, grouping, graph, pm->bbox_margin, nrandom, &nart, pm->nedgep,
385 pm->shore_depth_tol, &nverts, &x_poly, &poly_lines,
386 &polys, &polys_groups, &poly_point_map, &country_graph, pm->highlight_cluster);
387 }
388
389 }
390
391 Dot_SetClusterColor(g, rgb_r, rgb_g, rgb_b, grouping);
392 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,
393 (pm->plotedges?graph:NULL), pm->outfile);
394 SparseMatrix_delete(polys);
395 SparseMatrix_delete(poly_lines);
396 SparseMatrix_delete(poly_point_map);
397 free(x_poly);
398 free(polys_groups);
399 return 0;
400}
401
403static int mapFromGraph(Agraph_t *g, params_t *pm) {
405 int n;
406 double* width = NULL;
407 double* x;
408 char** labels = NULL;
409 int* grouping;
410 float* rgb_r = NULL;
411 float* rgb_g = NULL;
412 float* rgb_b = NULL;
413 float* fsz;
414
415 initDotIO(g);
416 graph = Import_coord_clusters_from_dot(g, pm->maxcluster, pm->dim, &n, &width, &x, &grouping,
417 &rgb_r, &rgb_g, &rgb_b, &fsz, &labels, pm->color_scheme, pm->clusterMethod, pm->useClusters);
418 const int rc = makeMap(graph, n, x, width, grouping, labels, fsz, rgb_r,
419 rgb_g, rgb_b, pm, g);
420 free(rgb_r);
421 free(rgb_g);
422 free(rgb_b);
423 return rc;
424}
425
426int main(int argc, char *argv[])
427{
428 params_t pm;
429 Agraph_t* g;
430 Agraph_t* prevg = NULL;
431 ingraph_state ig;
432
433 init(argc, argv, &pm);
434
435 newIngraph(&ig, pm.infiles);
436 while ((g = nextGraph (&ig)) != 0) {
437 if (prevg) agclose (prevg);
438 if (mapFromGraph(g, &pm) != 0) {
439 graphviz_exit(EXIT_FAILURE);
440 }
441 prevg = g;
442 }
443
444 graphviz_exit(0);
445}
446
void Dot_SetClusterColor(Agraph_t *g, float *rgb_r, float *rgb_g, float *rgb_b, int *clusters)
Definition DotIO.c:273
void initDotIO(Agraph_t *g)
Definition DotIO.c:653
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:292
@ 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)
#define MAX(a, b)
Definition arith.h:33
@ 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:269
static bool Verbose
Definition gml2gv.c:24
void free(void *)
node NULL
Definition grammar.y:181
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:95
Agraph_t * graph(char *name)
Definition gv.cpp:32
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:403
static int validateCluster(int n, int *grouping, int clust_num)
Definition gvmap.c:307
#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:318
static const char * usage
Definition gvpr.c:52
#define D
Definition hierarchy.c:120
Agraph_t * nextGraph(ingraph_state *sp)
Definition ingraphs.c:59
ingraph_state * newIngraph(ingraph_state *sp, char **files)
Definition ingraphs.c:138
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:36
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:1233
void map_optimal_coloring(int seed, SparseMatrix A, float *rgb_r, float *rgb_g, float *rgb_b)
Definition make_map.c:95
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:327
void improve_contiguity(int n, int dim, int *grouping, SparseMatrix poly_point_map, double *x, SparseMatrix graph)
Definition make_map.c:117
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:586
@ ELSCHEME_NONE
Definition overlap.h:30
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
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
char opacity[3]
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:90
#define UNREACHABLE()
Definition unreachable.h:30