graph.c 12 KB

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