move from CSV to TSV - 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 98d0cb5aa9d2adb27b2a992e90debce8b3843c5b DIR parent 8836c19534760f2ce037c39bde9dc5591011ed07 HTML Author: Josuah Demangeon <me@josuah.net> Date: Sun, 27 Jun 2021 04:57:00 +0200 move from CSV to TSV Diffstat: M Makefile | 6 +++--- M README.md | 6 +++--- D csv.c | 154 ------------------------------- D csv.h | 22 ---------------------- D example.csv | 114 ------------------------------- M example.png | 0 A example.tsv | 114 +++++++++++++++++++++++++++++++ M ploot-braille.c | 14 +++++++------- D ploot-csv.5 | 77 ------------------------------- M ploot-farbfeld.1 | 10 +++++----- M ploot-farbfeld.c | 18 +++++++++--------- M ploot-feed.1 | 6 +++--- M ploot-feed.c | 10 +++++----- A ploot-tsv.5 | 77 +++++++++++++++++++++++++++++++ A tsv.c | 154 +++++++++++++++++++++++++++++++ A tsv.h | 22 ++++++++++++++++++++++ 16 files changed, 402 insertions(+), 402 deletions(-) --- DIR diff --git a/Makefile b/Makefile @@ -7,9 +7,9 @@ LFLAGS = -static -lm PREFIX = /usr/local 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 +SRC = tsv.c drawille.c font.c font13.c font8.c util.c +INC = tsv.h drawille.h font.h util.h +BIN = ploot-farbfeld ploot-feed ploot-braille ploot-text OBJ = ${SRC:.c=.o} all: ${BIN} DIR diff --git a/README.md b/README.md @@ -3,7 +3,7 @@ ploot ploot-ffplot -------------- -*ploot-ffplot* reads collectd-style comma separated values (CSV) and produces a plot +*ploot-ffplot* reads collectd-style comma separated values (TSV) and produces a plot in the ffplot [1] image format (pipe it to ff2png). It is an alternative to RRDtool [2]. @@ -16,12 +16,12 @@ name of the curves. ploot-feed ---------- -*ploot-feed* also reads collectd-style comma separated values (CSV) but produces +*ploot-feed* also reads collectd-style comma separated values (TSV) but produces a plain text continuous waterfall chart for live monitoring in the terminal. it is an alternative to grafana [1]. ``` -% plootxt 1 1 1 <load-average.csv +% plootxt 1 1 1 <load-average.tsv │shortterm │midterm │longterm │ 17:34:00 _│⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│⣯⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 18/05/01 │⣟⡁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ DIR diff --git a/csv.c b/csv.c @@ -1,154 +0,0 @@ -#include "csv.h" -#include <errno.h> -#include <assert.h> -#include <string.h> -#include <time.h> -#include <stdlib.h> -#include <limits.h> -#include <time.h> -#include "util.h" - -/* - * 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) -{ - void *mem; - - if ((mem = realloc(vl->t, (vl->n + 1) * sizeof *vl->t)) == NULL) - err(1, "realloc: %s", strerror(errno)); - vl->t = mem; - vl->t[vl->n] = epoch; -} - -static void -csv_add_val(struct csv *vl, double field) -{ - void *mem; - - if ((mem = realloc(vl->v, (vl->n + 1) * sizeof *vl->v)) == NULL) - err(1, "", strerror(errno)); - vl->v = mem; - vl->v[vl->n] = field; -} - -/* - * Add to each column the value on the current row. The time_t - * buffer is shared among all fields. - */ -static void -csv_add_row(struct csv *vl, size_t ncol, char *line) -{ - char *field; - time_t *tbuf; - long l; - double d; - - if ((field = strsep(&line, ",")) == NULL) - err(1, "missing epoch at row %zu", vl->n); - - l = strtol(field, NULL, 10); - if (errno) - err(100, "parsing number '%s'", field); - - csv_add_time(vl, l); - tbuf = vl[0].t; - for (; (field = strsep(&line, ",")); ncol--, vl->n++, vl++) { - if (ncol == 0) - err(1, "too many fields at line %zu", vl->n); - d = strtod(field, NULL); - if (errno) - err(100, "parsing double '%s'", field); - csv_add_val(vl, d); - vl->t = tbuf; - } - if (ncol > 0) - err(1, "too few fields at line %zu", vl->n); -} - -/* - * < (ncol) > - * label1,label2,label3 - */ -void -csv_labels(FILE *fp, struct csv **vlp, size_t *ncol) -{ - char *field, *line, *cp; - struct csv *vl, *col; - size_t sz; - ssize_t r; - - sz = 0, line = NULL; - r = getline(&line, &sz, fp); - if (ferror(fp)) - err(111, "error while reading from file"); - if (feof(fp)) - err(100, "missing label line"); - strchomp(line); - - cp = line; - if (strcmp(strsep(&cp, ","), "epoch") != 0) - err(1, "first label must be 'epoch'"); - - sz = 0, vl = NULL, *ncol = 0; - while ((field = strsep(&cp, ","))) { - if ((vl = realloc(vl, sz += sizeof *vl)) == NULL) - err(1, "realloc: %s", strerror(errno)); - col = vl + (*ncol)++; - memset(col, 0, sizeof *vl); - strlcpy(col->label, field, sizeof col->label); - } - free(line); - *vlp = vl; -} - -/* - * < (ncol) > - * val1a,val1b,val1c ^ - * val2a,val2b,val2c | - * val3a,val3b,val3c (vl->n) - * val4a,val4b,val4c | - * val5a,val5b,val5c v - */ -void -csv_values(FILE *fp, struct csv *vl, size_t ncol) -{ - char *line; - size_t sz; - - sz = 0, line = NULL; - while (getline(&line, &sz, fp) > -1) - csv_add_row(vl, ncol, line); - if (vl->n == 0) - err(1, "no value could be read"); - if (vl->n == 1) - err(1, "only one value could be read"); - free(line); -} DIR diff --git a/csv.h b/csv.h @@ -1,22 +0,0 @@ -#ifndef CSV_H -#define CSV_H - -#include <stdio.h> -#include <time.h> - -/* - * List of values and timestamps. Both have their dedicated buffer - * so that the timestamp buffer can be shared across csv objects. - */ -struct csv { - time_t *t; /* array of timestamps */ - double *v; /* array of values */ - size_t n; /* number of values */ - char label[64]; /* for the legend */ -}; - -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.csv b/example.csv @@ -1,114 +0,0 @@ -epoch,shortterm,midterm,longterm -1525186140,0.023804,0.056885,0.049561 -1525187040,0.035767,0.047485,0.043701 -1525187940,0.057861,0.050293,0.042480 -1525188840,0.098267,0.099609,0.072266 -1525189740,0.083618,0.091187,0.079468 -1525190640,0.055298,0.063843,0.063354 -1525191540,0.046875,0.056152,0.058960 -1525192440,0.091187,0.062622,0.058716 -1525193340,0.067871,0.060303,0.059937 -1525194240,0.085571,0.056763,0.052612 -1525195140,0.020874,0.054810,0.055176 -1525196040,0.125122,0.062500,0.048096 -1525196940,0.040649,0.041870,0.040649 -1525197840,0.032471,0.049194,0.042114 -1525198740,0.073853,0.088501,0.071045 -1525199640,0.119995,0.072998,0.064697 -1525200540,0.030518,0.043335,0.046265 -1525201440,0.037842,0.042969,0.040894 -1525202340,0.054810,0.049927,0.042358 -1525203240,0.120728,0.077271,0.053589 -1525204140,0.068970,0.086670,0.074585 -1525205040,0.071289,0.083496,0.079834 -1525205940,0.046265,0.059326,0.068848 -1525206840,0.064209,0.083374,0.069214 -1525207740,0.055054,0.046753,0.051758 -1525208640,0.170410,0.088867,0.064575 -1525209540,0.067627,0.092407,0.092163 -1525210440,0.078003,0.087646,0.083130 -1525211340,0.032959,0.043457,0.059204 -1525212240,0.036377,0.054810,0.057861 -1525213140,0.054565,0.078369,0.071655 -1525214040,0.026611,0.041138,0.051514 -1525214940,0.065186,0.067505,0.061768 -1525215840,0.071411,0.055298,0.055176 -1525229081,0.041260,0.045044,0.045654 -1525229081,0.041260,0.045044,0.045654 -1525229981,0.059692,0.102051,0.105835 -1525230881,0.077148,0.067017,0.073730 -1525231781,0.080200,0.074341,0.064575 -1525232681,0.122437,0.099487,0.075806 -1525233581,0.085815,0.076050,0.073486 -1525234481,0.074585,0.064087,0.062012 -1525235381,0.024902,0.047241,0.053345 -1525236281,0.107910,0.081543,0.065918 -1525237181,0.038696,0.075684,0.080688 -1525238081,0.204834,0.181152,0.130737 -1525238981,0.231445,0.158325,0.137695 -1525239881,0.067505,0.089355,0.109497 -1525240781,0.047852,0.088745,0.107910 -1525241681,0.094360,0.085693,0.083618 -1525242581,0.047363,0.043335,0.052856 -1525243481,0.047363,0.031982,0.036621 -1525244381,0.055054,0.042236,0.040039 -1525245281,0.034668,0.041626,0.040039 -1525246181,0.088867,0.065918,0.048706 -1525247081,0.049072,0.051880,0.042236 -1525247981,0.045166,0.048828,0.041382 -1525248881,0.067261,0.061768,0.047852 -1525249781,0.039917,0.056519,0.045654 -1525250681,0.017822,0.030273,0.033081 -1525251581,0.034668,0.033691,0.034546 -1525252481,0.053223,0.051880,0.045166 -1525253381,0.028687,0.050049,0.050659 -1525254281,0.021118,0.042358,0.040649 -1525255181,0.059204,0.047974,0.041870 -1525256081,0.206421,0.141968,0.086670 -1525256981,0.105713,0.087158,0.073486 -1525257881,0.048950,0.060913,0.068359 -1525258781,0.024414,0.036621,0.046753 -1525259681,0.245239,0.109619,0.071045 -1525260581,0.042236,0.063965,0.069092 -1525261481,0.016724,0.054077,0.059692 -1525262381,0.018433,0.078003,0.076660 -1525263281,0.042480,0.057617,0.061890 -1525264181,0.040161,0.041138,0.044189 -1525265081,0.059082,0.090698,0.064575 -1525265981,0.129272,0.080811,0.073486 -1525266881,0.228516,0.164551,0.112915 -1525267781,0.083130,0.058594,0.067627 -1525268681,0.062378,0.063965,0.061523 -1525269581,0.066895,0.069702,0.062500 -1525270481,0.061768,0.080322,0.065674 -1525271381,0.123657,0.089478,0.072021 -1525272281,0.056885,0.045532,0.051514 -1525273181,0.108887,0.056519,0.046387 -1525274081,0.072266,0.119629,0.080078 -1525274981,0.033447,0.058350,0.070190 -1525275881,0.028198,0.050781,0.058105 -1525276781,0.067261,0.059937,0.057495 -1525277681,0.024780,0.028809,0.038452 -1525278581,0.053955,0.049561,0.041748 -1525279481,0.086304,0.065308,0.048096 -1525281698,0.019165,0.047485,0.041870 -1525281698,0.019165,0.047485,0.041870 -1525282598,0.039551,0.034302,0.038086 -1525283498,0.017700,0.022827,0.026367 -1525284398,0.023560,0.034790,0.024292 -1525285298,0.093506,0.078857,0.053101 -1525286198,0.051025,0.066162,0.069458 -1525287098,0.054077,0.057861,0.059082 -1525287998,0.080200,0.071655,0.062744 -1525288898,0.478638,0.375122,0.247192 -1525289798,0.393066,0.390991,0.347046 -1525290698,0.368164,0.383545,0.365723 -1525291598,0.459229,0.463867,0.432129 -1525292498,0.286865,0.354980,0.381958 -1525293398,0.180786,0.178833,0.232910 -1525294298,0.278198,0.260864,0.242920 -1525295198,0.192505,0.183716,0.200806 -1525296098,0.109375,0.185669,0.207153 -1525296098,0.109375,0.185669,0.207153 -1525296998,0.137085,0.126221,0.138184 -1525297898,0.077881,0.092529,0.109619 DIR diff --git a/example.png b/example.png Binary files differ. DIR diff --git a/example.tsv b/example.tsv @@ -0,0 +1,114 @@ +epoch shortterm midterm longterm +1525186140 0.023804 0.056885 0.049561 +1525187040 0.035767 0.047485 0.043701 +1525187940 0.057861 0.050293 0.042480 +1525188840 0.098267 0.099609 0.072266 +1525189740 0.083618 0.091187 0.079468 +1525190640 0.055298 0.063843 0.063354 +1525191540 0.046875 0.056152 0.058960 +1525192440 0.091187 0.062622 0.058716 +1525193340 0.067871 0.060303 0.059937 +1525194240 0.085571 0.056763 0.052612 +1525195140 0.020874 0.054810 0.055176 +1525196040 0.125122 0.062500 0.048096 +1525196940 0.040649 0.041870 0.040649 +1525197840 0.032471 0.049194 0.042114 +1525198740 0.073853 0.088501 0.071045 +1525199640 0.119995 0.072998 0.064697 +1525200540 0.030518 0.043335 0.046265 +1525201440 0.037842 0.042969 0.040894 +1525202340 0.054810 0.049927 0.042358 +1525203240 0.120728 0.077271 0.053589 +1525204140 0.068970 0.086670 0.074585 +1525205040 0.071289 0.083496 0.079834 +1525205940 0.046265 0.059326 0.068848 +1525206840 0.064209 0.083374 0.069214 +1525207740 0.055054 0.046753 0.051758 +1525208640 0.170410 0.088867 0.064575 +1525209540 0.067627 0.092407 0.092163 +1525210440 0.078003 0.087646 0.083130 +1525211340 0.032959 0.043457 0.059204 +1525212240 0.036377 0.054810 0.057861 +1525213140 0.054565 0.078369 0.071655 +1525214040 0.026611 0.041138 0.051514 +1525214940 0.065186 0.067505 0.061768 +1525215840 0.071411 0.055298 0.055176 +1525229081 0.041260 0.045044 0.045654 +1525229081 0.041260 0.045044 0.045654 +1525229981 0.059692 0.102051 0.105835 +1525230881 0.077148 0.067017 0.073730 +1525231781 0.080200 0.074341 0.064575 +1525232681 0.122437 0.099487 0.075806 +1525233581 0.085815 0.076050 0.073486 +1525234481 0.074585 0.064087 0.062012 +1525235381 0.024902 0.047241 0.053345 +1525236281 0.107910 0.081543 0.065918 +1525237181 0.038696 0.075684 0.080688 +1525238081 0.204834 0.181152 0.130737 +1525238981 0.231445 0.158325 0.137695 +1525239881 0.067505 0.089355 0.109497 +1525240781 0.047852 0.088745 0.107910 +1525241681 0.094360 0.085693 0.083618 +1525242581 0.047363 0.043335 0.052856 +1525243481 0.047363 0.031982 0.036621 +1525244381 0.055054 0.042236 0.040039 +1525245281 0.034668 0.041626 0.040039 +1525246181 0.088867 0.065918 0.048706 +1525247081 0.049072 0.051880 0.042236 +1525247981 0.045166 0.048828 0.041382 +1525248881 0.067261 0.061768 0.047852 +1525249781 0.039917 0.056519 0.045654 +1525250681 0.017822 0.030273 0.033081 +1525251581 0.034668 0.033691 0.034546 +1525252481 0.053223 0.051880 0.045166 +1525253381 0.028687 0.050049 0.050659 +1525254281 0.021118 0.042358 0.040649 +1525255181 0.059204 0.047974 0.041870 +1525256081 0.206421 0.141968 0.086670 +1525256981 0.105713 0.087158 0.073486 +1525257881 0.048950 0.060913 0.068359 +1525258781 0.024414 0.036621 0.046753 +1525259681 0.245239 0.109619 0.071045 +1525260581 0.042236 0.063965 0.069092 +1525261481 0.016724 0.054077 0.059692 +1525262381 0.018433 0.078003 0.076660 +1525263281 0.042480 0.057617 0.061890 +1525264181 0.040161 0.041138 0.044189 +1525265081 0.059082 0.090698 0.064575 +1525265981 0.129272 0.080811 0.073486 +1525266881 0.228516 0.164551 0.112915 +1525267781 0.083130 0.058594 0.067627 +1525268681 0.062378 0.063965 0.061523 +1525269581 0.066895 0.069702 0.062500 +1525270481 0.061768 0.080322 0.065674 +1525271381 0.123657 0.089478 0.072021 +1525272281 0.056885 0.045532 0.051514 +1525273181 0.108887 0.056519 0.046387 +1525274081 0.072266 0.119629 0.080078 +1525274981 0.033447 0.058350 0.070190 +1525275881 0.028198 0.050781 0.058105 +1525276781 0.067261 0.059937 0.057495 +1525277681 0.024780 0.028809 0.038452 +1525278581 0.053955 0.049561 0.041748 +1525279481 0.086304 0.065308 0.048096 +1525281698 0.019165 0.047485 0.041870 +1525281698 0.019165 0.047485 0.041870 +1525282598 0.039551 0.034302 0.038086 +1525283498 0.017700 0.022827 0.026367 +1525284398 0.023560 0.034790 0.024292 +1525285298 0.093506 0.078857 0.053101 +1525286198 0.051025 0.066162 0.069458 +1525287098 0.054077 0.057861 0.059082 +1525287998 0.080200 0.071655 0.062744 +1525288898 0.478638 0.375122 0.247192 +1525289798 0.393066 0.390991 0.347046 +1525290698 0.368164 0.383545 0.365723 +1525291598 0.459229 0.463867 0.432129 +1525292498 0.286865 0.354980 0.381958 +1525293398 0.180786 0.178833 0.232910 +1525294298 0.278198 0.260864 0.242920 +1525295198 0.192505 0.183716 0.200806 +1525296098 0.109375 0.185669 0.207153 +1525296098 0.109375 0.185669 0.207153 +1525296998 0.137085 0.126221 0.138184 +1525297898 0.077881 0.092529 0.109619 DIR diff --git a/ploot-braille.c b/ploot-braille.c @@ -9,7 +9,7 @@ #include <unistd.h> #include "drawille.h" #include "util.h" -#include "csv.h" +#include "tsv.h" #ifndef __OpenBSD__ #define pledge(...) 0 @@ -20,7 +20,7 @@ * a vertical and horizontal axis. */ static int -braille_histogram(struct csv *vl, struct drawille *drw, +braille_histogram(struct tsv *vl, struct drawille *drw, time_t tmin, time_t tmax, double vmin, double vmax) { int x, xprev, y, yprev, zero; @@ -104,7 +104,7 @@ 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) +plot(struct tsv *vl, size_t ncol, int rows, int cols, FILE *fp) { double vmin, vmax, vstep; time_t tmin, tmax, tstep; @@ -112,7 +112,7 @@ plot(struct csv *vl, size_t ncol, int rows, int cols, FILE *fp) rows = MAX(rows, 2); /* readable */ - if (csv_min_max(vl, ncol, &tmin, &tmax, &vmin, &vmax) < 0) + if (tsv_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); @@ -145,7 +145,7 @@ usage(void) int main(int argc, char **argv) { - struct csv *vl; + struct tsv *vl; size_t ncol; int c, rows, cols; @@ -181,8 +181,8 @@ main(int argc, char **argv) if (argc > 0) usage(); - csv_labels(stdin, &vl, &ncol); - csv_values(stdin, vl, ncol); + tsv_labels(stdin, &vl, &ncol); + tsv_values(stdin, vl, ncol); plot(vl, ncol, rows, cols, stdout); DIR diff --git a/ploot-csv.5 b/ploot-csv.5 @@ -1,77 +0,0 @@ -.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 coma-separated format used by the ploot-* programs. -. -. -.Sh INPUT FORMAT -. -.Nm -has a first header line, then zero or more data lines, both -coma-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.1 b/ploot-farbfeld.1 @@ -6,7 +6,7 @@ .Sh NAME . .Nm ploot-ffplot -.Nd produce a ffplot image of csv input +.Nd produce a ffplot image of tsv input . . .Sh SYNOPSIS @@ -20,7 +20,7 @@ . The .Nm -utility plots an image in the ffplot format out of csv values coming from stdin. +utility plots an image in the ffplot format out of tsv values coming from stdin. . .Bl -tag -width 6n . @@ -29,7 +29,7 @@ Set the title of the plot printed at the top left 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 +If the input tsv have 5 columns in addition of the timestamp, there must be 5 maxval arguments. color_ts available are red, orange, yellow, green, cyan and blue. . @@ -37,7 +37,7 @@ color_ts available are red, orange, yellow, green, cyan and blue. . .Pp The input format is documented in the -.Xr ploot-csv 7 +.Xr ploot-tsv 7 manual page. . . @@ -62,7 +62,7 @@ $ ploot-ffplot -t demo -u MB red yellow <sample.txt .Sh SEE ALSO . .Xr ploot-ffplot 1 , -.Xr ploot-csv 7 +.Xr ploot-tsv 7 . .Pp The DIR diff --git a/ploot-farbfeld.c b/ploot-farbfeld.c @@ -11,7 +11,7 @@ #include <string.h> #include <time.h> #include <unistd.h> -#include "csv.h" +#include "tsv.h" #include "font.h" #include "util.h" @@ -287,7 +287,7 @@ ffplot_title(struct ffplot *plot, struct ffcolor *ct, char *title) } static void -ffplot_plot(struct ffplot *plot, struct csv *vl, struct ffcolor *color, +ffplot_plot(struct ffplot *plot, struct tsv *vl, struct ffcolor *color, double vmin, double vmax, time_t tmin, time_t tmax) { @@ -310,7 +310,7 @@ ffplot_plot(struct ffplot *plot, struct csv *vl, struct ffcolor *color, } static void -ffplot_values(struct ffplot *plot, struct csv *vl, struct ffcolor **cl, size_t ncol, +ffplot_values(struct ffplot *plot, struct tsv *vl, struct ffcolor **cl, size_t ncol, time_t tmin, time_t tmax, double vmin, double vmax) { @@ -319,7 +319,7 @@ ffplot_values(struct ffplot *plot, struct csv *vl, struct ffcolor **cl, size_t n } static void -ffplot_legend(struct ffplot *plot, struct ffcolor *fg, struct csv *vl, struct ffcolor **cl, size_t ncol) +ffplot_legend(struct ffplot *plot, struct ffcolor *fg, struct tsv *vl, struct ffcolor **cl, size_t ncol) { size_t x, y; @@ -342,7 +342,7 @@ ffplot_legend(struct ffplot *plot, struct ffcolor *fg, struct csv *vl, struct ff * x label here */ static void -plot(struct csv *vl, struct ffcolor **cl, size_t ncol, char *name) +plot(struct tsv *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 }; @@ -353,7 +353,7 @@ plot(struct csv *vl, struct ffcolor **cl, size_t ncol, char *name) double vmin, vmax, vstep; time_t tmin, tmax, tstep; - csv_min_max(vl, ncol, &tmin, &tmax, &vmin, &vmax); + tsv_min_max(vl, ncol, &tmin, &tmax, &vmin, &vmax); tstep = scale_time_t(tmin, tmax, 7); vstep = scale_double(vmin, vmax, 7); @@ -424,7 +424,7 @@ usage(void) int main(int argc, char **argv) { - struct csv *vl; + struct tsv *vl; struct ffcolor **cl; size_t ncol; int c; @@ -451,12 +451,12 @@ main(int argc, char **argv) if ((cl = calloc(argc, sizeof *cl)) == NULL) err(1, "calloc: %s", strerror(errno)); - csv_labels(stdin, &vl, &ncol); + tsv_labels(stdin, &vl, &ncol); if (ncol > (size_t)argc) err(1, "too many columns or not enough arguments"); else if (ncol < (size_t)argc) err(1, "too many arguments or not enough columns"); - csv_values(stdin, vl, ncol); + tsv_values(stdin, vl, ncol); argv_to_color(cl, argv); plot(vl, cl, argc, flag_title); DIR diff --git a/ploot-feed.1 b/ploot-feed.1 @@ -20,7 +20,7 @@ . The .Nm -utility plots a text chart of csv values coming from stdin in real time. +utility plots a text chart of tsv values coming from stdin in real time. . .Bl -tag -width 6n . @@ -29,14 +29,14 @@ is the width of the plot in characters. . .It Ar maxval is a list of argument that specify the maximum value for each column. -If the input csv have 5 columns in addition of the timestamp, there must +If the input tsv have 5 columns in addition of the timestamp, there must be 5 maxval arguments. . .El . .Pp The input format is documented in the -.Xr ploot-csv 7 +.Xr ploot-tsv 7 manual page. . . DIR diff --git a/ploot-feed.c b/ploot-feed.c @@ -59,14 +59,14 @@ plot_row(long *out, char *line, double *max, int nrow, int ncol) int n; char *tok; - tok = strsep(&line, ","); + tok = strsep(&line, "\t"); if (!tok) err(100, "*** missing epoch value"); epoch = strtol(tok, NULL, 10); if (errno) warn("*** parsing epoch '%s'", tok); - for (n = 0; (tok = strsep(&line, ",")) != NULL; n++) { + for (n = 0; (tok = strsep(&line, "\t")) != NULL; n++) { if (n >= ncol) err(100, "too many values"); val = atof(tok); @@ -186,10 +186,10 @@ read_labels(char **labv) strchomp(line); cp = line; - if (strcmp(strsep(&cp, ","), "epoch") != 0) + if (strcmp(strsep(&cp, "\t"), "epoch") != 0) err(100, "first label must be 'epoch'"); - for (ncol = 0; (tok = strsep(&cp, ",")) != NULL; ncol++, labv++) + for (ncol = 0; (tok = strsep(&cp, "\t")) != NULL; ncol++, labv++) *labv = tok; *labv = NULL; @@ -212,7 +212,7 @@ fmt_labels(char out[4069], int ncol, char *labels[4069 / 2]) static void usage(void) { - fprintf(stderr, "usage: %s [-w width] maxval... <csv\n", arg0); + fprintf(stderr, "usage: %s [-w width] maxval... <tsv\n", arg0); exit(1); } DIR diff --git a/ploot-tsv.5 b/ploot-tsv.5 @@ -0,0 +1,77 @@ +.Dd $Mdocdate: February 01 2020$ +.Dt PLOOT-TSV 5 +.Os +. +. +.Sh NAME +. +.Nm ploot-tsv +.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 coma-separated format used by the ploot-* programs. +. +. +.Sh INPUT FORMAT +. +.Nm +has a first header line, then zero or more data lines, both +coma-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/tsv.c b/tsv.c @@ -0,0 +1,154 @@ +#include "tsv.h" +#include <errno.h> +#include <assert.h> +#include <string.h> +#include <time.h> +#include <stdlib.h> +#include <limits.h> +#include <time.h> +#include "util.h" + +/* + * Read TSV data onto a set of (struct tsv) and some utilities to work on these data. + */ + +int +tsv_min_max(struct tsv *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 +tsv_add_time(struct tsv *vl, time_t epoch) +{ + void *mem; + + if ((mem = realloc(vl->t, (vl->n + 1) * sizeof *vl->t)) == NULL) + err(1, "realloc: %s", strerror(errno)); + vl->t = mem; + vl->t[vl->n] = epoch; +} + +static void +tsv_add_val(struct tsv *vl, double field) +{ + void *mem; + + if ((mem = realloc(vl->v, (vl->n + 1) * sizeof *vl->v)) == NULL) + err(1, "", strerror(errno)); + vl->v = mem; + vl->v[vl->n] = field; +} + +/* + * Add to each column the value on the current row. The time_t + * buffer is shared among all fields. + */ +static void +tsv_add_row(struct tsv *vl, size_t ncol, char *line) +{ + char *field; + time_t *tbuf; + long l; + double d; + + if ((field = strsep(&line, "\t")) == NULL) + err(1, "missing epoch at row %zu", vl->n); + + l = strtol(field, NULL, 10); + if (errno) + err(100, "parsing number '%s'", field); + + tsv_add_time(vl, l); + tbuf = vl[0].t; + for (; (field = strsep(&line, "\t")); ncol--, vl->n++, vl++) { + if (ncol == 0) + err(1, "too many fields at line %zu", vl->n); + d = strtod(field, NULL); + if (errno) + err(100, "parsing double '%s'", field); + tsv_add_val(vl, d); + vl->t = tbuf; + } + if (ncol > 0) + err(1, "too few fields at line %zu", vl->n); +} + +/* + * < (ncol) > + * label1,label2,label3 + */ +void +tsv_labels(FILE *fp, struct tsv **vlp, size_t *ncol) +{ + char *field, *line, *cp; + struct tsv *vl, *col; + size_t sz; + ssize_t r; + + sz = 0, line = NULL; + r = getline(&line, &sz, fp); + if (ferror(fp)) + err(111, "error while reading from file"); + if (feof(fp)) + err(100, "missing label line"); + strchomp(line); + + cp = line; + if (strcmp(strsep(&cp, "\t"), "epoch") != 0) + err(1, "first label must be 'epoch'"); + + sz = 0, vl = NULL, *ncol = 0; + while ((field = strsep(&cp, "\t"))) { + if ((vl = realloc(vl, sz += sizeof *vl)) == NULL) + err(1, "realloc: %s", strerror(errno)); + col = vl + (*ncol)++; + memset(col, 0, sizeof *vl); + strlcpy(col->label, field, sizeof col->label); + } + free(line); + *vlp = vl; +} + +/* + * < (ncol) > + * val1a,val1b,val1c ^ + * val2a,val2b,val2c | + * val3a,val3b,val3c (vl->n) + * val4a,val4b,val4c | + * val5a,val5b,val5c v + */ +void +tsv_values(FILE *fp, struct tsv *vl, size_t ncol) +{ + char *line; + size_t sz; + + sz = 0, line = NULL; + while (getline(&line, &sz, fp) > -1) + tsv_add_row(vl, ncol, line); + if (vl->n == 0) + err(1, "no value could be read"); + if (vl->n == 1) + err(1, "only one value could be read"); + free(line); +} DIR diff --git a/tsv.h b/tsv.h @@ -0,0 +1,22 @@ +#ifndef TSV_H +#define TSV_H + +#include <stdio.h> +#include <time.h> + +/* + * List of values and timestamps. Both have their dedicated buffer + * so that the timestamp buffer can be shared across tsv objects. + */ +struct tsv { + time_t *t; /* array of timestamps */ + double *v; /* array of values */ + size_t n; /* number of values */ + char label[64]; /* for the legend */ +}; + +void tsv_labels(FILE *, struct tsv **, size_t *); +void tsv_values(FILE *, struct tsv *, size_t); +int tsv_min_max(struct tsv *, int, time_t *, time_t *, double *, double *); + +#endif