Graphviz 12.0.1~dev.20240716.0800
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 <cgraph/unreachable.h>
19#include <stdbool.h>
20#include <stdio.h>
21#include <stdlib.h>
22#define STANDALONE
23#include <sparse/general.h>
24#include <sparse/QuadTree.h>
25#include <time.h>
26#include <sparse/SparseMatrix.h>
27#include <getopt.h>
28#include <string.h>
29#include "make_map.h"
32#include <neatogen/overlap.h>
33#include <sparse/clustering.h>
34#include <cgraph/ingraphs.h>
35#include <cgraph/startswith.h>
36#include <sparse/DotIO.h>
37#include <sparse/colorutil.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
316static void
317makeMap (SparseMatrix graph, int n, double* x, double* width, int* grouping,
318 char** labels, float* fsz, float* rgb_r, float* rgb_g, float* rgb_b, params_t* pm, Agraph_t* g )
319{
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 n, dim, x, width, grouping, graph, pm->bbox_margin, nrandom, &nart, pm->nedgep,
342 pm->shore_depth_tol, &nverts, &x_poly, &poly_lines,
343 &polys, &polys_groups, &poly_point_map, &country_graph, pm->highlight_cluster);
344
345 if (Verbose) fprintf(stderr,"nart = %d\n",nart);
346 /* compute a good color permutation */
347 if (pm->color_optimize && country_graph && rgb_r && rgb_g && rgb_b)
348 map_optimal_coloring(pm->seed, country_graph, rgb_r, rgb_g, rgb_b);
349 else if (pm->color_scheme_str){
351 &rgb_r, &rgb_g, &rgb_b);
352 }
353
354#ifdef TIME
355 fprintf(stderr, "map making time = %f\n",((double) (clock() - cpu)) / CLOCKS_PER_SEC);
356#endif
357
358
359 /* 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
360 contiguous so we move point positions to improve contiguity */
361 if (graph && improve_contiguity_n) {
362 for (i = 0; i < improve_contiguity_n; i++){
363 improve_contiguity(n, dim, grouping, poly_point_map, x, graph);
364 nart = nart0;
366 n, dim, x, width, grouping, graph, pm->bbox_margin, nrandom, &nart, pm->nedgep,
367 pm->shore_depth_tol, &nverts, &x_poly, &poly_lines,
368 &polys, &polys_groups, &poly_point_map, &country_graph, pm->highlight_cluster);
369 }
370 {
372 remove_overlap(dim, D, x, width, 1000, 5000.,
373 ELSCHEME_NONE, 0, NULL, NULL, true);
375
376 nart = nart0;
378 n, dim, x, width, grouping, graph, pm->bbox_margin, nrandom, &nart, pm->nedgep,
379 pm->shore_depth_tol, &nverts, &x_poly, &poly_lines,
380 &polys, &polys_groups, &poly_point_map, &country_graph, pm->highlight_cluster);
381 }
382
383 }
384
385 Dot_SetClusterColor(g, rgb_r, rgb_g, rgb_b, grouping);
386 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,
387 (pm->plotedges?graph:NULL), pm->outfile);
388 SparseMatrix_delete(polys);
389 SparseMatrix_delete(poly_lines);
390 SparseMatrix_delete(poly_point_map);
391 free(x_poly);
392 free(polys_groups);
393}
394
395
396static void mapFromGraph (Agraph_t* g, params_t* pm)
397{
399 int n;
400 double* width = NULL;
401 double* x;
402 char** labels = NULL;
403 int* grouping;
404 float* rgb_r = NULL;
405 float* rgb_g = NULL;
406 float* rgb_b = NULL;
407 float* fsz;
408
409 initDotIO(g);
410 graph = Import_coord_clusters_from_dot(g, pm->maxcluster, pm->dim, &n, &width, &x, &grouping,
411 &rgb_r, &rgb_g, &rgb_b, &fsz, &labels, pm->color_scheme, pm->clusterMethod, pm->useClusters);
412 makeMap (graph, n, x, width, grouping, labels, fsz, rgb_r, rgb_g, rgb_b, pm, g);
413 free(rgb_r);
414 free(rgb_g);
415 free(rgb_b);
416}
417
418int main(int argc, char *argv[])
419{
420 params_t pm;
421 Agraph_t* g;
422 Agraph_t* prevg = NULL;
423 ingraph_state ig;
424
425 init(argc, argv, &pm);
426
427 newIngraph(&ig, pm.infiles);
428 while ((g = nextGraph (&ig)) != 0) {
429 if (prevg) agclose (prevg);
430 mapFromGraph (g, &pm);
431 prevg = g;
432 }
433
434 graphviz_exit(0);
435}
436
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:654
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
int 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 int Verbose
Definition gml2gv.c:22
void free(void *)
node NULL
Definition grammar.y:149
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:96
Agraph_t * graph(char *name)
Definition gv.cpp:31
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 void 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 int validateCluster(int n, int *grouping, int clust_num)
Definition gvmap.c:306
#define HLPFX
Definition gvmap.c:131
static void mapFromGraph(Agraph_t *g, params_t *pm)
Definition gvmap.c:396
static const char * usage
Definition gvpr.c:53
#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 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:1225
void map_palette_optimal_coloring(char *color_scheme, SparseMatrix A0, float **rgb_r, float **rgb_g, float **rgb_b)
Definition make_map.c:34
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 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