graph.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <stdio.h>
  4. #include "iplot.h"
  5. #define INF 1.e+37
  6. #define F .25
  7. struct xy {
  8. int xlbf; /*flag:explicit lower bound*/
  9. int xubf; /*flag:explicit upper bound*/
  10. int xqf; /*flag:explicit quantum*/
  11. double (*xf)(double); /*transform function, e.g. log*/
  12. float xa,xb; /*scaling coefficients*/
  13. float xlb,xub; /*lower and upper bound*/
  14. float xquant; /*quantum*/
  15. float xoff; /*screen offset fraction*/
  16. float xsize; /*screen fraction*/
  17. int xbot,xtop; /*screen coords of border*/
  18. float xmult; /*scaling constant*/
  19. } xd,yd;
  20. struct val {
  21. float xv;
  22. float yv;
  23. int lblptr;
  24. } *xx;
  25. char *labels;
  26. int labelsiz;
  27. int tick = 50;
  28. int top = 4000;
  29. int bot = 200;
  30. float absbot;
  31. int n;
  32. int erasf = 1;
  33. int gridf = 2;
  34. int symbf = 0;
  35. int absf = 0;
  36. int transf;
  37. int equf;
  38. int brkf;
  39. int ovlay = 1;
  40. float dx;
  41. char *plotsymb;
  42. #define BSIZ 80
  43. char labbuf[BSIZ];
  44. char titlebuf[BSIZ];
  45. char *modes[] = {
  46. "disconnected",
  47. "solid",
  48. "dotted",
  49. "dotdashed",
  50. "shortdashed",
  51. "longdashed"
  52. };
  53. int mode = 1;
  54. double ident(double x){
  55. return(x);
  56. }
  57. struct z {
  58. float lb,ub,mult,quant;
  59. };
  60. struct {
  61. char *name;
  62. int next;
  63. } palette[] = {
  64. ['b'] { "blue", 'b' },
  65. ['c'] { "cyan", 'c' },
  66. ['g'] { "green", 'g' },
  67. ['k'] { "kblack", 'k' },
  68. ['m'] { "magenta", 'm' },
  69. ['r'] { "red", 'r' },
  70. ['w'] { "white", 'w' },
  71. ['y'] { "yellow", 'y' }
  72. };
  73. int pencolor = 'k';
  74. void init(struct xy *);
  75. void setopt(int, char *[]);
  76. void readin(void);
  77. void transpose(void);
  78. void getlim(struct xy *, struct val *);
  79. void equilibrate(struct xy *, struct xy *);
  80. void scale(struct xy *);
  81. void limread(struct xy *, int *, char ***);
  82. int numb(float *, int *, char ***);
  83. void colread(int *, char ***);
  84. int copystring(int);
  85. struct z setloglim(int, int, float, float);
  86. struct z setlinlim(int, int, float, float);
  87. void axes(void);
  88. int setmark(int *, struct xy *);
  89. void submark(int *, int *, float, struct xy *);
  90. void plot(void);
  91. int getfloat(float *);
  92. int getstring(void);
  93. void title(void);
  94. void badarg(void);
  95. int conv(float, struct xy *, int *);
  96. int symbol(int, int, int);
  97. void axlab(char, struct xy *, char *);
  98. void main(int argc,char *argv[]){
  99. openpl();
  100. range(0,0,4096,4096);
  101. init(&xd);
  102. init(&yd);
  103. xd.xsize = yd.xsize = 1.;
  104. xx = (struct val *)malloc((unsigned)sizeof(struct val));
  105. labels = malloc(1);
  106. labels[labelsiz++] = 0;
  107. setopt(argc,argv);
  108. if(erasf)
  109. erase();
  110. readin();
  111. transpose();
  112. getlim(&xd,(struct val *)&xx->xv);
  113. getlim(&yd,(struct val *)&xx->yv);
  114. if(equf) {
  115. equilibrate(&xd,&yd);
  116. equilibrate(&yd,&xd);
  117. }
  118. scale(&xd);
  119. scale(&yd);
  120. axes();
  121. title();
  122. plot();
  123. closepl();
  124. exits(0);
  125. }
  126. void init(struct xy *p){
  127. p->xf = ident;
  128. p->xmult = 1;
  129. }
  130. void setopt(int argc, char *argv[]){
  131. char *p1, *p2;
  132. float temp;
  133. xd.xlb = yd.xlb = INF;
  134. xd.xub = yd.xub = -INF;
  135. while(--argc > 0) {
  136. argv++;
  137. again: switch(argv[0][0]) {
  138. case '-':
  139. argv[0]++;
  140. goto again;
  141. case 'l': /* label for plot */
  142. p1 = titlebuf;
  143. if (argc>=2) {
  144. argv++;
  145. argc--;
  146. p2 = argv[0];
  147. while (*p1++ = *p2++);
  148. }
  149. break;
  150. case 'd': /*disconnected,obsolete option*/
  151. case 'm': /*line mode*/
  152. mode = 0;
  153. if(!numb(&temp,&argc,&argv))
  154. break;
  155. if(temp>=sizeof(modes)/sizeof(*modes))
  156. mode = 1;
  157. else if(temp>=-1)
  158. mode = temp;
  159. break;
  160. case 'o':
  161. if(numb(&temp,&argc,&argv) && temp>=1)
  162. ovlay = temp;
  163. break;
  164. case 'a': /*automatic abscissas*/
  165. absf = 1;
  166. dx = 1;
  167. if(!numb(&dx,&argc,&argv))
  168. break;
  169. if(numb(&absbot,&argc,&argv))
  170. absf = 2;
  171. break;
  172. case 's': /*save screen, overlay plot*/
  173. erasf = 0;
  174. break;
  175. case 'g': /*grid style 0 none, 1 ticks, 2 full*/
  176. gridf = 0;
  177. if(!numb(&temp,&argc,&argv))
  178. temp = argv[0][1]-'0'; /*for caompatibility*/
  179. if(temp>=0&&temp<=2)
  180. gridf = temp;
  181. break;
  182. case 'c': /*character(s) for plotting*/
  183. if(argc >= 2) {
  184. symbf = 1;
  185. plotsymb = argv[1];
  186. argv++;
  187. argc--;
  188. }
  189. break;
  190. case 't': /*transpose*/
  191. transf = 1;
  192. break;
  193. case 'e': /*equal scales*/
  194. equf = 1;
  195. break;
  196. case 'b': /*breaks*/
  197. brkf = 1;
  198. break;
  199. case 'x': /*x limits */
  200. limread(&xd,&argc,&argv);
  201. break;
  202. case 'y':
  203. limread(&yd,&argc,&argv);
  204. break;
  205. case 'h': /*set height of plot */
  206. if(!numb(&yd.xsize, &argc,&argv))
  207. badarg();
  208. break;
  209. case 'w': /*set width of plot */
  210. if(!numb(&xd.xsize, &argc, &argv))
  211. badarg();
  212. break;
  213. case 'r': /* set offset to right */
  214. if(!numb(&xd.xoff, &argc, &argv))
  215. badarg();
  216. break;
  217. case 'u': /*set offset up the screen*/
  218. if(!numb(&yd.xoff,&argc,&argv))
  219. badarg();
  220. break;
  221. case 'p': /*pen color*/
  222. colread(&argc, &argv);
  223. break;
  224. default:
  225. badarg();
  226. }
  227. }
  228. }
  229. void limread(struct xy *p, int *argcp, char ***argvp){
  230. if(*argcp>1 && (*argvp)[1][0]=='l') {
  231. (*argcp)--;
  232. (*argvp)++;
  233. p->xf = log10;
  234. }
  235. if(!numb(&p->xlb,argcp,argvp))
  236. return;
  237. p->xlbf = 1;
  238. if(!numb(&p->xub,argcp,argvp))
  239. return;
  240. p->xubf = 1;
  241. if(!numb(&p->xquant,argcp,argvp))
  242. return;
  243. p->xqf = 1;
  244. }
  245. isdigit(char c){
  246. return '0'<=c && c<='9';
  247. }
  248. numb(float *np, int *argcp, char ***argvp){
  249. char c;
  250. if(*argcp <= 1)
  251. return(0);
  252. while((c=(*argvp)[1][0]) == '+')
  253. (*argvp)[1]++;
  254. if(!(isdigit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.'))
  255. return(0);
  256. *np = atof((*argvp)[1]);
  257. (*argcp)--;
  258. (*argvp)++;
  259. return(1);
  260. }
  261. void colread(int *argcp, char ***argvp){
  262. int c, cnext;
  263. int i, n;
  264. if(*argcp<=1)
  265. return;
  266. n = strlen((*argvp)[1]);
  267. if(strspn((*argvp)[1], "bcgkmrwy")!=n)
  268. return;
  269. pencolor = cnext = (*argvp)[1][0];
  270. for(i=0; i<n-1; i++){
  271. c = (unsigned char)(*argvp)[1][i];
  272. cnext = (unsigned char)(*argvp)[1][i+1];
  273. palette[c].next = cnext;
  274. }
  275. palette[cnext].next = pencolor;
  276. (*argcp)--;
  277. (*argvp)++;
  278. }
  279. void readin(void){
  280. int i, t;
  281. struct val *temp;
  282. if(absf==1) {
  283. if(xd.xlbf)
  284. absbot = xd.xlb;
  285. else if(xd.xf==log10)
  286. absbot = 1;
  287. }
  288. for(;;) {
  289. temp = (struct val *)realloc((char*)xx,
  290. (unsigned)(n+ovlay)*sizeof(struct val));
  291. if(temp==0)
  292. return;
  293. xx = temp;
  294. if(absf)
  295. xx[n].xv = n*dx/ovlay + absbot;
  296. else
  297. if(!getfloat(&xx[n].xv))
  298. return;
  299. t = 0; /* silence compiler */
  300. for(i=0;i<ovlay;i++) {
  301. xx[n+i].xv = xx[n].xv;
  302. if(!getfloat(&xx[n+i].yv))
  303. return;
  304. xx[n+i].lblptr = -1;
  305. t = getstring();
  306. if(t>0)
  307. xx[n+i].lblptr = copystring(t);
  308. if(t<0 && i+1<ovlay)
  309. return;
  310. }
  311. n += ovlay;
  312. if(t<0)
  313. return;
  314. }
  315. }
  316. void transpose(void){
  317. int i;
  318. float f;
  319. struct xy t;
  320. if(!transf)
  321. return;
  322. t = xd; xd = yd; yd = t;
  323. for(i= 0;i<n;i++) {
  324. f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f;
  325. }
  326. }
  327. int copystring(int k){
  328. char *temp;
  329. int i;
  330. int q;
  331. temp = realloc(labels,(unsigned)(labelsiz+1+k));
  332. if(temp==0)
  333. return(0);
  334. labels = temp;
  335. q = labelsiz;
  336. for(i=0;i<=k;i++)
  337. labels[labelsiz++] = labbuf[i];
  338. return(q);
  339. }
  340. float modceil(float f, float t){
  341. t = fabs(t);
  342. return(ceil(f/t)*t);
  343. }
  344. float
  345. modfloor(float f, float t){
  346. t = fabs(t);
  347. return(floor(f/t)*t);
  348. }
  349. void getlim(struct xy *p, struct val *v){
  350. int i;
  351. i = 0;
  352. do {
  353. if(!p->xlbf && p->xlb>v[i].xv)
  354. p->xlb = v[i].xv;
  355. if(!p->xubf && p->xub<v[i].xv)
  356. p->xub = v[i].xv;
  357. i++;
  358. } while(i < n);
  359. }
  360. void setlim(struct xy *p){
  361. float t,delta,sign;
  362. struct z z;
  363. int mark[50];
  364. float lb,ub;
  365. int lbf,ubf;
  366. lb = p->xlb;
  367. ub = p->xub;
  368. delta = ub-lb;
  369. if(p->xqf) {
  370. if(delta*p->xquant <=0 )
  371. badarg();
  372. return;
  373. }
  374. sign = 1;
  375. lbf = p->xlbf;
  376. ubf = p->xubf;
  377. if(delta < 0) {
  378. sign = -1;
  379. t = lb;
  380. lb = ub;
  381. ub = t;
  382. t = lbf;
  383. lbf = ubf;
  384. ubf = t;
  385. }
  386. else if(delta == 0) {
  387. if(ub > 0) {
  388. ub = 2*ub;
  389. lb = 0;
  390. }
  391. else
  392. if(lb < 0) {
  393. lb = 2*lb;
  394. ub = 0;
  395. }
  396. else {
  397. ub = 1;
  398. lb = -1;
  399. }
  400. }
  401. if(p->xf==log10 && lb>0 && ub>lb) {
  402. z = setloglim(lbf,ubf,lb,ub);
  403. p->xlb = z.lb;
  404. p->xub = z.ub;
  405. p->xmult *= z.mult;
  406. p->xquant = z.quant;
  407. if(setmark(mark,p)<2) {
  408. p->xqf = lbf = ubf = 1;
  409. lb = z.lb; ub = z.ub;
  410. } else
  411. return;
  412. }
  413. z = setlinlim(lbf,ubf,lb,ub);
  414. if(sign > 0) {
  415. p->xlb = z.lb;
  416. p->xub = z.ub;
  417. } else {
  418. p->xlb = z.ub;
  419. p->xub = z.lb;
  420. }
  421. p->xmult *= z.mult;
  422. p->xquant = sign*z.quant;
  423. }
  424. struct z
  425. setloglim(int lbf, int ubf, float lb, float ub){
  426. float r,s,t;
  427. struct z z;
  428. for(s=1; lb*s<1; s*=10) ;
  429. lb *= s;
  430. ub *= s;
  431. for(r=1; 10*r<=lb; r*=10) ;
  432. for(t=1; t<ub; t*=10) ;
  433. z.lb = !lbf ? r : lb;
  434. z.ub = !ubf ? t : ub;
  435. if(ub/lb<100) {
  436. if(!lbf) {
  437. if(lb >= 5*z.lb)
  438. z.lb *= 5;
  439. else if(lb >= 2*z.lb)
  440. z.lb *= 2;
  441. }
  442. if(!ubf) {
  443. if(ub*5 <= z.ub)
  444. z.ub /= 5;
  445. else if(ub*2 <= z.ub)
  446. z.ub /= 2;
  447. }
  448. }
  449. z.mult = s;
  450. z.quant = r;
  451. return(z);
  452. }
  453. struct z
  454. setlinlim(int lbf, int ubf, float xlb, float xub){
  455. struct z z;
  456. float r,s,delta;
  457. float ub,lb;
  458. loop:
  459. ub = xub;
  460. lb = xlb;
  461. delta = ub - lb;
  462. /*scale up by s, a power of 10, so range (delta) exceeds 1*/
  463. /*find power of 10 quantum, r, such that delta/10<=r<delta*/
  464. r = s = 1;
  465. while(delta*s < 10)
  466. s *= 10;
  467. delta *= s;
  468. while(10*r < delta)
  469. r *= 10;
  470. lb *= s;
  471. ub *= s;
  472. /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/
  473. if(r>=delta/2)
  474. r /= 2;
  475. else if(r<delta/5)
  476. r *= 2;
  477. z.ub = ubf? ub: modceil(ub,r);
  478. z.lb = lbf? lb: modfloor(lb,r);
  479. if(!lbf && z.lb<=r && z.lb>0) {
  480. xlb = 0;
  481. goto loop;
  482. }
  483. else if(!ubf && z.ub>=-r && z.ub<0) {
  484. xub = 0;
  485. goto loop;
  486. }
  487. z.quant = r;
  488. z.mult = s;
  489. return(z);
  490. }
  491. void scale(struct xy *p){
  492. float edge;
  493. setlim(p);
  494. edge = top-bot;
  495. p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb));
  496. p->xbot = bot + edge*p->xoff;
  497. p->xtop = p->xbot + (top-bot)*p->xsize;
  498. p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5;
  499. }
  500. void equilibrate(struct xy *p, struct xy *q){
  501. if(p->xlbf|| /* needn't test xubf; it implies xlbf*/
  502. q->xubf&&q->xlb>q->xub)
  503. return;
  504. if(p->xlb>q->xlb) {
  505. p->xlb = q->xlb;
  506. p->xlbf = q->xlbf;
  507. }
  508. if(p->xub<q->xub) {
  509. p->xub = q->xub;
  510. p->xubf = q->xubf;
  511. }
  512. }
  513. void axes(void){
  514. int i;
  515. int mark[50];
  516. int xn, yn;
  517. if(gridf==0)
  518. return;
  519. line(xd.xbot,yd.xbot,xd.xtop,yd.xbot);
  520. vec(xd.xtop,yd.xtop);
  521. vec(xd.xbot,yd.xtop);
  522. vec(xd.xbot,yd.xbot);
  523. xn = setmark(mark,&xd);
  524. for(i=0; i<xn; i++) {
  525. if(gridf==2)
  526. line(mark[i],yd.xbot,mark[i],yd.xtop);
  527. if(gridf==1) {
  528. line(mark[i],yd.xbot,mark[i],yd.xbot+tick);
  529. line(mark[i],yd.xtop-tick,mark[i],yd.xtop);
  530. }
  531. }
  532. yn = setmark(mark,&yd);
  533. for(i=0; i<yn; i++) {
  534. if(gridf==2)
  535. line(xd.xbot,mark[i],xd.xtop,mark[i]);
  536. if(gridf==1) {
  537. line(xd.xbot,mark[i],xd.xbot+tick,mark[i]);
  538. line(xd.xtop-tick,mark[i],xd.xtop,mark[i]);
  539. }
  540. }
  541. }
  542. int
  543. setmark(int *xmark, struct xy *p){
  544. int xn = 0;
  545. float x,xl,xu;
  546. float q;
  547. if(p->xf==log10&&!p->xqf) {
  548. for(x=p->xquant; x<p->xub; x*=10) {
  549. submark(xmark,&xn,x,p);
  550. if(p->xub/p->xlb<=100) {
  551. submark(xmark,&xn,2*x,p);
  552. submark(xmark,&xn,5*x,p);
  553. }
  554. }
  555. } else {
  556. xn = 0;
  557. q = p->xquant;
  558. if(q>0) {
  559. xl = modceil(p->xlb+q/6,q);
  560. xu = modfloor(p->xub-q/6,q)+q/2;
  561. } else {
  562. xl = modceil(p->xub-q/6,q);
  563. xu = modfloor(p->xlb+q/6,q)-q/2;
  564. }
  565. for(x=xl; x<=xu; x+=fabs(p->xquant))
  566. xmark[xn++] = (*p->xf)(x)*p->xa + p->xb;
  567. }
  568. return(xn);
  569. }
  570. void submark(int *xmark, int *pxn, float x, struct xy *p){
  571. if(1.001*p->xlb < x && .999*p->xub > x)
  572. xmark[(*pxn)++] = log10(x)*p->xa + p->xb;
  573. }
  574. void plot(void){
  575. int ix,iy;
  576. int i,j;
  577. int conn;
  578. for(j=0;j<ovlay;j++) {
  579. switch(mode) {
  580. case -1:
  581. pen(modes[j%(sizeof modes/sizeof *modes-1)+1]);
  582. break;
  583. case 0:
  584. break;
  585. default:
  586. pen(modes[mode]);
  587. }
  588. color(palette[pencolor].name);
  589. conn = 0;
  590. for(i=j; i<n; i+=ovlay) {
  591. if(!conv(xx[i].xv,&xd,&ix) ||
  592. !conv(xx[i].yv,&yd,&iy)) {
  593. conn = 0;
  594. continue;
  595. }
  596. if(mode!=0) {
  597. if(conn != 0)
  598. vec(ix,iy);
  599. else
  600. move(ix,iy);
  601. conn = 1;
  602. }
  603. conn &= symbol(ix,iy,xx[i].lblptr);
  604. }
  605. pencolor = palette[pencolor].next;
  606. }
  607. pen(modes[1]);
  608. }
  609. int
  610. conv(float xv, struct xy *p, int *ip){
  611. long ix;
  612. ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb;
  613. if(ix<p->xbot || ix>p->xtop)
  614. return(0);
  615. *ip = ix;
  616. return(1);
  617. }
  618. int
  619. getfloat(float *p){
  620. int i;
  621. i = scanf("%f",p);
  622. return(i==1);
  623. }
  624. int
  625. getstring(void){
  626. int i;
  627. char junk[20];
  628. i = scanf("%1s",labbuf);
  629. if(i==-1)
  630. return(-1);
  631. switch(*labbuf) {
  632. default:
  633. if(!isdigit(*labbuf)) {
  634. ungetc(*labbuf,stdin);
  635. i = scanf("%s",labbuf);
  636. break;
  637. }
  638. case '.':
  639. case '+':
  640. case '-':
  641. ungetc(*labbuf,stdin);
  642. return(0);
  643. case '"':
  644. i = scanf("%[^\"\n]",labbuf);
  645. scanf("%[\"]",junk);
  646. break;
  647. }
  648. if(i==-1)
  649. return(-1);
  650. return(strlen(labbuf));
  651. }
  652. int
  653. symbol(int ix, int iy, int k){
  654. if(symbf==0&&k<0) {
  655. if(mode==0)
  656. point(ix,iy);
  657. return(1);
  658. }
  659. else {
  660. move(ix,iy);
  661. text(k>=0?labels+k:plotsymb);
  662. move(ix,iy);
  663. return(!brkf|k<0);
  664. }
  665. }
  666. void title(void){
  667. char buf[BSIZ+100];
  668. buf[0] = ' ';
  669. buf[1] = ' ';
  670. buf[2] = ' ';
  671. strcpy(buf+3,titlebuf);
  672. if(erasf&&gridf) {
  673. axlab('x',&xd,buf);
  674. strcat(buf,",");
  675. axlab('y',&yd,buf);
  676. }
  677. move(xd.xbot,yd.xbot-60);
  678. text(buf);
  679. }
  680. void axlab(char c, struct xy *p, char *b){
  681. char *dir;
  682. dir = p->xlb<p->xub? "<=": ">=";
  683. sprintf(b+strlen(b), " %g %s %c%s %s %g", p->xlb/p->xmult,
  684. dir, c, p->xf==log10?" (log)":"", dir, p->xub/p->xmult);
  685. }
  686. void badarg(void){
  687. fprintf(stderr,"graph: error in arguments\n");
  688. closepl();
  689. exits("bad arg");
  690. }