Introduction
Introduction Statistics Contact Development Disclaimer Help
ploot-farbfeld.c - ploot - simple plotting tools
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65…
Log
Files
Refs
Tags
README
LICENSE
---
ploot-farbfeld.c (10488B)
---
1 #include <arpa/inet.h>
2 #include <ctype.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <math.h>
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 #include <unistd.h>
14 #include "tsv.h"
15 #include "font.h"
16 #include "util.h"
17
18 #ifndef __OpenBSD__
19 #define pledge(...) 0
20 #endif
21
22 #define MARGIN 8
23
24 #define IMAGE_H (TITLE_H + PLOT_H + XLABEL_H)
25 #define IMAGE_W (MARGIN + YLABEL_W + PLOT_W + MARGIN)
26
27 #define TITLE_X (MARGIN)
28 #define TITLE_Y (IMAGE_H - TITLE_H / 2)
29 #define TITLE_H ((font)->height * 2)
30 #define TITLE_W (PLOT_W)
31
32 #define YLABEL_X (MARGIN)
33 #define YLABEL_Y (PLOT_Y)
34 #define YLABEL_H (PLOT_H)
35 #define YLABEL_W (40 + MARGIN)
36
37 #define XLABEL_X (PLOT_X)
38 #define XLABEL_Y (0)
39 #define XLABEL_H ((font)->height * 2)
40 #define XLABEL_W (PLOT_W)
41
42 #define PLOT_X (YLABEL_X + YLABEL_W)
43 #define PLOT_Y (XLABEL_H)
44 #define PLOT_W (700)
45 #define PLOT_H (160)
46
47 #define LEGEND_X (IMAGE_W / 2)
48 #define LEGEND_Y (TITLE_Y)
49 #define LEGEND_H (PLOT_H)
50
51 struct ffcolor {
52 uint16_t red;
53 uint16_t green;
54 uint16_t blue;
55 uint16_t alpha;
56 };
57
58 struct ffplot {
59 int w, h, x, y; /* width, height and coordinamtes */
60 struct ffcolor *buf;
61 };
62
63 static struct colorname {
64 char *name;
65 struct ffcolor color;
66 } colorname[] = {
67 /* name red green blue alpha */
68 { "red", { 0xffff, 0x4444, 0x4444, 0xffff } },
69 { "orange", { 0xffff, 0x9999, 0x4444, 0xffff } },
70 { "yellow", { 0xffff, 0xffff, 0x4444, 0xffff } },
71 { "green", { 0x2222, 0xffff, 0x5555, 0xffff } },
72 { "cyan", { 0x0000, 0xffff, 0xdddd, 0xffff } },
73 { "blue", { 0x2222, 0x9999, 0xffff, 0xffff } },
74 { NULL, { 0, 0, 0, 0 } }
75 };
76
77 static char *flag_title = "";
78 static struct font *font = &font13;
79
80 /*
81 * Convert (x,y) coordinates to (row,col) for printing into the buffer.
82 * The buffer only contain one number, so the coordinate is a single int…
83 * width * y + y.
84 * The coordinates are shifted by offx and offy to permit relative coord…
85 *
86 * The convention used: y
87 * - (0,0) is at the lower left corner of the plotvas. |
88 * - (0,1) is above it. +--x
89 */
90 static void
91 ffplot_pixel(struct ffplot *plot, struct ffcolor *color,
92 int x, int y)
93 {
94 x += plot->x;
95 y += plot->y;
96 if (x < 0 || x >= plot->w || y < 0 || y >= plot->h)
97 return;
98 memcpy(plot->buf + plot->w * (plot->h - 1 - y) + x, color, sizeo…
99 }
100
101 static void
102 ffplot_rectangle(struct ffplot *plot, struct ffcolor *color,
103 int y1, int x1,
104 int y2, int x2)
105 {
106 int x, y, ymin, xmin, ymax, xmax;
107
108 ymin = MIN(y1, y2); ymax = MAX(y1, y2);
109 xmin = MIN(x1, x2); xmax = MAX(x1, x2);
110
111 for (y = ymin; y <= ymax; y++)
112 for (x = xmin; x <= xmax; x++)
113 ffplot_pixel(plot, color, x, y);
114 }
115
116 /*
117 * From Bresenham's line algorithm and dcat's tplot.
118 */
119 static void
120 ffplot_line(struct ffplot *plot, struct ffcolor *color,
121 int x0, int y0,
122 int x1, int y1)
123 {
124 int dy, dx, sy, sx, err, e;
125
126 sx = x0 < x1 ? 1 : -1;
127 sy = y0 < y1 ? 1 : -1;
128 dx = ABS(x1 - x0);
129 dy = ABS(y1 - y0);
130 err = (dy > dx ? dy : -dx) / 2;
131
132 for (;;) {
133 ffplot_pixel(plot, color, x0, y0);
134
135 if (y0 == y1 && x0 == x1)
136 break;
137
138 e = err;
139 if (e > -dy) {
140 y0 += sy;
141 err -= dx;
142 }
143 if (e < dx) {
144 x0 += sx;
145 err += dy;
146 }
147 }
148 }
149
150 /*
151 * Draw a coloured glyph from font f centered on y.
152 */
153 static int
154 ffplot_char(struct ffplot *plot, struct ffcolor *color, struct font *ft,…
155 int x, int y)
156 {
157 int yf, xf, wf;
158
159 if (c & 0x80)
160 c = '\0';
161 y -= ft->height / 2;
162 wf = font_width(ft, c);
163 for (xf = 0; xf < wf; xf++)
164 for (yf = 0; yf < ft->height; yf++)
165 if (ft->glyph[(int)c][wf * (ft->height - yf) + x…
166 ffplot_pixel(plot, color, x + xf, y + yf…
167 return wf + 1;
168 }
169
170 /*
171 * Draw a left aligned string without wrapping it.
172 */
173 static size_t
174 ffplot_text_left(struct ffplot *plot, struct ffcolor *color, struct font…
175 char *s, int x, int y)
176 {
177 for (; *s != '\0'; s++)
178 x += ffplot_char(plot, color, ft, *s, x, y);
179 return x;
180 }
181
182 /*
183 * Draw a center aligned string without wrapping it.
184 */
185 static size_t
186 ffplot_text_center(struct ffplot *plot, struct ffcolor *color, struct fo…
187 char *s, int x, int y)
188 {
189 x -= font_strlen(ft, s) / 2;
190 return ffplot_text_left(plot, color, ft, s, x, y);
191 }
192
193 /*
194 * Draw a right aligned string without wrapping it.
195 */
196 static size_t
197 ffplot_text_right(struct ffplot *plot, struct ffcolor *color, struct fon…
198 char *s, int x, int y)
199 {
200 x -= font_strlen(ft, s);
201 return ffplot_text_left(plot, color, ft, s, x, y);
202 }
203
204 static void
205 ffplot_print(FILE *fp, struct ffplot *plot)
206 {
207 uint32_t w, h;
208
209 w = htonl(plot->w);
210 h = htonl(plot->h);
211
212 fprintf(stdout, "farbfeld");
213 fwrite(&w, sizeof(w), 1, fp);
214 fwrite(&h, sizeof(h), 1, fp);
215 fwrite(plot->buf, plot->w * plot->h, sizeof(*plot->buf), fp);
216 }
217
218 static int
219 ffplot_t2x(time_t t, time_t tmin, time_t tmax)
220 {
221 if (tmin == tmax)
222 return PLOT_W;
223 return (t - tmin) * PLOT_W / (tmax - tmin);
224 }
225
226 static int
227 ffplot_v2y(double v, double vmin, double vmax)
228 {
229 if (vmin == vmax)
230 return PLOT_H;
231 return (v - vmin) * PLOT_H / (vmax - vmin);
232 }
233
234 static void
235 ffplot_xaxis(struct ffplot *plot, struct ffcolor *label, struct ffcolor …
236 time_t tmin, time_t tmax, time_t tstep)
237 {
238 time_t t;
239 int x;
240 char str[sizeof("MM/DD HH/MM")], *fmt;
241
242 if (tstep < 3600 * 12)
243 fmt = "%H:%M:%S";
244 else if (tstep < 3600 * 24)
245 fmt = "%m/%d %H:%M";
246 else
247 fmt = "%X/%m/%d";
248
249 for (t = tmax - tmax % tstep; t >= tmin; t -= tstep) {
250 x = ffplot_t2x(t, tmin, tmax);
251
252 ffplot_line(plot, grid,
253 x, XLABEL_H,
254 x, XLABEL_H + PLOT_H);
255
256 strftime(str, sizeof(str), fmt, localtime(&t));
257 ffplot_text_center(plot, label, font, str,
258 x, XLABEL_H / 2);
259 }
260 }
261
262 static void
263 ffplot_yaxis(struct ffplot *plot, struct ffcolor *label, struct ffcolor …
264 double vmin, double vmax, double vstep)
265 {
266 double v;
267 int y;
268 char str[8 + 1];
269
270 for (v = vmax - fmod(vmax, vstep); v >= vmin; v -= vstep) {
271 y = ffplot_v2y(v, vmin, vmax);
272
273 ffplot_line(plot, grid,
274 YLABEL_W, y,
275 YLABEL_W + PLOT_W, y);
276
277 humanize(str, v);
278 ffplot_text_right(plot, label, font, str,
279 YLABEL_W - MARGIN, y);
280 }
281 }
282
283 static void
284 ffplot_title(struct ffplot *plot, struct ffcolor *ct, char *title)
285 {
286 ffplot_text_left(plot, ct, font, title, TITLE_H / 2, 0);
287 }
288
289 static void
290 ffplot_plot(struct ffplot *plot, struct tsv *vl, struct ffcolor *color,
291 double vmin, double vmax,
292 time_t tmin, time_t tmax)
293 {
294 time_t *tp;
295 double *vp;
296 int x, y, n, ylast, xlast, first;
297
298 first = 1;
299 for (tp = vl->t, vp = vl->v, n = vl->n; n > 0; n--, vp++, tp++) {
300 y = ffplot_v2y(*vp, vmin, vmax);
301 x = ffplot_t2x(*tp, tmin, tmax);
302
303 if (!first)
304 ffplot_line(plot, color, xlast, ylast, x, y);
305
306 ylast = y;
307 xlast = x;
308 first = 0;
309 }
310 }
311
312 static void
313 ffplot_values(struct ffplot *plot, struct tsv *vl, struct ffcolor **cl, …
314 time_t tmin, time_t tmax,
315 double vmin, double vmax)
316 {
317 for (; ncol > 0; ncol--, vl++, cl++)
318 ffplot_plot(plot, vl, *cl, vmin, vmax, tmin, tmax);
319 }
320
321 static void
322 ffplot_legend(struct ffplot *plot, struct ffcolor *fg, struct tsv *vl, s…
323 {
324 size_t x, y;
325
326 x = y = 0;
327 for (; ncol > 0; ncol--, vl++, cl++) {
328 x = ffplot_text_left(plot, *cl, font, "-", x, y) + MARGI…
329 x = ffplot_text_left(plot, fg, font, vl->label, x, y);
330 x = ffplot_text_left(plot, fg, font, " ", x, y);
331 }
332 }
333
334 /*
335 * Plot the 'n' values list of the 'v' arrax with title 'name' label.
336 *
337 * Title Legend
338 * x ^
339 * label | - + - + - + - + -
340 * here | - + - + - + - + -
341 * +---+---+---+---+-->
342 * x label here
343 */
344 static void
345 plot(struct tsv *vl, struct ffcolor **cl, size_t ncol, char *name)
346 {
347 struct ffplot plot = { IMAGE_W, IMAGE_H, 0, 0, NULL };
348 struct ffcolor plot_bg = { 0x2222, 0x2222, 0x2222, 0xffff };
349 struct ffcolor grid_bg = { 0x2929, 0x2929, 0x2929, 0xffff };
350 struct ffcolor grid_fg = { 0x3737, 0x3737, 0x3737, 0xffff };
351 struct ffcolor label_fg = { 0x8888, 0x8888, 0x8888, 0xffff };
352 struct ffcolor title_fg = { 0xdddd, 0xdddd, 0xdddd, 0xffff };
353 double vmin, vmax, vstep;
354 time_t tmin, tmax, tstep;
355
356 tsv_min_max(vl, ncol, &tmin, &tmax, &vmin, &vmax);
357 tstep = scale_time_t(tmin, tmax, 7);
358 vstep = scale_double(vmin, vmax, 7);
359
360 if ((plot.buf = calloc(IMAGE_H * IMAGE_W, sizeof *plot.buf)) == …
361 err(1, "calloc: %s", strerror(errno));
362
363 plot.y = 0;
364 plot.x = 0;
365 ffplot_rectangle(&plot, &plot_bg, 0, 0, IMAGE_H - 1, IMAGE_W - 1…
366
367 plot.x = PLOT_X;
368 plot.y = PLOT_Y;
369 ffplot_rectangle(&plot, &grid_bg, 0, 0, PLOT_H, PLOT_W);
370
371 plot.x = XLABEL_X;
372 plot.y = XLABEL_Y;
373 ffplot_xaxis(&plot, &label_fg, &grid_fg, tmin, tmax, tstep);
374
375 plot.x = YLABEL_X;
376 plot.y = YLABEL_Y;
377 ffplot_yaxis(&plot, &label_fg, &grid_fg, vmin, vmax, vstep);
378
379 plot.x = TITLE_X;
380 plot.y = TITLE_Y;
381 ffplot_title(&plot, &title_fg, name);
382
383 plot.x = PLOT_X;
384 plot.y = PLOT_Y;
385 ffplot_values(&plot, vl, cl, ncol, tmin, tmax, vmin, vmax);
386
387 plot.x = LEGEND_X;
388 plot.y = LEGEND_Y;
389 ffplot_legend(&plot, &label_fg, vl, cl, ncol);
390
391 ffplot_print(stdout, &plot);
392 }
393
394 static struct ffcolor *
395 name_to_color(char *name)
396 {
397 struct colorname *cn;
398
399 for (cn = colorname; cn->name != NULL; cn++)
400 if (strcmp(name, cn->name) == 0)
401 return &cn->color;
402 return NULL;
403 }
404
405 static void
406 argv_to_color(struct ffcolor **cl, char **argv)
407 {
408 for (; *argv != NULL; cl++, argv++)
409 if ((*cl = name_to_color(*argv)) == NULL)
410 err(1, "unknown color name: %s", *argv);
411 }
412
413 static void
414 usage(void)
415 {
416 fprintf(stderr, "usage: %s [-t title] {", arg0);
417 fputs(colorname->name, stderr);
418 for (struct colorname *cn = colorname + 1; cn->name != NULL; cn+…
419 fprintf(stderr, ",%s", cn->name);
420 fputs("}...\n", stderr);
421 exit(1);
422 }
423
424 int
425 main(int argc, char **argv)
426 {
427 struct tsv *vl;
428 struct ffcolor **cl;
429 size_t ncol;
430 int c;
431
432 if (pledge("stdio", "") < 0)
433 err(1, "pledge: %s", strerror(errno));
434
435 arg0 = *argv;
436 while ((c = getopt(argc, argv, "t:")) > -1) {
437 switch (c) {
438 case 't':
439 flag_title = optarg;
440 break;
441 default:
442 usage();
443 }
444 }
445 argc -= optind;
446 argv += optind;
447
448 if (argc == 0)
449 usage();
450
451 if ((cl = calloc(argc, sizeof *cl)) == NULL)
452 err(1, "calloc: %s", strerror(errno));
453
454 tsv_labels(stdin, &vl, &ncol);
455 if (ncol > (size_t)argc)
456 err(1, "too many columns or not enough arguments");
457 else if (ncol < (size_t)argc)
458 err(1, "too many arguments or not enough columns");
459 tsv_values(stdin, vl, ncol);
460 argv_to_color(cl, argv);
461
462 plot(vl, cl, argc, flag_title);
463
464 free(vl);
465 free(cl);
466 return 0;
467 }
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.