histogram.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <bio.h>
  5. #include <thread.h>
  6. #include <mouse.h>
  7. #include <keyboard.h>
  8. enum {
  9. STACK = 8*1024,
  10. Dot = 2, /* height of dot */
  11. Lx = 4, /* x offset */
  12. Ly = 4, /* y offset */
  13. Bw = 2, /* border width */
  14. };
  15. Image *neutral;
  16. Image *light;
  17. Image *dark;
  18. Image *txtcolor;
  19. char *title = "histogram";
  20. Rectangle hrect;
  21. Point maxvloc;
  22. double *data;
  23. double vmax = 100, scale = 1.0;
  24. uint nval;
  25. int dontdie = 0, col = 1;
  26. int colors[][3] = {
  27. { 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF }, /* Peach */
  28. { DPalebluegreen, DPalegreygreen, DPurpleblue }, /* Aqua */
  29. { DPaleyellow, DDarkyellow, DYellowgreen }, /* Yellow */
  30. { DPalegreen, DMedgreen, DDarkgreen }, /* Green */
  31. { 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF }, /* Blue */
  32. { 0xEEEEEEFF, 0xCCCCCCFF, 0x888888F }, /* Grey */
  33. };
  34. void
  35. initcolor(int i)
  36. {
  37. neutral = allocimagemix(display, colors[i][0], DWhite);
  38. light = allocimage(display, Rect(0,0,1,1), CMAP8, 1, colors[i][1]);
  39. dark = allocimage(display, Rect(0,0,1,1), CMAP8, 1, colors[i][2]);
  40. txtcolor = display->black;
  41. }
  42. void*
  43. erealloc(void *v, ulong sz)
  44. {
  45. v = realloc(v, sz);
  46. if(v == nil){
  47. sysfatal("realloc: %r");
  48. threadexitsall("memory");
  49. }
  50. return v;
  51. }
  52. Point
  53. datapoint(int x, double v)
  54. {
  55. Point p;
  56. double y;
  57. p.x = x;
  58. y = (v*scale) / vmax;
  59. p.y = hrect.max.y - Dy(hrect)*y - Dot;
  60. if(p.y < hrect.min.y)
  61. p.y = hrect.min.y;
  62. if(p.y > hrect.max.y - Dot)
  63. p.y = hrect.max.y - Dot;
  64. return p;
  65. }
  66. void
  67. drawdatum(int x, double prev, double v)
  68. {
  69. Point p, q;
  70. p = datapoint(x, v);
  71. q = datapoint(x, prev);
  72. if(p.y < q.y){
  73. draw(screen, Rect(p.x, hrect.min.y, p.x+1, p.y), neutral,
  74. nil, ZP);
  75. draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), dark, nil, ZP);
  76. draw(screen, Rect(p.x, q.y+Dot, p.x+1, hrect.max.y), light,
  77. nil, ZP);
  78. }else{
  79. draw(screen, Rect(p.x, hrect.min.y, p.x+1, q.y), neutral,
  80. nil, ZP);
  81. draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), dark, nil, ZP);
  82. draw(screen, Rect(p.x, p.y+Dot, p.x+1, hrect.max.y), light,
  83. nil, ZP);
  84. }
  85. }
  86. void
  87. updatehistogram(double v)
  88. {
  89. char buf[32];
  90. draw(screen, hrect, screen, nil, Pt(hrect.min.x+1, hrect.min.y));
  91. if(v * scale > vmax)
  92. v = vmax / scale;
  93. drawdatum(hrect.max.x-1, data[0], v);
  94. memmove(&data[1], &data[0], (nval-1) * sizeof data[0]);
  95. data[0] = v;
  96. snprint(buf, sizeof buf, "%0.9f", v);
  97. stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf,
  98. neutral, ZP);
  99. flushimage(display, 1);
  100. }
  101. void
  102. redrawhistogram(int new)
  103. {
  104. Point p, q;
  105. Rectangle r;
  106. uint onval = nval;
  107. int i;
  108. char buf[32];
  109. if(new && getwindow(display, Refnone) < 0)
  110. sysfatal("getwindow: %r");
  111. r = screen->r;
  112. draw(screen, r, neutral, nil, ZP);
  113. p = string(screen, addpt(r.min, Pt(Lx, Ly)), txtcolor, ZP,
  114. display->defaultfont, title);
  115. p.x = r.min.x + Lx;
  116. p.y += display->defaultfont->height + Ly;
  117. q = subpt(r.max, Pt(Lx, Ly));
  118. hrect = Rpt(p, q);
  119. maxvloc = Pt(r.max.x - Lx - stringwidth(display->defaultfont,
  120. "999999999"), r.min.y + Ly);
  121. nval = abs(Dx(hrect));
  122. if(nval != onval){
  123. data = erealloc(data, nval * sizeof data[0]);
  124. if(nval > onval)
  125. memset(data+onval, 0, (nval - onval) * sizeof data[0]);
  126. }
  127. border(screen, hrect, -Bw, dark, ZP);
  128. snprint(buf, sizeof buf, "%0.9f", data[0]);
  129. stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf,
  130. neutral, ZP);
  131. draw(screen, hrect, neutral, nil, ZP);
  132. for(i = 1; i < nval - 1; i++)
  133. drawdatum(hrect.max.x - i, data[i-1], data[i]);
  134. drawdatum(hrect.min.x, data[i], data[i]);
  135. flushimage(display, 1);
  136. }
  137. void
  138. reader(void *arg)
  139. {
  140. int fd;
  141. double v;
  142. char *p, *f[2];
  143. uchar buf[512];
  144. Biobufhdr b;
  145. Channel *c = arg;
  146. threadsetname("reader");
  147. fd = dup(0, -1);
  148. Binits(&b, fd, OREAD, buf, sizeof buf);
  149. while((p = Brdline(&b, '\n')) != nil) {
  150. p[Blinelen(&b) - 1] = '\0';
  151. if(tokenize(p, f, 1) != 1)
  152. continue;
  153. v = strtod(f[0], 0);
  154. send(c, &v);
  155. }
  156. if(!dontdie)
  157. threadexitsall(nil);
  158. }
  159. void
  160. histogram(char *rect)
  161. {
  162. int rm;
  163. double dm;
  164. Channel *dc;
  165. Keyboardctl *kc;
  166. Mouse mm;
  167. Mousectl *mc;
  168. Rune km;
  169. Alt a[] = {
  170. /* c v op */
  171. {nil, &dm, CHANRCV}, /* data from stdin */
  172. {nil, &mm, CHANRCV}, /* mouse message */
  173. {nil, &km, CHANRCV}, /* keyboard runes */
  174. {nil, &rm, CHANRCV}, /* resize event */
  175. {nil, nil, CHANEND},
  176. };
  177. static char *mitems[] = {
  178. "exit",
  179. nil
  180. };
  181. static Menu menu = {
  182. mitems,
  183. nil,
  184. -1
  185. };
  186. memset(&mm, 0, sizeof mm);
  187. memset(&km, 0, sizeof km);
  188. dm = rm = 0;
  189. if(newwindow(rect) < 0)
  190. sysfatal("newwindow: %r");
  191. if(initdraw(nil, nil, "histogram") < 0)
  192. sysfatal("initdraw: %r");
  193. initcolor(col);
  194. mc = initmouse(nil, screen);
  195. if(!mc)
  196. sysfatal("initmouse: %r");
  197. kc = initkeyboard(nil);
  198. if(!kc)
  199. sysfatal("initkeyboard: %r");
  200. dc = chancreate(sizeof dm, 10);
  201. if(!dc)
  202. sysfatal("chancreate: %r");
  203. a[0].c = dc;
  204. a[1].c = mc->c;
  205. a[2].c = kc->c;
  206. a[3].c = mc->resizec;
  207. proccreate(reader, a[0].c, STACK + sizeof(Biobuf));
  208. redrawhistogram(0);
  209. for(;;)
  210. switch(alt(a)){
  211. case 0:
  212. updatehistogram(dm);
  213. break;
  214. case 1:
  215. if(mm.buttons & 4 && menuhit(3, mc, &menu, nil) == 0)
  216. goto done;
  217. break;
  218. case 2:
  219. if(km == 0x7F)
  220. goto done;
  221. break;
  222. case 3:
  223. redrawhistogram(1);
  224. break;
  225. default:
  226. sysfatal("shouldn't happen");
  227. }
  228. done:
  229. closekeyboard(kc);
  230. closemouse(mc);
  231. chanfree(a[0].c);
  232. threadexitsall(nil);
  233. }
  234. void
  235. usage(void)
  236. {
  237. fprint(2, "usage: histogram [-h] [-c index] [-r minx,miny,maxx,maxy] "
  238. "[-s scale] [-t title] [-v maxv]\n");
  239. exits("usage");
  240. }
  241. void
  242. threadmain(int argc, char **argv)
  243. {
  244. char *p, *q;
  245. p = "-r 0,0,400,150";
  246. ARGBEGIN{
  247. case 'v':
  248. vmax = strtod(EARGF(usage()), 0);
  249. break;
  250. case 'r':
  251. p = smprint("-r %s", EARGF(usage()));
  252. break;
  253. case 's':
  254. scale = strtod(EARGF(usage()), 0);
  255. if(scale <= 0)
  256. usage();
  257. break;
  258. case 'h':
  259. dontdie = 1;
  260. break;
  261. case 't':
  262. title = EARGF(usage());
  263. break;
  264. case 'c':
  265. col = atoi(EARGF(usage())) % nelem(colors);
  266. break;
  267. default:
  268. usage();
  269. }ARGEND;
  270. while((q = strchr(p, ',')) != nil)
  271. *q = ' ';
  272. histogram(p);
  273. }