URI: 
       tgraph.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tgraph.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 }