graph.c (13324B)
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 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; 26 27 char *labels; 28 int labelsiz; 29 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; 45 46 #define BSIZ 80 47 char labbuf[BSIZ]; 48 char titlebuf[BSIZ]; 49 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 } 62 63 struct z { 64 float lb,ub,mult,quant; 65 }; 66 67 struct { 68 char *name; 69 int next; 70 } palette[256]; 71 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; 86 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 } 92 93 int pencolor = 'k'; 94 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 *); 119 120 int main(int argc,char *argv[]){ 121 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); 141 } 142 scale(&xd); 143 scale(&yd); 144 axes(); 145 title(); 146 plot(); 147 closepl(); 148 exits(0); 149 return 0; /* gcc */ 150 } 151 152 void init(struct xy *p){ 153 p->xf = ident; 154 p->xmult = 1; 155 } 156 157 void setopt(int argc, char *argv[]){ 158 char *p1, *p2; 159 float temp; 160 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++); 176 } 177 break; 178 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; 189 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; 202 203 case 's': /*save screen, overlay plot*/ 204 erasf = 0; 205 break; 206 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; 214 215 case 'c': /*character(s) for plotting*/ 216 if(argc >= 2) { 217 symbf = 1; 218 plotsymb = argv[1]; 219 argv++; 220 argc--; 221 } 222 break; 223 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(); 260 } 261 } 262 } 263 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; 269 } 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; 279 } 280 281 #ifdef NOTDEF 282 isdigit(char c){ 283 return '0'<=c && c<='9'; 284 } 285 #endif 286 287 int 288 numb(float *np, int *argcp, char ***argvp){ 289 char c; 290 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); 301 } 302 303 void colread(int *argcp, char ***argvp){ 304 int c, cnext; 305 int i, n; 306 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; 317 } 318 palette[cnext].next = pencolor; 319 (*argcp)--; 320 (*argvp)++; 321 } 322 323 void readin(void){ 324 int i, t; 325 struct val *temp; 326 327 if(absf==1) { 328 if(xd.xlbf) 329 absbot = xd.xlb; 330 else if(xd.xf==log10) 331 absbot = 1; 332 } 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; 355 } 356 n += ovlay; 357 if(t<0) 358 return; 359 } 360 } 361 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; 371 } 372 } 373 374 int copystring(int k){ 375 char *temp; 376 int i; 377 int q; 378 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); 387 } 388 389 float modceil(float f, float t){ 390 391 t = fabs(t); 392 return(ceil(f/t)*t); 393 } 394 395 float 396 modfloor(float f, float t){ 397 t = fabs(t); 398 return(floor(f/t)*t); 399 } 400 401 void getlim(struct xy *p, struct val *v){ 402 int i; 403 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); 412 } 413 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; 420 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; 428 } 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; 440 } 441 else if(delta == 0) { 442 if(ub > 0) { 443 ub = 2*ub; 444 lb = 0; 445 } 446 else 447 if(lb < 0) { 448 lb = 2*lb; 449 ub = 0; 450 } 451 else { 452 ub = 1; 453 lb = -1; 454 } 455 } 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; 467 } 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; 475 } 476 p->xmult *= z.mult; 477 p->xquant = sign*z.quant; 478 } 479 480 struct z 481 setloglim(int lbf, int ubf, float lb, float ub){ 482 float r,s,t; 483 struct z z; 484 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; 498 } 499 if(!ubf) { 500 if(ub*5 <= z.ub) 501 z.ub /= 5; 502 else if(ub*2 <= z.ub) 503 z.ub /= 2; 504 } 505 } 506 z.mult = s; 507 z.quant = r; 508 return(z); 509 } 510 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; 516 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; 541 } 542 else if(!ubf && z.ub>=-r && z.ub<0) { 543 xub = 0; 544 goto loop; 545 } 546 z.quant = r; 547 z.mult = s; 548 return(z); 549 } 550 551 void scale(struct xy *p){ 552 float edge; 553 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; 560 } 561 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; 569 } 570 if(p->xub<q->xub) { 571 p->xub = q->xub; 572 p->xubf = q->xubf; 573 } 574 } 575 576 void axes(void){ 577 int i; 578 int mark[50]; 579 int xn, yn; 580 if(gridf==0) 581 return; 582 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); 587 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); 595 } 596 } 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]); 604 } 605 } 606 } 607 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); 619 } 620 } 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; 630 } 631 for(x=xl; x<=xu; x+=fabs(p->xquant)) 632 xmark[xn++] = (*p->xf)(x)*p->xa + p->xb; 633 } 634 return(xn); 635 } 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; 639 } 640 641 void plot(void){ 642 int ix,iy; 643 int i,j; 644 int conn; 645 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]); 655 } 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; 663 } 664 if(mode!=0) { 665 if(conn != 0) 666 vec(ix,iy); 667 else 668 move(ix,iy); 669 conn = 1; 670 } 671 conn &= symbol(ix,iy,xx[i].lblptr); 672 } 673 pencolor = palette[pencolor].next; 674 } 675 pen(modes[1]); 676 } 677 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); 686 } 687 688 int 689 getfloat(float *p){ 690 int i; 691 692 i = scanf("%f",p); 693 return(i==1); 694 } 695 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; 709 } 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; 719 } 720 if(i==-1) 721 return(-1); 722 return(strlen(labbuf)); 723 } 724 725 int 726 symbol(int ix, int iy, int k){ 727 728 if(symbf==0&&k<0) { 729 if(mode==0) 730 point(ix,iy); 731 return(1); 732 } 733 else { 734 move(ix,iy); 735 text(k>=0?labels+k:plotsymb); 736 move(ix,iy); 737 return(!brkf|k<0); 738 } 739 } 740 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); 751 } 752 move(xd.xbot,yd.xbot-60); 753 text(buf); 754 } 755 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); 761 } 762 763 void badarg(void){ 764 fprintf(stderr,"graph: error in arguments\n"); 765 closepl(); 766 exits("bad arg"); 767 }