fix the horizontal scale - ploot - simple plotting tools HTML git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot DIR Log DIR Files DIR Refs DIR Tags DIR README DIR LICENSE --- DIR commit 26a6e01805dd158f9f97be0cc9bf43f3d5b6db37 DIR parent 1d056caf74acaf182318297e2911fa8595fbd45c HTML Author: Josuah Demangeon <me@josuah.net> Date: Tue, 3 Mar 2020 21:26:54 +0100 fix the horizontal scale Diffstat: M Makefile | 18 +++++++++--------- M ploot-braille.c | 26 +++++++++++++++----------- A ploot-csv.5 | 77 +++++++++++++++++++++++++++++++ D ploot-csv.7 | 77 ------------------------------- M ploot-farbfeld.c | 6 ++++-- M ploot-feed.c | 2 +- M ploot-text.c | 2 +- M src/csv.c | 2 +- M src/ffplot.c | 2 +- M src/scale.c | 84 +++++++------------------------ M src/scale.h | 8 +++----- D src/tool.c | 80 ------------------------------- A src/util.c | 80 +++++++++++++++++++++++++++++++ R src/tool.h -> src/util.h | 0 14 files changed, 211 insertions(+), 253 deletions(-) --- DIR diff --git a/Makefile b/Makefile @@ -1,27 +1,27 @@ include config.mk src = src/csv.c src/drawille.c src/ffplot.c src/font.c src/font13.c \ - src/font8.c src/log.c src/scale.c src/tool.c + src/font8.c src/log.c src/scale.c src/util.c inc = src/csv.h src/drawille.h src/ffplot.h src/font.h src/log.h \ - src/scale.h src/tool.h + src/scale.h src/util.h bin = ploot-farbfeld ploot-feed ploot-braille ploot-text obj = ${src:.c=.o} lib = -lm -all: $(bin) +all: ${bin} .c.o: ${CC} -c ${CFLAGS} -o $@ $< ${obj} ${bin:=.o}: ${inc} Makefile ${bin}: ${obj} ${bin:=.o} - ${CC} $(LFLAGS) -o $@ $@.o ${obj} $(lib) + ${CC} ${LFLAGS} -o $@ $@.o ${obj} ${lib} -install: $(bin) - mkdir -p ${PREFIX}/bin $(MANDIR)/man1 $(MANDIR)/man7 - cp $(bin) ${PREFIX}/bin - cp ploot-farbfeld.1 ploot-feed.1 $(MANDIR)/man1 - cp ploot-csv.7 $(MANDIR)/man7 +install: ${bin} + mkdir -p ${PREFIX}/bin ${MANDIR}/man1 ${MANDIR}/man5 + cp ${bin} ${PREFIX}/bin + cp *.1 ${MANDIR}/man1 + cp *.5 ${MANDIR}/man7 clean: rm -f *.o */*.o ${bin} DIR diff --git a/ploot-braille.c b/ploot-braille.c @@ -10,7 +10,7 @@ #include "drawille.h" #include "scale.h" -#include "tool.h" +#include "util.h" #include "log.h" char const *arg0 = NULL; @@ -104,23 +104,26 @@ braille_render(struct drawille *drw, FILE *fp, double vmin, double vmax) } static void -plot(struct csv *vl, FILE *fp, size_t ncol, int row, int col) +plot(struct csv *vl, FILE *fp, size_t ncol, int rows, int cols) { double vmin, vmax, vstep; time_t tmin, tmax, tstep; struct drawille *drw; - col -= 8; + cols -= 8; /* scale printed at the right */ - scale(vl, ncol, &tmin, &tmax, &tstep, &vmin, &vmax, &vstep); - row -= ncol - 1; /* room for the labels and the scale */ - row /= ncol; /* plot <ncol> times */ - row = MAX(row, 3); /* readable */ + scale_minmax(vl, ncol, &tmin, &tmax, &vmin, &vmax); + tstep = scale_tstep(tmin, tmax, cols / 10); + vstep = scale_vstep(vmin, vmax, rows / 10); - debug("vstep=%lf vstep=%ld ncol=%zu row=%zu", vstep, tstep, ncol, row); + rows -= ncol - 1; /* room for the labels and the scale */ + rows /= ncol; /* plot <ncol> times */ + rows = MAX(rows, 3); /* readable */ + + debug("vstep=%lf vstep=%ld ncol=%zu rows=%zu", vstep, tstep, ncol, rows); for (; ncol > 0; vl++, ncol--) { - assert(drw = drawille_new(row, col)); + assert(drw = drawille_new(rows, cols)); fprintf(fp, " %s\n", vl->label); if (braille_histogram(vl, drw, tmin, tmax, vmin, vmax) == -1) die(1, "allocating drawille canvas"); @@ -128,7 +131,7 @@ plot(struct csv *vl, FILE *fp, size_t ncol, int row, int col) die(1, "rendering braille canvas"); free(drw); } - if (braille_axis_x(fp, tmin, tmax, tstep, col) == -1) + if (braille_axis_x(fp, tmin, tmax, tstep, cols) == -1) die(1, "printing x axis");; } @@ -136,7 +139,7 @@ plot(struct csv *vl, FILE *fp, size_t ncol, int row, int col) static void usage(void) { - fprintf(stderr, "usage: %s\n", arg0); + fprintf(stderr, "usage: %s [-r rows] [-c cols]\n", arg0); exit(1); } @@ -148,6 +151,7 @@ main(int argc, char **argv) int c, rows, cols; rows = 20, cols = 80; + arg0 = *argv; optind = 0; while ((c = getopt(argc, argv, "r:c:")) > -1) { switch (c) { DIR diff --git a/ploot-csv.5 b/ploot-csv.5 @@ -0,0 +1,77 @@ +.Dd $Mdocdate: February 01 2020$ +.Dt PLOOT-CSV 5 +.Os +. +. +.Sh NAME +. +.Nm ploot-csv +.Nd input format used by the ploot set of programs +. +. +.Sh SYNOPSIS +. +.Bd -literal +epoch,column-name-1,column-name-2 +timestamp,value1,value2 +timestamp,value1,value2 +… +.Ed +. +. +.Sh DESCRIPTION +. +This is the simple comma-separated format used by the ploot-* programs. +. +. +.Sh INPUT FORMAT +. +.Nm +has a first header line, then zero or more data lines, both +comma-separated list of values. +. +. +.Ss Header line +. +The input must contain a first header line with the label of each column in order. +The first column is always +.Dq epoch . +Then there are the actual column names. +. +.Bd -literal -offset indent +epoch,free_memory,process_count +.Ed +. +. +.Ss Data lines +. +The following lines are the data. +The first column is always an unix timestamp as in +.Vt time_t . +The remaining columns are values parsed as floating point numbers by +.Xr strtod 3 : +. +.Bd -literal -offset indent +1533752053,16.3,45 +1533752054,18.7,42 +1533752055,40.1,39 +1533752056,40.1,39 +.Ed +. +. +.Sh SEE ALSO +. +.Xr ploot-feed 1 , +.Xr ploot-farbfeld 1 +. +.Sh HISTORY +. +.Nm +was defined at +.Lk gopher://bitreich.org/1/scm/ploot/ "Bitreich" +. +. +.Sh AUTHORS +. +.An Josuah Demangeon +.Aq Mt me@josuah.net DIR diff --git a/ploot-csv.7 b/ploot-csv.7 @@ -1,77 +0,0 @@ -.Dd $Mdocdate: February 01 2020$ -.Dt PLOOT-CSV 7 -.Os -. -. -.Sh NAME -. -.Nm ploot-csv -.Nd input format used by the ploot set of programs -. -. -.Sh SYNOPSIS -. -.Bd -literal -epoch,column-name-1,column-name-2 -timestamp,value1,value2 -timestamp,value1,value2 -… -.Ed -. -. -.Sh DESCRIPTION -. -This is the simple comma-separated format used by the ploot-* programs. -. -. -.Sh INPUT FORMAT -. -.Nm -has a first header line, then zero or more data lines, both -comma-separated list of values. -. -. -.Ss Header line -. -The input must contain a first header line with the label of each column in order. -The first column is always -.Dq epoch . -Then there are the actual column names. -. -.Bd -literal -offset indent -epoch,free_memory,process_count -.Ed -. -. -.Ss Data lines -. -The following lines are the data. -The first column is always an unix timestamp as in -.Vt time_t . -The remaining columns are values parsed as floating point numbers by -.Xr strtod 3 : -. -.Bd -literal -offset indent -1533752053,16.3,45 -1533752054,18.7,42 -1533752055,40.1,39 -1533752056,40.1,39 -.Ed -. -. -.Sh SEE ALSO -. -.Xr ploot-feed 1 , -.Xr ploot-farbfeld 1 -. -.Sh HISTORY -. -.Nm -was defined at -.Lk gopher://bitreich.org/1/scm/ploot/ "Bitreich" -. -. -.Sh AUTHORS -. -.An Josuah Demangeon -.Aq Mt me@josuah.net DIR diff --git a/ploot-farbfeld.c b/ploot-farbfeld.c @@ -15,7 +15,7 @@ #include "ffplot.h" #include "font.h" #include "log.h" -#include "tool.h" +#include "util.h" #include "scale.h" #define MARGIN 4 @@ -211,7 +211,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(vl, ncol, &tmin, &tmax, &tstep, &vmin, &vmax, &vstep); + scale_minmax(vl, ncol, &tmin, &tmax, &vmin, &vmax); + tstep = scale_tstep(tmin, tmax, 7); + vstep = scale_vstep(vmin, vmax, 7); assert(plot.buf = calloc(IMAGE_H * IMAGE_W, sizeof *plot.buf)); DIR diff --git a/ploot-feed.c b/ploot-feed.c @@ -9,7 +9,7 @@ #include <time.h> #include <unistd.h> -#include "tool.h" +#include "util.h" #include "log.h" #define WIDTH_MAX 1024 DIR diff --git a/ploot-text.c b/ploot-text.c @@ -5,7 +5,7 @@ #include "drawille.h" #include "font.h" -#include "tool.h" +#include "util.h" char *arg0 = NULL; DIR diff --git a/src/csv.c b/src/csv.c @@ -9,7 +9,7 @@ #include <time.h> #include "log.h" -#include "tool.h" +#include "util.h" /* * Read CSV data onto a set of (struct csv). DIR diff --git a/src/ffplot.c b/src/ffplot.c @@ -7,7 +7,7 @@ #include <stdint.h> #include "font.h" -#include "tool.h" +#include "util.h" /* * Convert (x,y) coordinates to (row,col) for printing into the buffer. DIR diff --git a/src/scale.c b/src/scale.c @@ -3,7 +3,7 @@ #include <stddef.h> #include <time.h> -#include "tool.h" +#include "util.h" #include "log.h" /* @@ -31,7 +31,7 @@ scale_xpos(time_t t, time_t t1, time_t t2, int szx) return szx * (t - t1) / (t2 - t1); } -static void +void scale_minmax(struct csv *vl, int ncol, time_t *tmin, time_t *tmax, double *vmin, double *vmax) @@ -56,10 +56,10 @@ scale_minmax(struct csv *vl, int ncol, die(1, "invalid time scale: min=%lld max=%lld", *tmin, *tmax); } -static time_t -scale_tstep(time_t min, time_t max, int density) +time_t +scale_tstep(time_t min, time_t max, int nval) { - time_t dt, *s, scale[] = { + time_t dt, *sc, 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, @@ -67,75 +67,29 @@ scale_tstep(time_t min, time_t max, int density) }; dt = max - min; - for (s = scale; s < scale + LEN(scale); s++) - if (dt < *s * density) - return *s; - return 0; + + for (sc = scale; *sc > 0; sc++) + if (dt < *sc * nval) + return *sc; + return dt / nval; } -static double -scale_vstep(double min, double max, int density) +double +scale_vstep(double min, double max, int nval) { - double dv, d, *s, scale[] = { 1, 2, 3, 5 }; + double dv, d, *sc, scale[] = { 1, 2, 3, 5 }; dv = max - min; if (dv > 1) for (d = 1; d != 0; d *= 10) - for (s = scale; s < scale + LEN(scale); s++) - if (dv < *s * d * density) - return *s * d; + for (sc = scale; sc < scale + LEN(scale); sc++) + if (dv < *sc * d * nval) + return *sc * d; if (dv < 1) for (d = 1; d != 0; d *= 10) - for (s = scale + LEN(scale) - 1; s >= scale; s--) - if (dv > *s / d * density / 2) - return *s / d; + for (sc = scale + LEN(scale) - 1; sc >= scale; sc--) + if (dv > *sc / d * nval / 2) + return *sc / d; return 0; } - -/* - * Adjust the vertical scale so that everything fits, with nice - * scale values. - */ -void -scale_vminmax(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; -} - -void -scale(struct csv *vl, int ncol, - time_t *tmin, time_t *tmax, time_t *tstep, - double *vmin, double *vmax, double *vstep) -{ - scale_minmax(vl, ncol, tmin, tmax, vmin, vmax); - *tstep = scale_tstep(*tmin, *tmax, SCALE_X); - *vstep = scale_vstep(*vmin, *vmax, SCALE_Y); -} DIR diff --git a/src/scale.h b/src/scale.h @@ -6,13 +6,11 @@ #include "csv.h" -#define SCALE_X 7 /* nb of values on x axis */ -#define SCALE_Y 7 /* nb of values on y axis */ - /**/ int scale_ypos (double, double, double, int); int scale_xpos (time_t, time_t, time_t, int); -void scale_vminmax (double *, double *, int); -void scale (struct csv *, int, time_t *, time_t *, time_t *, double *, double *, double *); +void scale_minmax (struct csv *, int, time_t *, time_t *, double *, double *); +time_t scale_tstep (time_t, time_t, int); +double scale_vstep (double, double, int); #endif DIR diff --git a/src/tool.c b/src/tool.c @@ -1,80 +0,0 @@ -#include "tool.h" - -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -size_t -strlcpy(char *buf, const char *str, size_t sz) -{ - size_t len, cpy; - - cpy = ((len = strlen(str)) > sz) ? (sz) : (len); - memcpy(buf, str, cpy); - buf[sz - 1] = '\0'; - return len; -} - -void -put3utf(long rune) -{ - putchar((char)(0xe0 | (0x0f & (rune >> 12)))); /* 1110xxxx */ - putchar((char)(0x80 | (0x3f & (rune >> 6)))); /* 10xxxxxx */ - putchar((char)(0x80 | (0x3f & (rune)))); /* 10xxxxxx */ -} - -char * -strsep(char **strp, const char *sep) -{ - char *s, *prev; - - if (*strp == NULL) - return NULL; - for (s = prev = *strp; strchr(sep, *s) == NULL; s++); - if (*s == '\0') { - *strp = NULL; - return prev; - } - *s = '\0'; - *strp = s + 1; - - return prev; -} - -void -strchomp(char *s) -{ - char *x = s + strlen(s); - - while (--x >= s && (*x == '\r' || *x == '\n')) - *x = '\0'; -} - -/* - * Set 'str' to a human-readable form of 'num' with always a width of 8 (+1 for - * the '\0' terminator). Buffer overflow is ensured not to happen due to the - * max size of a double. Return the exponent. - */ -int -humanize(char *str, double val) -{ - int exp, precision; - char label[] = { '\0', 'M', 'G', 'T', 'E' }; - - for (exp = 0; ABS(val) > 1000; exp++) - val /= 1000; - - precision = (ABS(val) < 10) ? 2 : (ABS(val) < 100) ? 1 : 0; - precision += (exp == 0); - - snprintf(str, 9, "%+.*f %c", precision, val, label[exp]); - str[8] = '\0'; - if (val >= 0) - str[0] = ' '; - - return exp * 3; -} DIR diff --git a/src/util.c b/src/util.c @@ -0,0 +1,80 @@ +#include "util.h" + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +size_t +strlcpy(char *buf, const char *str, size_t sz) +{ + size_t len, cpy; + + cpy = ((len = strlen(str)) > sz) ? (sz) : (len); + memcpy(buf, str, cpy); + buf[sz - 1] = '\0'; + return len; +} + +void +put3utf(long rune) +{ + putchar((char)(0xe0 | (0x0f & (rune >> 12)))); /* 1110xxxx */ + putchar((char)(0x80 | (0x3f & (rune >> 6)))); /* 10xxxxxx */ + putchar((char)(0x80 | (0x3f & (rune)))); /* 10xxxxxx */ +} + +char * +strsep(char **strp, const char *sep) +{ + char *s, *prev; + + if (*strp == NULL) + return NULL; + for (s = prev = *strp; strchr(sep, *s) == NULL; s++); + if (*s == '\0') { + *strp = NULL; + return prev; + } + *s = '\0'; + *strp = s + 1; + + return prev; +} + +void +strchomp(char *s) +{ + char *x = s + strlen(s); + + while (--x >= s && (*x == '\r' || *x == '\n')) + *x = '\0'; +} + +/* + * Set 'str' to a human-readable form of 'num' with always a width of 8 (+1 for + * the '\0' terminator). Buffer overflow is ensured not to happen due to the + * max size of a double. Return the exponent. + */ +int +humanize(char *str, double val) +{ + int exp, precision; + char label[] = { '\0', 'M', 'G', 'T', 'E' }; + + for (exp = 0; ABS(val) > 1000; exp++) + val /= 1000; + + precision = (ABS(val) < 10) ? 2 : (ABS(val) < 100) ? 1 : 0; + precision += (exp == 0); + + snprintf(str, 9, "%+.*f %c", precision, val, label[exp]); + str[8] = '\0'; + if (val >= 0) + str[0] = ' '; + + return exp * 3; +} DIR diff --git a/src/tool.h b/src/util.h