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*/
59 double ident(double x){
64 float lb,ub,mult,quant;
72 static char* colors[] = {
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];
95 void init(struct xy *);
96 void setopt(int, char *[]);
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 ***);
106 struct z setloglim(int, int, float, float);
107 struct z setlinlim(int, int, float, float);
109 int setmark(int *, struct xy *);
110 void submark(int *, int *, float, struct xy *);
112 int getfloat(float *);
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[]){
124 range(0,0,4096,4096);
127 xd.xsize = yd.xsize = 1.;
128 xx = (struct val *)malloc((unsigned)sizeof(struct val));
130 labels[labelsiz++] = 0;
136 getlim(&xd,(struct val *)&xx->xv);
137 getlim(&yd,(struct val *)&xx->yv);
139 equilibrate(&xd,&yd);
140 equilibrate(&yd,&xd);
152 void init(struct xy *p){
157 void setopt(int argc, char *argv[]){
161 xd.xlb = yd.xlb = INF;
162 xd.xub = yd.xub = -INF;
165 again: switch(argv[0][0]) {
169 case 'l': /* label for plot */
175 while (*p1++ = *p2++);
179 case 'd': /*disconnected,obsolete option*/
180 case 'm': /*line mode*/
182 if(!numb(&temp,&argc,&argv))
184 if(temp>=sizeof(modes)/sizeof(*modes))
191 if(numb(&temp,&argc,&argv) && temp>=1)
194 case 'a': /*automatic abscissas*/
197 if(!numb(&dx,&argc,&argv))
199 if(numb(&absbot,&argc,&argv))
203 case 's': /*save screen, overlay plot*/
207 case 'g': /*grid style 0 none, 1 ticks, 2 full*/
209 if(!numb(&temp,&argc,&argv))
210 temp = argv[0][1]-'0'; /*for caompatibility*/
215 case 'c': /*character(s) for plotting*/
224 case 't': /*transpose*/
227 case 'e': /*equal scales*/
233 case 'x': /*x limits */
234 limread(&xd,&argc,&argv);
237 limread(&yd,&argc,&argv);
239 case 'h': /*set height of plot */
240 if(!numb(&yd.xsize, &argc,&argv))
243 case 'w': /*set width of plot */
244 if(!numb(&xd.xsize, &argc, &argv))
247 case 'r': /* set offset to right */
248 if(!numb(&xd.xoff, &argc, &argv))
251 case 'u': /*set offset up the screen*/
252 if(!numb(&yd.xoff,&argc,&argv))
255 case 'p': /*pen color*/
256 colread(&argc, &argv);
264 void limread(struct xy *p, int *argcp, char ***argvp){
265 if(*argcp>1 && (*argvp)[1][0]=='l') {
270 if(!numb(&p->xlb,argcp,argvp))
273 if(!numb(&p->xub,argcp,argvp))
276 if(!numb(&p->xquant,argcp,argvp))
283 return '0'<=c && c<='9';
288 numb(float *np, int *argcp, char ***argvp){
293 while((c=(*argvp)[1][0]) == '+')
295 if(!(isdigit((uchar)c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.'))
297 *np = atof((*argvp)[1]);
303 void colread(int *argcp, char ***argvp){
309 n = strlen((*argvp)[1]);
310 if(strspn((*argvp)[1], "bcgkmrwy")!=n)
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;
330 else if(xd.xf==log10)
334 temp = (struct val *)realloc((char*)xx,
335 (unsigned)(n+ovlay)*sizeof(struct val));
340 xx[n].xv = n*dx/ovlay + absbot;
342 if(!getfloat(&xx[n].xv))
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))
352 xx[n+i].lblptr = copystring(t);
362 void transpose(void){
368 t = xd; xd = yd; yd = t;
370 f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f;
374 int copystring(int k){
379 temp = realloc(labels,(unsigned)(labelsiz+1+k));
385 labels[labelsiz++] = labbuf[i];
389 float modceil(float f, float t){
396 modfloor(float f, float t){
398 return(floor(f/t)*t);
401 void getlim(struct xy *p, struct val *v){
406 if(!p->xlbf && p->xlb>v[i].xv)
408 if(!p->xubf && p->xub<v[i].xv)
414 void setlim(struct xy *p){
425 if(delta*p->xquant <=0 )
441 else if(delta == 0) {
456 if(p->xf==log10 && lb>0 && ub>lb) {
457 z = setloglim(lbf,ubf,lb,ub);
462 if(setmark(mark,p)<2) {
463 p->xqf = lbf = ubf = 1;
464 lb = z.lb; ub = z.ub;
468 z = setlinlim(lbf,ubf,lb,ub);
477 p->xquant = sign*z.quant;
481 setloglim(int lbf, int ubf, float lb, float ub){
485 for(s=1; lb*s<1; s*=10) ;
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;
496 else if(lb >= 2*z.lb)
502 else if(ub*2 <= z.ub)
512 setlinlim(int lbf, int ubf, float xlb, float xub){
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*/
531 /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/
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) {
542 else if(!ubf && z.ub>=-r && z.ub<0) {
551 void scale(struct xy *p){
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)
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++) {
591 line(mark[i],yd.xbot,mark[i],yd.xtop);
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++) {
600 line(xd.xbot,mark[i],xd.xtop,mark[i]);
602 line(xd.xbot,mark[i],xd.xbot+tick,mark[i]);
603 line(xd.xtop-tick,mark[i],xd.xtop,mark[i]);
609 setmark(int *xmark, struct xy *p){
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);
625 xl = modceil(p->xlb+q/6,q);
626 xu = modfloor(p->xub-q/6,q)+q/2;
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;
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;
646 for(j=0;j<ovlay;j++) {
649 pen(modes[j%(sizeof modes/sizeof *modes-1)+1]);
656 color(palette[pencolor].name);
658 for(i=j; i<n; i+=ovlay) {
659 if(!conv(xx[i].xv,&xd,&ix) ||
660 !conv(xx[i].yv,&yd,&iy)) {
671 conn &= symbol(ix,iy,xx[i].lblptr);
673 pencolor = palette[pencolor].next;
679 conv(float xv, struct xy *p, int *ip){
681 ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb;
682 if(ix<p->xbot || ix>p->xtop)
700 i = scanf("%1s",labbuf);
705 if(!isdigit((uchar)*labbuf)) {
706 ungetc(*labbuf,stdin);
707 i = scanf("%s",labbuf);
713 ungetc(*labbuf,stdin);
716 i = scanf("%[^\"\n]",labbuf);
722 return(strlen(labbuf));
726 symbol(int ix, int iy, int k){
735 text(k>=0?labels+k:plotsymb);
746 strcpy(buf+3,titlebuf);
752 move(xd.xbot,yd.xbot-60);
756 void axlab(char c, struct xy *p, char *b){
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);
764 fprintf(stderr,"graph: error in arguments\n");