histogram.c 6.3 KB

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