ploot-farbfeld: comeback - 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 8836c19534760f2ce037c39bde9dc5591011ed07
 (DIR) parent eb816ab512727f55665f05809c78563ff93a94cc
 (HTM) Author: Josuah Demangeon <me@josuah.net>
       Date:   Sun, 27 Jun 2021 04:51:38 +0200
       
       ploot-farbfeld: comeback
       
       Diffstat:
         M Makefile                            |       2 +-
         M csv.c                               |      27 ++++++++++++++++++++++++++-
         M csv.h                               |       1 +
         A example.png                         |       0 
         M ploot-braille.c                     |      90 +++----------------------------
         M ploot-farbfeld.1                    |       4 ----
         M ploot-farbfeld.c                    |      64 +++++++++++++------------------
         M util.c                              |      53 ++++++++++++++++++++++++++++++
         M util.h                              |       3 +++
       
       9 files changed, 118 insertions(+), 126 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       @@ -9,7 +9,7 @@ MANOREFIX = $(PREFIX)/share/man
        
        SRC = csv.c drawille.c font.c font13.c font8.c util.c
        INC = csv.h drawille.h font.h util.h
       -BIN = ploot-feed ploot-braille ploot-text # ploot-farbfeld
       +BIN = ploot-feed ploot-braille ploot-text  ploot-farbfeld
        OBJ = ${SRC:.c=.o}
        
        all: ${BIN}
 (DIR) diff --git a/csv.c b/csv.c
       @@ -9,9 +9,34 @@
        #include "util.h"
        
        /*
       - * Read CSV data onto a set of (struct csv).
       + * Read CSV data onto a set of (struct csv) and some utilities to work on these data.
         */
        
       +int
       +csv_min_max(struct csv *vl, int ncol,
       +        time_t *tmin, time_t *tmax,
       +        double *vmin, double *vmax)
       +{
       +        double *v;
       +        time_t *t;
       +        size_t n;
       +
       +        *vmin = *vmax = 0; /* always show 0 on the scale */
       +        *tmin = *tmax = *vl->t;
       +
       +        for (; ncol > 0; ncol--, vl++) {
       +                for (t = vl->t, v = vl->v, n = vl->n; n > 0; t++, v++, n--) {
       +                        if (*v < *vmin) *vmin = *v;
       +                        if (*v > *vmax) *vmax = *v;
       +                        if (*t < *tmin) *tmin = *t;
       +                        if (*t > *tmax) *tmax = *t;
       +                }
       +        }
       +        if (*tmin == *tmax)
       +                return -1;
       +        return 0;
       +}
       +
        static void
        csv_add_time(struct csv *vl, time_t epoch)
        {
 (DIR) diff --git a/csv.h b/csv.h
       @@ -17,5 +17,6 @@ struct csv {
        
        void        csv_labels(FILE *, struct csv **, size_t *);
        void        csv_values(FILE *, struct csv *, size_t);
       +int        csv_min_max(struct csv *, int, time_t *, time_t *, double *, double *);
        
        #endif
 (DIR) diff --git a/example.png b/example.png
       Binary files differ.
 (DIR) diff --git a/ploot-braille.c b/ploot-braille.c
       @@ -15,85 +15,6 @@
        #define pledge(...) 0
        #endif
        
       -static int
       -get_min_max(struct csv *vl, int ncol,
       -        time_t *tmin, time_t *tmax,
       -        double *vmin, double *vmax)
       -{
       -        double *v;
       -        time_t *t;
       -        size_t n;
       -
       -        *vmin = *vmax = 0; /* always show 0 on the scale */
       -        *tmin = *tmax = *vl->t;
       -
       -        for (; ncol > 0; ncol--, vl++) {
       -                for (t = vl->t, v = vl->v, n = vl->n; n > 0; t++, v++, n--) {
       -                        if (*v < *vmin) *vmin = *v;
       -                        if (*v > *vmax) *vmax = *v;
       -                        if (*t < *tmin) *tmin = *t;
       -                        if (*t > *tmax) *tmax = *t;
       -                }
       -        }
       -        if (*tmin == *tmax)
       -                return -1;
       -        return 0;
       -}
       -
       -static time_t
       -time_mark_step(time_t min, time_t max, int dots)
       -{
       -        time_t dt, scale[] = {
       -                1, 5, 2, 10, 20, 30, 60, 60*2, 60*5, 60*10, 60*20, 60*30, 3600, 
       -                3600*2, 3600*6, 3600*12, 3600*24, 3600*24*2, 
       -                3600*24*7, 3600*24*14, 3600*24*20, 3600*24*21, 3600*24*28, 3600*24*50,
       -                3600*24*100, 3600*24*365, 0
       -        };
       -
       -        dt = max - min;
       -        for (time_t *sc = scale; *sc > 0; sc++)
       -                if (dt < *sc * dots)
       -                        return *sc;
       -        return dt / dots;
       -}
       -
       -/*
       - * Make the value scale aligned with round values by changing the
       - * minimal and maximal values.
       - */
       -static void
       -adjust_scale(double *min, double *max, int rows)
       -{
       -        double dv, step, scale[] = { 1, 2, 2.5, 5, };
       -
       -        dv = *max - *min;
       -
       -        step = 1;
       -        if (dv > 1) {
       -                for (double mant = 1;; mant *= 10) {
       -                        double *sc = scale;
       -                        for (; sc < scale + LEN(scale); sc++) {
       -                                step = mant * *sc;
       -                                if (dv < rows * step)
       -                                        goto end;
       -                        }
       -                }
       -        } else {
       -                for (double mant = 1;; mant /= 10) {
       -                        double *sc = scale + LEN(scale) - 1;
       -                        for (; sc >= scale; sc--) {
       -                                double tmp = mant * *sc;
       -                                if (dv > rows * tmp)
       -                                        goto end;
       -                                step = tmp;
       -                        }
       -                }
       -        }
       -end:
       -        *min = (int)(*min / step) * step;
       -        *max = *min + step * rows;
       -}
       -
        /*
         * Plot the body as an histogram interpolating the gaps and include
         * a vertical and horizontal axis.
       @@ -185,17 +106,20 @@ braille_render(struct drawille *drw, FILE *fp, double min, double max)
        static void
        plot(struct csv *vl, size_t ncol, int rows, int cols, FILE *fp)
        {
       -        double vmin, vmax;
       +        double vmin, vmax, vstep;
                time_t tmin, tmax, tstep;
                struct drawille *drw;
        
                rows = MAX(rows, 2);        /* readable */
        
       -        if (get_min_max(vl, ncol, &tmin, &tmax, &vmin, &vmax) < 0)
       +        if (csv_min_max(vl, ncol, &tmin, &tmax, &vmin, &vmax) < 0)
                        err(1, "invalid scale: tmin=%lld tmax=%lld vmin=%fd vmax=%fd",
                            (long long)tmin, (long long)tmax, vmin, vmax);
       -        adjust_scale(&vmin, &vmax, rows);
       -        tstep = time_mark_step(tmin, tmax, cols);
       +
       +        tstep = scale_time_t(tmin, tmax, cols);
       +        vstep = scale_double(vmin, vmax, rows);
       +        vmin = (int)(vmin / vstep) * vstep;
       +        vmax = vmin + vstep * rows;
        
                for (; ncol > 0; vl++, ncol--) {
                        if ((drw = drawille_new(rows, cols)) == NULL)
 (DIR) diff --git a/ploot-farbfeld.1 b/ploot-farbfeld.1
       @@ -13,7 +13,6 @@
        .
        .Nm ploot-ffplot
        .Op Fl t Ar title
       -.Op Fl u Ar unit
        .Ar colors...
        .
        .
       @@ -28,9 +27,6 @@ utility plots an image in the ffplot format out of csv values coming from stdin.
        .It Fl t
        Set the title of the plot printed at the top left corner.
        .
       -.It Fl u
       -Set the unit description printed at the top right corner.
       -.
        .It Ar colors
        List of argument that specify the color for each column.
        If the input csv have 5 columns in addition of the timestamp, there must
 (DIR) diff --git a/ploot-farbfeld.c b/ploot-farbfeld.c
       @@ -13,24 +13,23 @@
        #include <unistd.h>
        #include "csv.h"
        #include "font.h"
       -#include "scale.h"
        #include "util.h"
        
        #ifndef __OpenBSD__
        #define pledge(...) 0
        #endif
        
       -#define MARGIN                4
       +#define MARGIN                8
        
        #define IMAGE_H                (TITLE_H + PLOT_H + XLABEL_H)
       -#define IMAGE_W                (YLABEL_W + PLOT_W + LEGEND_W)
       +#define IMAGE_W                (MARGIN + YLABEL_W + PLOT_W + MARGIN)
        
       -#define TITLE_X                (YLABEL_W)
       -#define TITLE_Y                (IMAGE_H - TITLE_H)
       +#define TITLE_X                (MARGIN)
       +#define TITLE_Y                (IMAGE_H - TITLE_H / 2)
        #define TITLE_H                ((font)->height * 2)
        #define TITLE_W                (PLOT_W)
        
       -#define YLABEL_X        (0)
       +#define YLABEL_X        (MARGIN)
        #define YLABEL_Y        (PLOT_Y)
        #define YLABEL_H        (PLOT_H)
        #define YLABEL_W        (40 + MARGIN)
       @@ -40,14 +39,13 @@
        #define XLABEL_H        ((font)->height * 2)
        #define XLABEL_W        (PLOT_W)
        
       -#define PLOT_X                (YLABEL_W)
       +#define PLOT_X                (YLABEL_X + YLABEL_W)
        #define PLOT_Y                (XLABEL_H)
        #define PLOT_W                (700)
        #define PLOT_H                (160)
        
       -#define LEGEND_X        (IMAGE_W - LEGEND_W)
       -#define LEGEND_Y        (TITLE_H + PLOT_H - (font)->height)
       -#define LEGEND_W        (100)
       +#define LEGEND_X        (IMAGE_W / 2)
       +#define LEGEND_Y        (TITLE_Y)
        #define LEGEND_H        (PLOT_H)
        
        struct ffcolor {
       @@ -76,8 +74,7 @@ static struct colorname {
                { NULL, { 0, 0, 0, 0 } }
        };
        
       -static char *tflag = "";
       -static char *uflag = "";
       +static char *flag_title = "";
        static struct font *font = &font13;
        
        /*
       @@ -212,7 +209,7 @@ ffplot_print(FILE *fp, struct ffplot *plot)
                w = htonl(plot->w);
                h = htonl(plot->h);
        
       -        fprintf(stdout, "ffplot");
       +        fprintf(stdout, "farbfeld");
                fwrite(&w, sizeof(w), 1, fp);
                fwrite(&h, sizeof(h), 1, fp);
                fwrite(plot->buf, plot->w * plot->h, sizeof(*plot->buf), fp);
       @@ -284,12 +281,9 @@ ffplot_yaxis(struct ffplot *plot, struct ffcolor *label, struct ffcolor *grid,
        }
        
        static void
       -ffplot_title(struct ffplot *plot,
       -        struct ffcolor *ct, char *title,
       -        struct ffcolor *cu, char *unit)
       +ffplot_title(struct ffplot *plot, struct ffcolor *ct, char *title)
        {
                ffplot_text_left(plot, ct, font, title, TITLE_H / 2, 0);
       -        ffplot_text_right(plot, cu, font, unit, TITLE_H / 2, TITLE_W);
        }
        
        static void
       @@ -329,27 +323,26 @@ ffplot_legend(struct ffplot *plot, struct ffcolor *fg, struct csv *vl, struct ff
        {
                size_t x, y;
        
       +        x = y = 0;
                for (; ncol > 0; ncol--, vl++, cl++) {
       -                y = -(ncol - 1) * (font->height + MARGIN);
       -                x = MARGIN * 2;
                        x = ffplot_text_left(plot, *cl, font, "-", x, y) + MARGIN;
                        x = ffplot_text_left(plot, fg, font, vl->label, x, y);
       +                x = ffplot_text_left(plot, fg, font, "   ", x, y);
                }
        }
        
        /*
       - * Plot the 'n' values list of the 'v' arrax with title 'name' and
       - * 'units' label.
       + * Plot the 'n' values list of the 'v' arrax with title 'name' label.
         *
       - *               Title       (units)
       - *             x ^                    Legend
       - *         label | - + - + - + - + -   ....
       - *          here | - + - + - + - + -   ....
       + *               Title      Legend
       + *             x ^                   
       + *         label | - + - + - + - + -
       + *          here | - + - + - + - + -
         *               +---+---+---+---+-->
         *                x label here        
         */
        static void
       -plot(struct csv *vl, struct ffcolor **cl, size_t ncol, char *name, char *units)
       +plot(struct csv *vl, struct ffcolor **cl, size_t ncol, char *name)
        {
                struct ffplot plot = { IMAGE_W, IMAGE_H, 0, 0, NULL };
                struct ffcolor plot_bg = { 0x2222, 0x2222, 0x2222, 0xffff };
       @@ -360,9 +353,9 @@ plot(struct csv *vl, struct ffcolor **cl, size_t ncol, char *name, char *units)
                double vmin, vmax, vstep;
                time_t tmin, tmax, tstep;
        
       -        scale_minmax(vl, ncol, &tmin, &tmax, &vmin, &vmax);
       -        tstep = scale_tstep(tmin, tmax, 7);
       -        vstep = scale_vstep(vmin, vmax, 7);
       +        csv_min_max(vl, ncol, &tmin, &tmax, &vmin, &vmax);
       +        tstep = scale_time_t(tmin, tmax, 7);
       +        vstep = scale_double(vmin, vmax, 7);
        
                if ((plot.buf = calloc(IMAGE_H * IMAGE_W, sizeof *plot.buf)) == NULL)
                        err(1, "calloc: %s", strerror(errno));
       @@ -385,7 +378,7 @@ plot(struct csv *vl, struct ffcolor **cl, size_t ncol, char *name, char *units)
        
                plot.x = TITLE_X;
                plot.y = TITLE_Y;
       -        ffplot_title(&plot, &title_fg, name, &label_fg, units);
       +        ffplot_title(&plot, &title_fg, name);
        
                plot.x = PLOT_X;
                plot.y = PLOT_Y;
       @@ -420,7 +413,7 @@ argv_to_color(struct ffcolor **cl, char **argv)
        static void
        usage(void)
        {
       -        fprintf(stderr, "usage: %s [-t title] [-u unit] {", arg0);
       +        fprintf(stderr, "usage: %s [-t title] {", arg0);
                fputs(colorname->name, stderr);
                for (struct colorname *cn = colorname + 1; cn->name != NULL; cn++)
                        fprintf(stderr, ",%s", cn->name);
       @@ -440,13 +433,10 @@ main(int argc, char **argv)
                        err(1, "pledge: %s", strerror(errno));
        
                arg0 = *argv;
       -        while ((c = getopt(argc, argv, "t:u:")) > -1) {
       +        while ((c = getopt(argc, argv, "t:")) > -1) {
                        switch (c) {
                        case 't':
       -                        tflag = optarg;
       -                        break;
       -                case 'u':
       -                        uflag = optarg;
       +                        flag_title = optarg;
                                break;
                        default:
                                usage();
       @@ -469,7 +459,7 @@ main(int argc, char **argv)
                csv_values(stdin, vl, ncol);
                argv_to_color(cl, argv);
        
       -        plot(vl, cl, argc, tflag, uflag);
       +        plot(vl, cl, argc, flag_title);
        
                free(vl);
                free(cl);
 (DIR) diff --git a/util.c b/util.c
       @@ -1,4 +1,5 @@
        #include "util.h"
       +#include <assert.h>
        #include <ctype.h>
        #include <errno.h>
        #include <limits.h>
       @@ -122,3 +123,55 @@ humanize(char *str, double val)
        
                return exp * 3;
        }
       +
       +time_t
       +scale_time_t(time_t min, time_t max, int dots)
       +{
       +        time_t dt, scale[] = {
       +                1, 5, 2, 10, 20, 30, 60, 60*2, 60*5, 60*10, 60*20, 60*30, 3600, 
       +                3600*2, 3600*6, 3600*12, 3600*24, 3600*24*2, 
       +                3600*24*7, 3600*24*14, 3600*24*20, 3600*24*21, 3600*24*28, 3600*24*50,
       +                3600*24*100, 3600*24*365, 0
       +        };
       +
       +        dt = max - min;
       +        for (time_t *sc = scale; *sc > 0; sc++)
       +                if (dt < *sc * dots)
       +                        return *sc;
       +        return dt / dots;
       +}
       +
       +/*
       + * Make the value scale aligned with round values by changing the
       + * minimal and maximal values.
       + */
       +double
       +scale_double(double min, double max, int rows)
       +{
       +        double dv, step, scale[] = { 1, 2, 2.5, 5, };
       +
       +        dv = max - min;
       +        step = 1;
       +        if (dv > 1) {
       +                for (double mant = 1;; mant *= 10) {
       +                        double *sc = scale;
       +                        for (; sc < scale + LEN(scale); sc++) {
       +                                step = mant * *sc;
       +                                if (dv < rows * step)
       +                                        return step;
       +                        }
       +                }
       +        } else {
       +                for (double mant = 1;; mant /= 10) {
       +                        double *sc = scale + LEN(scale) - 1;
       +                        for (; sc >= scale; sc--) {
       +                                double tmp = mant * *sc;
       +                                if (dv > rows * tmp)
       +                                        return step;
       +                                step = tmp;
       +                        }
       +                }
       +        }
       +        assert(!"not reached");
       +        return 0;
       +}
 (DIR) diff --git a/util.h b/util.h
       @@ -2,6 +2,7 @@
        #define TOOL_H
        
        #include <stddef.h>
       +#include <time.h>
        
        #define LEN(x) (sizeof(x) / sizeof(*x))
        #define MAX(x, y) ((x) > (y) ? (x) : (y))
       @@ -18,5 +19,7 @@ void         put3utf(long);
        char        *strsep(char **, const char *);
        void         strchomp(char *);
        int         humanize(char *, double);
       +time_t         scale_time_t(time_t, time_t, int);
       +double         scale_double(double, double, int);
        
        #endif