123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <stdio.h>
- #include "iplot.h"
- #define INF 1.e+37
- #define F .25
- struct xy {
- int xlbf; /*flag:explicit lower bound*/
- int xubf; /*flag:explicit upper bound*/
- int xqf; /*flag:explicit quantum*/
- double (*xf)(double); /*transform function, e.g. log*/
- float xa,xb; /*scaling coefficients*/
- float xlb,xub; /*lower and upper bound*/
- float xquant; /*quantum*/
- float xoff; /*screen offset fraction*/
- float xsize; /*screen fraction*/
- int xbot,xtop; /*screen coords of border*/
- float xmult; /*scaling constant*/
- } xd,yd;
- struct val {
- float xv;
- float yv;
- int lblptr;
- } *xx;
- char *labels;
- int labelsiz;
- int tick = 50;
- int top = 4000;
- int bot = 200;
- float absbot;
- int n;
- int erasf = 1;
- int gridf = 2;
- int symbf = 0;
- int absf = 0;
- int transf;
- int equf;
- int brkf;
- int ovlay = 1;
- float dx;
- char *plotsymb;
- #define BSIZ 80
- char labbuf[BSIZ];
- char titlebuf[BSIZ];
- char *modes[] = {
- "disconnected",
- "solid",
- "dotted",
- "dotdashed",
- "shortdashed",
- "longdashed"
- };
- int mode = 1;
- double ident(double x){
- return(x);
- }
- struct z {
- float lb,ub,mult,quant;
- };
- struct {
- char *name;
- int next;
- } palette[] = {
- ['b'] { "blue", 'b' },
- ['c'] { "cyan", 'c' },
- ['g'] { "green", 'g' },
- ['k'] { "kblack", 'k' },
- ['m'] { "magenta", 'm' },
- ['r'] { "red", 'r' },
- ['w'] { "white", 'w' },
- ['y'] { "yellow", 'y' }
- };
- int pencolor = 'k';
- void init(struct xy *);
- void setopt(int, char *[]);
- void readin(void);
- void transpose(void);
- void getlim(struct xy *, struct val *);
- void equilibrate(struct xy *, struct xy *);
- void scale(struct xy *);
- void limread(struct xy *, int *, char ***);
- int numb(float *, int *, char ***);
- void colread(int *, char ***);
- int copystring(int);
- struct z setloglim(int, int, float, float);
- struct z setlinlim(int, int, float, float);
- void axes(void);
- int setmark(int *, struct xy *);
- void submark(int *, int *, float, struct xy *);
- void plot(void);
- int getfloat(float *);
- int getstring(void);
- void title(void);
- void badarg(void);
- int conv(float, struct xy *, int *);
- int symbol(int, int, int);
- void axlab(char, struct xy *, char *);
- void main(int argc,char *argv[]){
- openpl();
- range(0,0,4096,4096);
- init(&xd);
- init(&yd);
- xd.xsize = yd.xsize = 1.;
- xx = (struct val *)malloc((unsigned)sizeof(struct val));
- labels = malloc(1);
- labels[labelsiz++] = 0;
- setopt(argc,argv);
- if(erasf)
- erase();
- readin();
- transpose();
- getlim(&xd,(struct val *)&xx->xv);
- getlim(&yd,(struct val *)&xx->yv);
- if(equf) {
- equilibrate(&xd,&yd);
- equilibrate(&yd,&xd);
- }
- scale(&xd);
- scale(&yd);
- axes();
- title();
- plot();
- closepl();
- exits(0);
- }
- void init(struct xy *p){
- p->xf = ident;
- p->xmult = 1;
- }
- void setopt(int argc, char *argv[]){
- char *p1, *p2;
- float temp;
- xd.xlb = yd.xlb = INF;
- xd.xub = yd.xub = -INF;
- while(--argc > 0) {
- argv++;
- again: switch(argv[0][0]) {
- case '-':
- argv[0]++;
- goto again;
- case 'l': /* label for plot */
- p1 = titlebuf;
- if (argc>=2) {
- argv++;
- argc--;
- p2 = argv[0];
- while (*p1++ = *p2++);
- }
- break;
- case 'd': /*disconnected,obsolete option*/
- case 'm': /*line mode*/
- mode = 0;
- if(!numb(&temp,&argc,&argv))
- break;
- if(temp>=sizeof(modes)/sizeof(*modes))
- mode = 1;
- else if(temp>=-1)
- mode = temp;
- break;
- case 'o':
- if(numb(&temp,&argc,&argv) && temp>=1)
- ovlay = temp;
- break;
- case 'a': /*automatic abscissas*/
- absf = 1;
- dx = 1;
- if(!numb(&dx,&argc,&argv))
- break;
- if(numb(&absbot,&argc,&argv))
- absf = 2;
- break;
- case 's': /*save screen, overlay plot*/
- erasf = 0;
- break;
- case 'g': /*grid style 0 none, 1 ticks, 2 full*/
- gridf = 0;
- if(!numb(&temp,&argc,&argv))
- temp = argv[0][1]-'0'; /*for caompatibility*/
- if(temp>=0&&temp<=2)
- gridf = temp;
- break;
- case 'c': /*character(s) for plotting*/
- if(argc >= 2) {
- symbf = 1;
- plotsymb = argv[1];
- argv++;
- argc--;
- }
- break;
- case 't': /*transpose*/
- transf = 1;
- break;
- case 'e': /*equal scales*/
- equf = 1;
- break;
- case 'b': /*breaks*/
- brkf = 1;
- break;
- case 'x': /*x limits */
- limread(&xd,&argc,&argv);
- break;
- case 'y':
- limread(&yd,&argc,&argv);
- break;
- case 'h': /*set height of plot */
- if(!numb(&yd.xsize, &argc,&argv))
- badarg();
- break;
- case 'w': /*set width of plot */
- if(!numb(&xd.xsize, &argc, &argv))
- badarg();
- break;
- case 'r': /* set offset to right */
- if(!numb(&xd.xoff, &argc, &argv))
- badarg();
- break;
- case 'u': /*set offset up the screen*/
- if(!numb(&yd.xoff,&argc,&argv))
- badarg();
- break;
- case 'p': /*pen color*/
- colread(&argc, &argv);
- break;
- default:
- badarg();
- }
- }
- }
- void limread(struct xy *p, int *argcp, char ***argvp){
- if(*argcp>1 && (*argvp)[1][0]=='l') {
- (*argcp)--;
- (*argvp)++;
- p->xf = log10;
- }
- if(!numb(&p->xlb,argcp,argvp))
- return;
- p->xlbf = 1;
- if(!numb(&p->xub,argcp,argvp))
- return;
- p->xubf = 1;
- if(!numb(&p->xquant,argcp,argvp))
- return;
- p->xqf = 1;
- }
- isdigit(char c){
- return '0'<=c && c<='9';
- }
- numb(float *np, int *argcp, char ***argvp){
- char c;
- if(*argcp <= 1)
- return(0);
- while((c=(*argvp)[1][0]) == '+')
- (*argvp)[1]++;
- if(!(isdigit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.'))
- return(0);
- *np = atof((*argvp)[1]);
- (*argcp)--;
- (*argvp)++;
- return(1);
- }
- void colread(int *argcp, char ***argvp){
- int c, cnext;
- int i, n;
- if(*argcp<=1)
- return;
- n = strlen((*argvp)[1]);
- if(strspn((*argvp)[1], "bcgkmrwy")!=n)
- return;
- pencolor = cnext = (*argvp)[1][0];
- for(i=0; i<n-1; i++){
- c = (unsigned char)(*argvp)[1][i];
- cnext = (unsigned char)(*argvp)[1][i+1];
- palette[c].next = cnext;
- }
- palette[cnext].next = pencolor;
- (*argcp)--;
- (*argvp)++;
- }
- void readin(void){
- int i, t;
- struct val *temp;
- if(absf==1) {
- if(xd.xlbf)
- absbot = xd.xlb;
- else if(xd.xf==log10)
- absbot = 1;
- }
- for(;;) {
- temp = (struct val *)realloc((char*)xx,
- (unsigned)(n+ovlay)*sizeof(struct val));
- if(temp==0)
- return;
- xx = temp;
- if(absf)
- xx[n].xv = n*dx/ovlay + absbot;
- else
- if(!getfloat(&xx[n].xv))
- return;
- t = 0; /* silence compiler */
- for(i=0;i<ovlay;i++) {
- xx[n+i].xv = xx[n].xv;
- if(!getfloat(&xx[n+i].yv))
- return;
- xx[n+i].lblptr = -1;
- t = getstring();
- if(t>0)
- xx[n+i].lblptr = copystring(t);
- if(t<0 && i+1<ovlay)
- return;
- }
- n += ovlay;
- if(t<0)
- return;
- }
- }
- void transpose(void){
- int i;
- float f;
- struct xy t;
- if(!transf)
- return;
- t = xd; xd = yd; yd = t;
- for(i= 0;i<n;i++) {
- f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f;
- }
- }
- int copystring(int k){
- char *temp;
- int i;
- int q;
- temp = realloc(labels,(unsigned)(labelsiz+1+k));
- if(temp==0)
- return(0);
- labels = temp;
- q = labelsiz;
- for(i=0;i<=k;i++)
- labels[labelsiz++] = labbuf[i];
- return(q);
- }
- float modceil(float f, float t){
- t = fabs(t);
- return(ceil(f/t)*t);
- }
- float
- modfloor(float f, float t){
- t = fabs(t);
- return(floor(f/t)*t);
- }
- void getlim(struct xy *p, struct val *v){
- int i;
- i = 0;
- do {
- if(!p->xlbf && p->xlb>v[i].xv)
- p->xlb = v[i].xv;
- if(!p->xubf && p->xub<v[i].xv)
- p->xub = v[i].xv;
- i++;
- } while(i < n);
- }
- void setlim(struct xy *p){
- float t,delta,sign;
- struct z z;
- int mark[50];
- float lb,ub;
- int lbf,ubf;
- lb = p->xlb;
- ub = p->xub;
- delta = ub-lb;
- if(p->xqf) {
- if(delta*p->xquant <=0 )
- badarg();
- return;
- }
- sign = 1;
- lbf = p->xlbf;
- ubf = p->xubf;
- if(delta < 0) {
- sign = -1;
- t = lb;
- lb = ub;
- ub = t;
- t = lbf;
- lbf = ubf;
- ubf = t;
- }
- else if(delta == 0) {
- if(ub > 0) {
- ub = 2*ub;
- lb = 0;
- }
- else
- if(lb < 0) {
- lb = 2*lb;
- ub = 0;
- }
- else {
- ub = 1;
- lb = -1;
- }
- }
- if(p->xf==log10 && lb>0 && ub>lb) {
- z = setloglim(lbf,ubf,lb,ub);
- p->xlb = z.lb;
- p->xub = z.ub;
- p->xmult *= z.mult;
- p->xquant = z.quant;
- if(setmark(mark,p)<2) {
- p->xqf = lbf = ubf = 1;
- lb = z.lb; ub = z.ub;
- } else
- return;
- }
- z = setlinlim(lbf,ubf,lb,ub);
- if(sign > 0) {
- p->xlb = z.lb;
- p->xub = z.ub;
- } else {
- p->xlb = z.ub;
- p->xub = z.lb;
- }
- p->xmult *= z.mult;
- p->xquant = sign*z.quant;
- }
- struct z
- setloglim(int lbf, int ubf, float lb, float ub){
- float r,s,t;
- struct z z;
- for(s=1; lb*s<1; s*=10) ;
- lb *= s;
- ub *= s;
- for(r=1; 10*r<=lb; r*=10) ;
- for(t=1; t<ub; t*=10) ;
- z.lb = !lbf ? r : lb;
- z.ub = !ubf ? t : ub;
- if(ub/lb<100) {
- if(!lbf) {
- if(lb >= 5*z.lb)
- z.lb *= 5;
- else if(lb >= 2*z.lb)
- z.lb *= 2;
- }
- if(!ubf) {
- if(ub*5 <= z.ub)
- z.ub /= 5;
- else if(ub*2 <= z.ub)
- z.ub /= 2;
- }
- }
- z.mult = s;
- z.quant = r;
- return(z);
- }
- struct z
- setlinlim(int lbf, int ubf, float xlb, float xub){
- struct z z;
- float r,s,delta;
- float ub,lb;
- loop:
- ub = xub;
- lb = xlb;
- delta = ub - lb;
- /*scale up by s, a power of 10, so range (delta) exceeds 1*/
- /*find power of 10 quantum, r, such that delta/10<=r<delta*/
- r = s = 1;
- while(delta*s < 10)
- s *= 10;
- delta *= s;
- while(10*r < delta)
- r *= 10;
- lb *= s;
- ub *= s;
- /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/
- if(r>=delta/2)
- r /= 2;
- else if(r<delta/5)
- r *= 2;
- z.ub = ubf? ub: modceil(ub,r);
- z.lb = lbf? lb: modfloor(lb,r);
- if(!lbf && z.lb<=r && z.lb>0) {
- xlb = 0;
- goto loop;
- }
- else if(!ubf && z.ub>=-r && z.ub<0) {
- xub = 0;
- goto loop;
- }
- z.quant = r;
- z.mult = s;
- return(z);
- }
- void scale(struct xy *p){
- float edge;
- setlim(p);
- edge = top-bot;
- p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb));
- p->xbot = bot + edge*p->xoff;
- p->xtop = p->xbot + (top-bot)*p->xsize;
- p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5;
- }
- void equilibrate(struct xy *p, struct xy *q){
- if(p->xlbf|| /* needn't test xubf; it implies xlbf*/
- q->xubf&&q->xlb>q->xub)
- return;
- if(p->xlb>q->xlb) {
- p->xlb = q->xlb;
- p->xlbf = q->xlbf;
- }
- if(p->xub<q->xub) {
- p->xub = q->xub;
- p->xubf = q->xubf;
- }
- }
- void axes(void){
- int i;
- int mark[50];
- int xn, yn;
- if(gridf==0)
- return;
- line(xd.xbot,yd.xbot,xd.xtop,yd.xbot);
- vec(xd.xtop,yd.xtop);
- vec(xd.xbot,yd.xtop);
- vec(xd.xbot,yd.xbot);
- xn = setmark(mark,&xd);
- for(i=0; i<xn; i++) {
- if(gridf==2)
- line(mark[i],yd.xbot,mark[i],yd.xtop);
- if(gridf==1) {
- line(mark[i],yd.xbot,mark[i],yd.xbot+tick);
- line(mark[i],yd.xtop-tick,mark[i],yd.xtop);
- }
- }
- yn = setmark(mark,&yd);
- for(i=0; i<yn; i++) {
- if(gridf==2)
- line(xd.xbot,mark[i],xd.xtop,mark[i]);
- if(gridf==1) {
- line(xd.xbot,mark[i],xd.xbot+tick,mark[i]);
- line(xd.xtop-tick,mark[i],xd.xtop,mark[i]);
- }
- }
- }
- int
- setmark(int *xmark, struct xy *p){
- int xn = 0;
- float x,xl,xu;
- float q;
- if(p->xf==log10&&!p->xqf) {
- for(x=p->xquant; x<p->xub; x*=10) {
- submark(xmark,&xn,x,p);
- if(p->xub/p->xlb<=100) {
- submark(xmark,&xn,2*x,p);
- submark(xmark,&xn,5*x,p);
- }
- }
- } else {
- xn = 0;
- q = p->xquant;
- if(q>0) {
- xl = modceil(p->xlb+q/6,q);
- xu = modfloor(p->xub-q/6,q)+q/2;
- } else {
- xl = modceil(p->xub-q/6,q);
- xu = modfloor(p->xlb+q/6,q)-q/2;
- }
- for(x=xl; x<=xu; x+=fabs(p->xquant))
- xmark[xn++] = (*p->xf)(x)*p->xa + p->xb;
- }
- return(xn);
- }
- void submark(int *xmark, int *pxn, float x, struct xy *p){
- if(1.001*p->xlb < x && .999*p->xub > x)
- xmark[(*pxn)++] = log10(x)*p->xa + p->xb;
- }
- void plot(void){
- int ix,iy;
- int i,j;
- int conn;
- for(j=0;j<ovlay;j++) {
- switch(mode) {
- case -1:
- pen(modes[j%(sizeof modes/sizeof *modes-1)+1]);
- break;
- case 0:
- break;
- default:
- pen(modes[mode]);
- }
- color(palette[pencolor].name);
- conn = 0;
- for(i=j; i<n; i+=ovlay) {
- if(!conv(xx[i].xv,&xd,&ix) ||
- !conv(xx[i].yv,&yd,&iy)) {
- conn = 0;
- continue;
- }
- if(mode!=0) {
- if(conn != 0)
- vec(ix,iy);
- else
- move(ix,iy);
- conn = 1;
- }
- conn &= symbol(ix,iy,xx[i].lblptr);
- }
- pencolor = palette[pencolor].next;
- }
- pen(modes[1]);
- }
- int
- conv(float xv, struct xy *p, int *ip){
- int32_t ix;
- ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb;
- if(ix<p->xbot || ix>p->xtop)
- return(0);
- *ip = ix;
- return(1);
- }
- int
- getfloat(float *p){
- int i;
- i = scanf("%f",p);
- return(i==1);
- }
- int
- getstring(void){
- int i;
- char junk[20];
- i = scanf("%1s",labbuf);
- if(i==-1)
- return(-1);
- switch(*labbuf) {
- default:
- if(!isdigit(*labbuf)) {
- ungetc(*labbuf,stdin);
- i = scanf("%s",labbuf);
- break;
- }
- case '.':
- case '+':
- case '-':
- ungetc(*labbuf,stdin);
- return(0);
- case '"':
- i = scanf("%[^\"\n]",labbuf);
- scanf("%[\"]",junk);
- break;
- }
- if(i==-1)
- return(-1);
- return(strlen(labbuf));
- }
- int
- symbol(int ix, int iy, int k){
- if(symbf==0&&k<0) {
- if(mode==0)
- point(ix,iy);
- return(1);
- }
- else {
- move(ix,iy);
- text(k>=0?labels+k:plotsymb);
- move(ix,iy);
- return(!brkf|k<0);
- }
- }
- void title(void){
- char buf[BSIZ+100];
- buf[0] = ' ';
- buf[1] = ' ';
- buf[2] = ' ';
- strcpy(buf+3,titlebuf);
- if(erasf&&gridf) {
- axlab('x',&xd,buf);
- strcat(buf,",");
- axlab('y',&yd,buf);
- }
- move(xd.xbot,yd.xbot-60);
- text(buf);
- }
- void axlab(char c, struct xy *p, char *b){
- char *dir;
- dir = p->xlb<p->xub? "<=": ">=";
- sprintf(b+strlen(b), " %g %s %c%s %s %g", p->xlb/p->xmult,
- dir, c, p->xf==log10?" (log)":"", dir, p->xub/p->xmult);
- }
- void badarg(void){
- fprintf(stderr,"graph: error in arguments\n");
- closepl();
- exits("bad arg");
- }
|