put code in commont between ploot-ff.c and ploot-braille.c to separate files - ploot - simple plotting tools
(HTM) git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Tags
(DIR) README
(DIR) LICENSE
---
(DIR) commit 1c1a69494de95f4f5a3a439a16fac98026e2aa09
(DIR) parent 62211b846caa7b980b6a43dea1fdf0a0e2f6de34
(HTM) Author: Josuah Demangeon <me@josuah.net>
Date: Sat, 8 Feb 2020 18:38:14 +0100
put code in commont between ploot-ff.c and ploot-braille.c to separate files
Diffstat:
M Makefile | 2 +-
M arg.h | 6 +++---
M def.h | 27 +++++++++++++++++++++------
A ploot-braille.c | 200 +++++++++++++++++++++++++++++++
M ploot-ff.c | 295 +++++++------------------------
D ploot-plot.c | 201 ------------------------------
6 files changed, 292 insertions(+), 439 deletions(-)
---
(DIR) diff --git a/Makefile b/Makefile
@@ -5,7 +5,7 @@ BIN = ploot-ff ploot-feed
LIB = -lm
MANDIR = $(PREFIX)/share/man
-SRC = util.c drawille.c font.c font7.c font8.c font13.c
+SRC = csv.c drawille.c font.c font7.c font8.c font13.c util.c scale.c
all: $(BIN)
(DIR) diff --git a/arg.h b/arg.h
@@ -5,11 +5,11 @@ extern char const *arg0;
#define ARG_SWITCH(argc, argv) \
arg0 = *argv; \
- while (++argv && --argc && **argv == '-' && (*argv)[1]) \
+ while (++argv && --argc && **argv == '-' && (*argv)[1]) \
if ((*argv)[1] == '-' && (*argv)[2] == '\0') { \
++argv; break; \
- } else for (int stop = 0; !stop && *++*argv != '\0' ;) \
- switch (**argv)
+ } else for (int stop = 0; !stop && *++*argv != '\0' ;) \
+ switch (**argv)
#define ARG ((*++*argv != '\0' || *++argv != NULL) \
? ((stop = 1), argc--, *argv) \
(DIR) diff --git a/def.h b/def.h
@@ -23,6 +23,23 @@ struct font {
char *glyph[128]; /* 0: end, 1: off, 2: on. */
};
+/*
+ * List of values and timestamps. Both have their dedicated buffer
+ * so that the timestamp buffer can be shared across vlist objects.
+ */
+struct vlist {
+ time_t *t; /* array of timestamps */
+ double *v; /* array of values */
+ size_t n; /* number of values */
+ char *label; /* for the legend */
+};
+
+/* csv.c */
+
+void csv_addrow (struct vlist *, size_t, char *);
+void csv_values (struct vlist *, size_t);
+void csv_labels (struct vlist *, char **, char *);
+
/* drawille.c */
size_t drawille_fmt_row (struct drawille *, char *, size_t, int);
@@ -38,17 +55,15 @@ char * drawille_text (struct drawille *, int, int, struct font *, char *);
size_t font_width (struct font *, int);
size_t font_strlen (struct font *, char *);
-/* font13.c */
+/* font*.c */
struct font font13;
-
-/* font7.c */
-
+struct font font7;
struct font font8;
-/* font8.c */
+/* scale.c */
-struct font font8;
+void scale (struct vlist *, int, time_t *, time_t *, time_t *, double *, double *, double *);
/* util.c */
(DIR) diff --git a/ploot-braille.c b/ploot-braille.c
@@ -0,0 +1,200 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+
+#include "def.h"
+
+/*
+ * Adjust the vertical scale so that it gets possible to
+ */
+static void
+plot_scale(double *min, double *max, int row)
+{
+ double unit, range, mi;
+
+ range = *max - *min;
+ unit = 1;
+
+ /* Zoom until it fills the canvas. */
+ for (; (row - 1) * unit > range; unit /= 10)
+ continue;
+
+ /* Dezoom until it fits the canvas. */
+ for (; (row - 1) * unit < range; unit *= 10)
+ continue;
+
+ /* Fine tune. */
+ if ((row - 1) * unit / 5 > range)
+ unit /= 5;
+ if ((row - 1) * unit / 4 > range)
+ unit /= 4;
+ if ((row - 1) * unit / 2 > range)
+ unit /= 2;
+
+ /* Align the minimum (and the zero). */
+ for (mi = 0; mi > *min - unit; mi -= unit)
+ continue;
+
+ /* Update the displayed minimal and maximal. */
+ *min = mi;
+ *max = mi + unit * row;
+}
+
+/*
+ * Return the step between two values.
+ */
+static int
+plot_time_interval(time_t step)
+{
+ time_t scale[] = {
+ 1, 5, 2, 10, 20, 30, 60, 60*2, 60*5, 60*10, 60*20, 60*30,
+ 3600, 3600*2, 3600*5, 3600*10, 3600*18, 3600*24, 3600*24*2,
+ 3600*24*5, 3600*24*10, 3600*24*20, 3600*24*30, 3600*24*50,
+ 3600*24*100, 3600*24*365, 0
+ };
+
+ for (time_t *s = scale; *s != 0; s++)
+ if (*s >= 20 * step)
+ return *s;
+ return 1;
+}
+
+static size_t
+plot_axis_x(char *buf, size_t sz, time_t step, time_t t2, int col)
+{
+ int x, prec;
+ char tmp[sizeof("MM/DD HH:MM")], *fmt;
+ size_t n;
+ time_t t, interval;
+
+ interval = plot_time_interval(step);
+ fmt = (step < 3600 * 12) ? "^%H:%M:%S" :
+ (step < 3600 * 24) ? "^%m/%d %H:%M" :
+ "^%Y/%m/%d";
+ n = x = 0;
+
+ t = t2 - col * 2 * step;
+ t += interval - t % interval;
+ for (; t < t2; t += interval) {
+ strftime(tmp, sizeof tmp, fmt, localtime(&t));
+ x = ((t - t2) / 2 + col * step) / step;
+ prec = x - n + strlen(tmp);
+ assert((n += snprintf(buf+n, sz-n, "%*s", prec, tmp)) <= sz);
+ }
+ assert((n += strlcpy(buf+n, "\n", sz-n)) < sz);
+ return n;
+}
+
+/*
+ * Plot a single line out of the y axis, at row <r> out of <rows>.
+ */
+static size_t
+plot_axis_y(char *buf, size_t sz, double min, double max, int r, int rows)
+{
+ size_t i;
+ char tmp[10] = "", *s;
+ double val;
+
+ val = (max - min) * (rows - r) / rows + min;
+ humanize(tmp, sizeof tmp, val);
+ s = (r == 0) ? "┌" :
+ (r == rows - 1) ? "└" :
+ "├";
+ i = snprintf(buf, sz, "%s%-6s ", s, tmp);
+ return (i > sz) ? (sz) : (i);
+}
+
+static char *
+plot_render(struct drawille *drw, double min, double max, time_t step, time_t t2)
+{
+ char *buf;
+ size_t sz;
+ size_t n;
+
+ /* Render the plot line by line. */
+ sz = drw->row * (20 + drw->col * 3 + 1) + 1;
+ sz += drw->col + 1 + 100000;
+ if ((buf = calloc(sz, 1)) == NULL)
+ goto err;
+ n = 0;
+ for (int row = 0; row < drw->row; row++) {
+ n += drawille_fmt_row(drw, buf+n, sz-n, row);
+ n += plot_axis_y(buf+n, sz-n, min, max, row, drw->row);
+ n += strlcpy(buf+n, "\n", sz-n);
+ }
+ plot_axis_x(buf+n, sz-n, step, t2, drw->col);
+ return buf;
+err:
+ errno = ENOBUFS;
+ free(buf);
+ return NULL;
+}
+
+/*
+ * Plot the body as an histogram interpolating the gaps and include
+ * a vertical and horizontal axis.
+ */
+static char *
+plot_hist(struct vlist *vl, time_t t2, struct drawille *drw)
+{
+ int x, y, zero, shift;
+ double min, max, val;
+ time_t t1, t;
+
+ /* Adjust the y scale. */
+ shift = min = max = 0;
+ timeserie_stats(vl, &min, &max);
+ if (drw->row > 1) {
+ shift = 2; /* Align values to the middle of the scale: |- */
+ plot_scale(&min, &max, drw->row);
+ }
+ zero = timeserie_ypos(0, min, max, drw->row*4) - shift;
+
+ /* Adjust the x scale. */
+ t2 = t2 + vl->step - t2 % vl->step;
+ t1 = t2 - vl->step * vl->len;
+
+ /* Plot the data in memory in <drw> starting from the end (t2). */
+ t = t2;
+ for (x = drw->col * 2; x > 0; x--) {
+ val = timeserie_get(vl, t);
+ if (!isnan(val)) {
+ y = timeserie_ypos(val, min, max, drw->row*4) - shift;
+ drawille_dot_hist(drw, x, y, zero);
+ }
+ t -= vl->step;
+ }
+
+ return plot_render(drw, min, max, vl->step, t2);
+}
+
+static char *
+plot(struct vlist *vl, time_t t2, int row, int col)
+{
+ struct drawille *drw;
+ size_t len;
+ char *buf;
+
+ len = 500;
+ buf = NULL;
+ drw = NULL;
+ col -= 8;
+
+ if (timeserie_read(vl) == -1)
+ goto err;
+
+ if ((drw = drawille_new(row, col)) == NULL)
+ goto err;
+
+ buf = plot_hist(vl, t2, drw);
+err:
+ if (buf == NULL)
+ timedb_close(&vl->db);
+ free(drw);
+ return buf;
+}
(DIR) diff --git a/ploot-ff.c b/ploot-ff.c
@@ -18,9 +18,6 @@
#define MARGIN 4
-#define XDENSITX 7 /* nb of values on x axis */
-#define YDENSITX 7 /* nb of values on y axis */
-
#define IMAGE_H (TITLE_H + PLOT_H + XLABEL_H)
#define IMAGE_W (YLABEL_W + PLOT_W + LEGEND_W)
@@ -45,8 +42,8 @@
#define PLOT_H (160)
#define LEGEND_X (IMAGE_W - LEGEND_W)
-#define LEGEND_Y (XLABEL_H)
-#define LEGEND_W (150)
+#define LEGEND_Y (TITLE_H + PLOT_H - (font)->height)
+#define LEGEND_W (100)
#define LEGEND_H (PLOT_H)
struct color {
@@ -56,12 +53,9 @@ struct color {
uint16_t alpha;
};
-struct vlist {
- struct color color; /* color to use to draw the line */
- time_t *t; /* array of timestamps */
- double *v; /* array of values */
- int n; /* number of values */
- char *label; /* for the legend */
+struct cname {
+ char *name;
+ struct color color;
};
struct canvas {
@@ -72,17 +66,12 @@ struct canvas {
struct color *buf;
};
-struct clist {
- char *name;
- struct color color;
-};
-
char const *arg0;
static char *tflag = "";
static char *uflag = "";
static struct font *font = &font13;
-struct clist clist[] = {
+static struct cname cname[] = {
/* name red green blue alpha */
{ "red", { 0xffff, 0x4444, 0x4444, 0xffff } },
{ "orange", { 0xffff, 0x9999, 0x4444, 0xffff } },
@@ -93,98 +82,6 @@ struct clist clist[] = {
{ NULL, { 0, 0, 0, 0 } }
};
-static struct color *
-name_to_color(char *name)
-{
- for (struct clist *c = clist; c->name != NULL; c++)
- if (strcmp(name, c->name) == 0)
- return &c->color;
- return NULL;
-}
-
-static void
-scale_minmax(struct vlist *v, int n,
- time_t *tmin, time_t *tmax,
- double *vmin, double *vmax)
-{
- int i;
-
- *vmin = *vmax = 0;
- *tmin = *tmax = *v->t;
-
- for (; n-- > 0; v++) {
- for (i = 0; i < v->n; i++) {
- if (v->v[i] < *vmin)
- *vmin = v->v[i];
- if (v->v[i] > *vmax)
- *vmax = v->v[i];
- if (v->t[i] < *tmin)
- *tmin = v->t[i];
- if (v->t[i] > *tmax)
- *tmax = v->t[i];
- }
- }
-}
-
-static void
-scale_tstep(time_t *step, int density, time_t min, time_t max)
-{
- time_t dt, *s, scale[] = {
- 1, 5, 2, 10, 20, 30, 60, 60*2, 60*5, 60*10, 60*20, 60*30, 3600,
- 3600*2, 3600*5, 3600*10, 3600*18, 3600*24, 3600*24*2,
- 3600*24*5, 3600*24*10, 3600*24*20, 3600*24*30, 3600*24*50,
- 3600*24*100, 3600*24*365, 0
- };
-
- dt = max - min;
-
- for (s = scale; s < scale + LEN(scale); s++) {
- if (dt < *s * density) {
- *step = *s;
- break;
- }
- }
-}
-
-static void
-scale_vstep(double *step, int density, double min, double max)
-{
- double dv, *s, scale[] = { 1, 2, 3, 5 };
- int i;
-
- dv = max - min;
-
- if (dv > 1) {
- for (i = 1; i != 0; i *= 10) {
- for (s = scale; s < scale + LEN(scale); s++) {
- if (dv < *s * i * density) {
- *step = *s * i;
- return;
- }
- }
- }
- } else {
- for (i = 1; i != 0; i *= 10) {
- for (s = scale + LEN(scale) - 1; s >= scale; s--) {
- if (dv > *s / i * density / 2) {
- *step = *s / i;
- return;
- }
- }
- }
- }
-}
-
-static void
-scale(struct vlist *v, int n,
- time_t *tmin, time_t *tmax, time_t *tstep,
- double *vmin, double *vmax, double *vstep)
-{
- scale_minmax(v, n, tmin, tmax, vmin, vmax);
- scale_tstep(tstep, XDENSITX, *tmin, *tmax);
- scale_vstep(vstep, YDENSITX, *vmin, *vmax);
-}
-
/*
* Convert (x,y) coordinates to (row,col) for printing into the buffer.
* The buffer only contain one number, so the coordinate is a single integer:
@@ -196,18 +93,18 @@ scale(struct vlist *v, int n,
* - (0,1) is above it. +--x
*/
static void
-ff_pixel(struct canvas *can, struct color *col,
+ff_pixel(struct canvas *can, struct color *color,
int x, int y)
{
x += can->x;
y += can->y;
if (x < 0 || x >= can->w || y < 0 || y >= can->h)
return;
- memcpy(can->buf + can->w * (can->h - 1 - y) + x, col, sizeof(*can->buf));
+ memcpy(can->buf + can->w * (can->h - 1 - y) + x, color, sizeof(*can->buf));
}
static void
-ff_rectangle(struct canvas *can, struct color *col,
+ff_rectangle(struct canvas *can, struct color *color,
int y1, int x1,
int y2, int x2)
{
@@ -218,14 +115,14 @@ ff_rectangle(struct canvas *can, struct color *col,
for (y = ymin; y <= ymax; y++)
for (x = xmin; x <= xmax; x++)
- ff_pixel(can, col, x, y);
+ ff_pixel(can, color, x, y);
}
/*
* From Bresenham's line algorithm and dcat's tplot.
*/
static void
-ff_line(struct canvas *can, struct color *col,
+ff_line(struct canvas *can, struct color *color,
int x0, int y0,
int x1, int y1)
{
@@ -238,7 +135,7 @@ ff_line(struct canvas *can, struct color *col,
err = (dy > dx ? dy : -dx) / 2;
for (;;) {
- ff_pixel(can, col, x0, y0);
+ ff_pixel(can, color, x0, y0);
if (y0 == y1 && x0 == x1)
break;
@@ -259,7 +156,7 @@ ff_line(struct canvas *can, struct color *col,
* Draw a coloured glyph from font f centered on y.
*/
static int
-ff_char(struct canvas *can, struct color *col, char c,
+ff_char(struct canvas *can, struct color *color, char c,
int x, int y)
{
int yf, xf, wf;
@@ -271,7 +168,7 @@ ff_char(struct canvas *can, struct color *col, char c,
for (xf = 0; xf < wf; xf++)
for (yf = 0; yf < font->height; yf++)
if (font->glyph[(int)c][wf * (font->height - yf) + xf] == 3)
- ff_pixel(can, col, x + xf, y + yf);
+ ff_pixel(can, color, x + xf, y + yf);
return wf + 1;
}
@@ -279,11 +176,11 @@ ff_char(struct canvas *can, struct color *col, char c,
* Draw a left aligned string without wrapping it.
*/
static size_t
-ff_text_left(struct canvas *can, struct color *col, char *s,
+ff_text_left(struct canvas *can, struct color *color, char *s,
int x, int y)
{
for (; *s != '\0'; s++)
- x += ff_char(can, col, *s, x, y);
+ x += ff_char(can, color, *s, x, y);
return x;
}
@@ -291,22 +188,22 @@ ff_text_left(struct canvas *can, struct color *col, char *s,
* Draw a center aligned string without wrapping it.
*/
static size_t
-ff_text_center(struct canvas *can, struct color *col, char *s,
+ff_text_center(struct canvas *can, struct color *color, char *s,
int x, int y)
{
x -= font_strlen(font, s) / 2;
- return ff_text_left(can, col, s, x, y);
+ return ff_text_left(can, color, s, x, y);
}
/*
* Draw a right aligned string without wrapping it.
*/
static size_t
-ff_text_right(struct canvas *can, struct color *col, char *s,
+ff_text_right(struct canvas *can, struct color *color, char *s,
int x, int y)
{
x -= font_strlen(font, s);
- return ff_text_left(can, col, s, x, y);
+ return ff_text_left(can, color, s, x, y);
}
static void
@@ -326,12 +223,16 @@ ff_print(struct canvas *can)
static int
ff_t2x(time_t t, time_t tmin, time_t tmax)
{
+ if (tmin == tmax)
+ return PLOT_W;
return (t - tmin) * PLOT_W / (tmax - tmin);
}
static int
ff_v2y(double v, double vmin, double vmax)
{
+ if (vmin == vmax)
+ return PLOT_H;
return (v - vmin) * PLOT_H / (vmax - vmin);
}
@@ -394,7 +295,7 @@ ff_title(struct canvas *can,
}
static void
-ff_plot(struct canvas *can, struct vlist *v,
+ff_plot(struct canvas *can, struct vlist *vl, struct color *color,
double vmin, double vmax,
time_t tmin, time_t tmax)
{
@@ -403,12 +304,12 @@ ff_plot(struct canvas *can, struct vlist *v,
int x, y, n, ylast, xlast, first;
first = 1;
- for (tp = v->t, vp = v->v, n = v->n; n > 0; n--, vp++, tp++) {
+ for (tp = vl->t, vp = vl->v, n = vl->n; n > 0; n--, vp++, tp++) {
y = ff_v2y(*vp, vmin, vmax);
x = ff_t2x(*tp, tmin, tmax);
if (!first)
- ff_line(can, &v->color, xlast, ylast, x, y);
+ ff_line(can, color, xlast, ylast, x, y);
ylast = y;
xlast = x;
@@ -417,24 +318,24 @@ ff_plot(struct canvas *can, struct vlist *v,
}
static void
-ff_values(struct canvas *can, struct vlist *v, int n,
+ff_values(struct canvas *can, struct vlist *vl, struct color **cl, size_t ncol,
time_t tmin, time_t tmax,
double vmin, double vmax)
{
- for (; n > 0; n--, v++)
- ff_plot(can, v, vmin, vmax, tmin, tmax);
+ for (; ncol > 0; ncol--, vl++, cl++)
+ ff_plot(can, vl, *cl, vmin, vmax, tmin, tmax);
}
static void
-ff_legend(struct canvas *can, struct color *label_fg, struct vlist *v, int n)
+ff_legend(struct canvas *can, struct color *fg, struct vlist *vl, struct color **cl, size_t ncol)
{
- int i, x, y;
+ size_t i, x, y;
- for (i = 0; i < n; i++, v++) {
- x = MARGIN;
- x = ff_text_left(can, &v->color, "\1", x, y);
- x = ff_text_left(can, label_fg, v->label, x, y);
- y = LEGEND_H - i * (font->height + MARGIN) - font->height / 2;
+ for (i = 0; i < ncol; i++, vl++, cl++) {
+ x = MARGIN * 2;
+ x = ff_text_left(can, *cl, "\1", x, y) + MARGIN;
+ x = ff_text_left(can, fg, vl->label, x, y);
+ y = LEGEND_H - i * (font->height + MARGIN);
}
}
@@ -450,7 +351,7 @@ ff_legend(struct canvas *can, struct color *label_fg, struct vlist *v, int n)
* x label here
*/
static void
-ff(struct vlist *v, int n, char *name, char *units)
+ff(struct vlist *vl, struct color **cl, size_t ncol, char *name, char *units)
{
struct canvas can = { IMAGE_W, IMAGE_H, 0, 0, NULL };
struct color plot_bg = { 0x2222, 0x2222, 0x2222, 0xffff };
@@ -461,7 +362,7 @@ ff(struct vlist *v, int n, char *name, char *units)
double vmin, vmax, vstep;
time_t tmin, tmax, tstep;
- scale(v, n, &tmin, &tmax, &tstep, &vmin, &vmax, &vstep);
+ scale(vl, ncol, &tmin, &tmax, &tstep, &vmin, &vmax, &vstep);
assert(can.buf = calloc(IMAGE_H * IMAGE_W, sizeof *can.buf));
@@ -487,108 +388,41 @@ ff(struct vlist *v, int n, char *name, char *units)
can.x = PLOT_X;
can.y = PLOT_Y;
- ff_values(&can, v, n, tmin, tmax, vmin, vmax);
+ ff_values(&can, vl, cl, ncol, tmin, tmax, vmin, vmax);
can.x = LEGEND_X;
can.y = LEGEND_Y;
- ff_legend(&can, &label_fg, v, n);
+ ff_legend(&can, &label_fg, vl, cl, ncol);
ff_print(&can);
}
-
-static void
-csv_labels(struct vlist *v, char **argv, char *buf)
-{
- struct color *color;
-
- if (esfgets(buf, LINE_MAX, stdin) == NULL)
- err(1, "missing label line");
-
- if (strcmp(strsep(&buf, ","), "epoch") != 0)
- err(1, "first label must be \"epoch\"");
-
- for (; *argv != NULL; v++, argv++) {
- if ((v->label = strsep(&buf, ",")) == NULL)
- err(1, "more arguments than columns");
- else if ((color = name_to_color(*argv)) == NULL)
- err(1, "unknown color: %s", *argv);
- v->color = *color;
- }
-
- if (strsep(&buf, ",") != NULL)
- err(1, "more columns than arguments");
-}
-
-static int
-csv_addval(struct vlist *v, size_t sz, size_t nval, double field, time_t epoch)
-{
- if (nval >= sz) {
- sz = sz * 2 + 1;
- if ((v->v = realloc(v->v, sz * sizeof(*v->v))) == NULL)
- err(1, "reallocating values buffer");
- if ((v->t = realloc(v->t, sz * sizeof(*v->t))) == NULL)
- err(1, "reallocating values buffer");
- }
- v->v[nval] = field;
- v->t[nval] = epoch;
- v->n = nval + 1;
-
- return sz;
-}
-/*
- * Add to each column the value on the current row.
- */
-static int
-csv_addrow(struct vlist *v, size_t sz, size_t ncol, size_t nval, char *line)
+static struct color *
+name_to_color(char *name)
{
- time_t epoch;
- int bs;
- char *field, *dot;
-
- if ((field = strsep(&line, ",")) == NULL)
- err(1, "%d: missing epoch", nval);
-
- if ((dot = strchr(field, '.')) != NULL)
- *dot = '\0';
- epoch = eatol(field);
- for (; (field = strsep(&line, ",")) != NULL; ncol--, v++) {
- if (ncol <= 0)
- err(1, "%d: too many fields", nval);
- bs = csv_addval(v, sz, nval, eatof(field), epoch);
- }
- if (ncol > 0)
- err(1, "%d: too few fields", ncol);
+ struct cname *cn;
- return bs;
+ for (cn = cname; cn->name != NULL; cn++)
+ if (strcmp(name, cn->name) == 0)
+ return &cn->color;
+ return NULL;
}
-/*
- * < ncol >
- * epoch,a1,b1,c1 ^
- * epoch,a2,b2,c2 nval
- * epoch,a3,b3,c3 v
- */
static void
-csv_values(struct vlist *v, size_t ncol)
+argv_to_color(struct color **cl, char **argv)
{
- int nval, sz;
- char line[LINE_MAX];
-
- sz = 0;
- for (nval = 0; esfgets(line, sizeof(line), stdin) != NULL; nval++)
- sz = csv_addrow(v, sz, ncol, nval, line);
- if (nval == 0)
- err(1, "no value could be read\n");
+ for (; *argv != NULL; cl++, argv++)
+ if ((*cl = name_to_color(*argv)) == NULL)
+ err(1, "unknown color name: %s", *argv);
}
static void
usage(void)
{
fprintf(stderr, "usage: %s [-t title] [-u unit] {", arg0);
- fputs(clist->name, stderr);
- for (struct clist *c = clist + 1; c->name != NULL; c++)
- fprintf(stderr, ",%s", c->name);
+ fputs(cname->name, stderr);
+ for (struct cname *cn = cname + 1; cn->name != NULL; cn++)
+ fprintf(stderr, ",%s", cn->name);
fputs("}...\n", stderr);
exit(1);
}
@@ -596,7 +430,8 @@ usage(void)
int
main(int argc, char **argv)
{
- struct vlist *v;
+ struct vlist *vl;
+ struct color **cl;
char labels[LINE_MAX];
ARG_SWITCH(argc, argv) {
@@ -610,15 +445,19 @@ main(int argc, char **argv)
usage();
}
- fflush(stdout);
+ if (argc == 0)
+ usage();
- if ((v = calloc(argc, sizeof(*v))) == NULL)
- err(1, "calloc value list");
+ assert(vl = calloc(argc, sizeof(*vl)));
+ assert(cl = calloc(argc, sizeof(*cl)));
- csv_labels(v, argv, labels);
- csv_values(v, argc);
+ csv_labels(vl, argv, labels);
+ csv_values(vl, argc);
+ argv_to_color(cl, argv);
- ff(v, argc, tflag, uflag);
+ ff(vl, cl, argc, tflag, uflag);
+ free(vl);
+ free(cl);
return 0;
}
(DIR) diff --git a/ploot-plot.c b/ploot-plot.c
@@ -1,201 +0,0 @@
-#include <assert.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <math.h>
-
-#include "def.h"
-
-/*
- * Adjust the vertical scale so that it gets possible to
- */
-static void
-plot_scale(double *min, double *max, int row)
-{
- double unit, range, mi;
-
- range = *max - *min;
- unit = 1;
-
- /* Zoom until it fills the canvas. */
- for (; (row - 1) * unit > range; unit /= 10)
- continue;
-
- /* Dezoom until it fits the canvas. */
- for (; (row - 1) * unit < range; unit *= 10)
- continue;
-
- /* Fine tune. */
- if ((row - 1) * unit / 5 > range)
- unit /= 5;
- if ((row - 1) * unit / 4 > range)
- unit /= 4;
- if ((row - 1) * unit / 2 > range)
- unit /= 2;
-
- /* Align the minimum (and the zero). */
- for (mi = 0; mi > *min - unit; mi -= unit)
- continue;
-
- /* Update the displayed minimal and maximal. */
- *min = mi;
- *max = mi + unit * row;
-}
-
-/*
- * Return the step between two values.
- */
-static int
-plot_time_interval(time_t step)
-{
- time_t scale[] = {
- 1, 5, 2, 10, 20, 30, 60, 60*2, 60*5, 60*10, 60*20, 60*30,
- 3600, 3600*2, 3600*5, 3600*10, 3600*18, 3600*24, 3600*24*2,
- 3600*24*5, 3600*24*10, 3600*24*20, 3600*24*30, 3600*24*50,
- 3600*24*100, 3600*24*365, 0
- };
-
- for (time_t *s = scale; *s != 0; s++)
- if (*s >= 20 * step)
- return *s;
- return 1;
-}
-
-static size_t
-plot_axis_x(char *buf, size_t sz, time_t step, time_t t2, int col)
-{
- int x, prec;
- char tmp[sizeof("MM/DD HH:MM")], *fmt;
- size_t n;
- time_t t, interval;
-
- interval = plot_time_interval(step);
- fmt = (step < 3600 * 12) ? "^%H:%M:%S" :
- (step < 3600 * 24) ? "^%m/%d %H:%M" :
- "^%Y/%m/%d";
- n = x = 0;
-
- t = t2 - col * 2 * step;
- t += interval - t % interval;
- for (; t < t2; t += interval) {
- strftime(tmp, sizeof tmp, fmt, localtime(&t));
- x = ((t - t2) / 2 + col * step) / step;
- prec = x - n + strlen(tmp);
- assert((n += snprintf(buf+n, sz-n, "%*s", prec, tmp)) <= sz);
- }
- assert((n += strlcpy(buf+n, "\n", sz-n)) < sz);
- return n;
-}
-
-/*
- * Plot a single line out of the y axis, at row <r> out of <rows>.
- */
-static size_t
-plot_axis_y(char *buf, size_t sz, double min, double max, int r, int rows)
-{
- size_t i;
- char tmp[10] = "", *s;
- double val;
-
- val = (max - min) * (rows - r) / rows + min;
- humanize(tmp, sizeof tmp, val);
- s = (r == 0) ? "┌" :
- (r == rows - 1) ? "└" :
- "├";
- i = snprintf(buf, sz, "%s%-6s ", s, tmp);
- return (i > sz) ? (sz) : (i);
-}
-
-static char *
-plot_render(struct drawille *drw, double min, double max, time_t step, time_t t2)
-{
- char *buf;
- size_t sz;
- size_t n;
-
- /* Render the plot line by line. */
- sz = drw->row * (20 + drw->col * 3 + 1) + 1;
- sz += drw->col + 1 + 100000;
- if ((buf = calloc(sz, 1)) == NULL)
- goto err;
- n = 0;
- for (int row = 0; row < drw->row; row++) {
- n += drawille_fmt_row(drw, buf+n, sz-n, row);
- n += plot_axis_y(buf+n, sz-n, min, max, row, drw->row);
- n += strlcpy(buf+n, "\n", sz-n);
- }
- plot_axis_x(buf+n, sz-n, step, t2, drw->col);
-
- return buf;
-err:
- errno = ENOBUFS;
- free(buf);
- return NULL;
-}
-
-/*
- * Plot the body as an histogram interpolating the gaps and include
- * a vertical and horizontal axis.
- */
-static char *
-plot_hist(struct timeserie *ts, time_t t2, struct drawille *drw)
-{
- int x, y, zero, shift;
- double min, max, val;
- time_t t1, t;
-
- /* Adjust the y scale. */
- shift = min = max = 0;
- timeserie_stats(ts, &min, &max);
- if (drw->row > 1) {
- shift = 2; /* Align values to the middle of the scale: |- */
- plot_scale(&min, &max, drw->row);
- }
- zero = timeserie_ypos(0, min, max, drw->row*4) - shift;
-
- /* Adjust the x scale. */
- t2 = t2 + ts->step - t2 % ts->step;
- t1 = t2 - ts->step * ts->len;
-
- /* Plot the data in memory in <drw> starting from the end (t2). */
- t = t2;
- for (x = drw->col * 2; x > 0; x--) {
- val = timeserie_get(ts, t);
- if (!isnan(val)) {
- y = timeserie_ypos(val, min, max, drw->row*4) - shift;
- drawille_dot_hist(drw, x, y, zero);
- }
- t -= ts->step;
- }
-
- return plot_render(drw, min, max, ts->step, t2);
-}
-
-static char *
-plot(struct timeserie *ts, time_t t2, int row, int col)
-{
- struct drawille *drw;
- size_t len;
- char *buf;
-
- len = 500;
- buf = NULL;
- drw = NULL;
- col -= 8;
-
- if (timeserie_read(ts) == -1)
- goto err;
-
- if ((drw = drawille_new(row, col)) == NULL)
- goto err;
-
- buf = plot_hist(ts, t2, drw);
-err:
- if (buf == NULL)
- timedb_close(&ts->db);
- free(drw);
- return buf;
-}