Blob


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