Plan 9 from Bell Labs’s /usr/web/sources/contrib/gabidiaz/root/sys/src/cmd/drawvars/drawvars.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include  <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <bio.h>

#define MAXVARS	7



// test cmd awk 'BEGIN{for(x=0;x<100;x++) { print x " " 100*rand() " " 100*(rand()*rand())  }}' | 8.out -t 'awk rand() distribution' -s 0 -e 100 -m 120 -v x,'rand()','rand()^2' | topng > sample.png


/* colors */
enum {
	Peach,
	Aqua,
	Green,
	Blue,
	Grey,
	Pink,
	Yellow,
	White,
	Black,
};

struct Color {
	Memimage *bg;
	Memimage *fg;
	Memimage *hl;
};
typedef struct Color Color;


/* figures */
typedef struct fpoint {
	double x, y;
} fpoint;

typedef struct frectangle {
	fpoint min, max;
} frectangle;

typedef struct polygon {
	Point *p;			/* a malloc'ed array */
	int n;				/* p[] has n elements: p[0..n] */
} polygon;

/* input values */
struct Var {
	char *s;
	int c;
	double max;
	double min;
	double mean;
	double sum;
	polygon fig;
};

typedef struct Var Var;

Var *V;
int Nvars;
Color Pallete[8];  


/* utils */
void*
emalloc(ulong sz)
{
	void *v;

	if((v = malloc(sz)) == nil) {
		fprint(2, "out of memory allocating %lud\n", sz);
		exits("mem");
	}
	memset(v, 0, sz);
	setmalloctag(v, getcallerpc(&sz));
	return v;
}

void*
erealloc(void *v, ulong sz)
{
	void *nv;

	if((nv = realloc(v, sz)) == nil) {
		fprint(2, "out of memory allocating %lud\n", sz);
		exits("mem");
	}
	if(v == nil)
		setmalloctag(nv, getcallerpc(&v));
	setrealloctag(nv, getcallerpc(&v));
	return nv;
}


void
mkcol(int i, int c0, int c1, int c2, Rectangle clipr)
{
	Pallete[i].bg = allocmemimage(Rect(0,0,1,1),RGB24);
	memfillcolor(Pallete[i].bg,c0); Pallete[i].bg->flags=Frepl;
	Pallete[i].bg->clipr = clipr;
	Pallete[i].fg = allocmemimage(Rect(0,0,1,1),RGB24);
	memfillcolor(Pallete[i].fg,c1);Pallete[i].fg->flags=Frepl;
	Pallete[i].fg->clipr = clipr;
	Pallete[i].hl = allocmemimage(Rect(0,0,1,1),RGB24);
	memfillcolor(Pallete[i].hl,c2);Pallete[i].hl->flags=Frepl;
	Pallete[i].hl->clipr = clipr;
}


void
colinit(Rectangle clipr)
{
	mkcol(Peach, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF,clipr);
	mkcol(Aqua, DPalebluegreen, DPalegreygreen, DPurpleblue,clipr);
	mkcol(Yellow, DPaleyellow, DDarkyellow, DYellowgreen,clipr);
	mkcol(Green, DPalegreen, DMedgreen, DDarkgreen,clipr);
	mkcol(Blue, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF,clipr);
	mkcol(Grey,0xEEEEEEFF,0xCCCCCCFF,0x888888FF,clipr);
	mkcol(Pink,0xffaaaaFF, 0x990099FF, 0xffaa00FF,clipr);
	mkcol(White,0xffffffff,0xffffffff,0xffffffff,clipr);
	mkcol(Black,0,0,0,clipr);

}

Rectangle
frtor(frectangle fr)
{
	Rectangle r;
	r.max.x = (int) fr.max.x;
	r.max.y = (int) fr.max.y;
	r.min.x = (int) fr.min.x;
	r.min.y = (int) fr.min.y;
	
	return r;
}

Point
fptop(fpoint fp) 
{
	Point p;
	p.x = (int)fp.x;
	p.y = (int)fp.y;
	
	return p;
}


fpoint
fPt(double  x, double y)
{
	fpoint p;

	p.x = x;
	p.y = y;
	return p;
}

frectangle
fRect(double x, double y, double bx, double by)
{
	frectangle r;

	r.min.x = x;
	r.min.y = y;
	r.max.x = bx;
	r.max.y = by;
	return r;
}

fpoint
transform(frectangle dr, frectangle s, fpoint sp)
{
	fpoint dp;


	( sp.x > s.max.x ) ?  sp.x = s.max.x-1 : 1;
	( sp.x <= s.min.x ) ? sp.x=s.min.x+1 : 1;
	(sp.y > s.max.y) ? sp.y=s.max.y-1 : 1;
	(sp.y <= s.min.y) ? sp.y=s.min.y+1 : 1;
 
	if ( sp.x == 0 )
		dp.x = dr.min.x;
	else {
		dp.x =(dr.max.x-dr.min.x)/((s.max.x-s.min.x)/(sp.x-s.min.x));
		dp.x += dr.min.x;
	}
	if (sp.y == 0 )
		dp.y = dr.min.y;
	else {
		dp.y = (dr.max.y-dr.min.y)/((s.max.y-s.min.y)/(sp.y-s.min.y));
 		dp.y += dr.min.y;
	}

	// adjust the y coords
	dp.y = (dr.max.y - dp.y)+dr.min.y;

	return  dp;
}

void 
addptvar(int i, fpoint p) {

		if( V[i].fig.p == nil ) {
			V[i].fig.p = emalloc(sizeof(Point));
			V[i].fig.p[0] = fptop(p);
			V[i].fig.n = 0;
		} else {
			V[i].fig.p = erealloc(V[i].fig.p,sizeof(Point)*(V[i].fig.n+1));
			V[i].fig.p[V[i].fig.n] =  fptop(p);
			V[i].fig.n++;
		}

}

void
endpolys(fpoint end){

	for(int i=1;i<Nvars;i++) {
			if ( V[i].fig.n >=1 ) {
				addptvar(i,fPt(V[i].fig.p[V[i].fig.n-1].x, end.y));
				addptvar(i,fPt(V[i].fig.p[0].x, end.y));
			}
	}

}

void
getvals(frectangle dst, double start, double end, double maxval)
{
	Biobuf bin;
	char *line;
	double xval,yval;
	char *vals[MAXVARS];
	fpoint p;
	frectangle src;
	int i,n, nvals;
	
	
	src=fRect(start,0,end,maxval);
	Binit(&bin,0,OREAD);
	nvals = 1;
	while((line=Brdstr(&bin, '\n', 1)) != nil){
		n =getfields(line, vals, Nvars, 1, " ");
		if ( n != Nvars )
			sysfatal("getvals(): error getting values");
		xval=strtod(vals[0],0);

		for(i=1;i<Nvars;i++) {
			
			yval=strtod(vals[i],0);
			p = transform(dst,src,fPt(xval,yval));

			addptvar(i,p);

			// fill stats
			if ( V[i].fig.n < 1 )
				V[i].min = yval;
			if ( yval > V[i].max )  
				V[i].max = yval;
			else if ( yval < V[i].min )
				V[i].min = yval;

			V[i].sum += yval;
			V[i].mean = V[i].sum / nvals;
		}
		free(line);
		line = nil;
		nvals++;
	}
	Bterm(&bin);
	endpolys(dst.max);
	
}

void
drawvalue(Memimage *dst,polygon *pol, int color, int fill)
{
	if (fill)
		 memfillpoly(dst, pol->p, pol->n, 0,Pallete[color].fg, pol->p[0], SoverD);
	 
	mempoly(dst,pol->p,pol->n,Endsquare,Endsquare,0,Pallete[color].hl,pol->p[0],SoverD);

}


/* draw functions */
void
drawbox(Memimage *dst, frectangle box,int color, int fill) 
{
	int radius;
	Point rect[5];
	Drawop dop;
	
	dop = SoverD;
	radius=0;

	rect[0] = fptop(box.min);
	rect[1].x = box.max.x; rect[1].y = box.min.y;
	rect[2] = fptop(box.max);
	rect[3].x = box.min.x; rect[3].y = box.max.y;
	rect[4] = fptop(box.min);

	if (fill)
		 memfillpoly(dst, rect, 5, 1,Pallete[color].fg, ZP, dop);
	else
		mempoly(dst,rect,5,Endsquare,Endsquare,radius,Pallete[color].fg,ZP,dop);

}

void
drawtext(Memimage *dst,Point p, int color,int size,char *s)
{
	Memsubfont *f;
	char *font;

	font=smprint("/lib/font/bit/lucida/latin1.%d.0",size);
	
	f = openmemsubfont(font);

	if ( f == nil )
		sysfatal("cannot open font: %r\n");

	memimagestring(dst, p, Pallete[color].fg, ZP, f, s);
	freememsubfont(f);
}


void 
drawresume(Memimage *dst,frectangle coord)
{
	char *str;
	frectangle c;
	c = fRect(coord.min.x+2,coord.min.y+2,coord.min.x+10,coord.min.y+10);
	for(int i=1;i<Nvars;i++) {
		drawbox(dst,c,V[i].c,1);
		str=smprint("%s: max %f min %f mean %f",V[i].s,V[i].max, V[i].min,V[i].mean);
		drawtext(dst,Pt(c.min.x+15,c.min.y-4),Black,7,str);
		// next point
		c = fRect(c.min.x+0,c.min.y+15,c.max.x+0,c.max.y+15); 
	}
	
}

void 
drawgrid(Memimage *dst,frectangle grid, frectangle stats, double xmin, double xmax, double ymax, int istime)
{
	Point p0x,p1x,p0y,p1y;
	int i;
	double stepx, stepy, vstepx;
	char *str;
	long xval,hms,hour,min,d1;
	long clockl;
	/* a line each 10% of the total */
	stepx = (stats.max.x-stats.min.x)/10;
	stepy = (stats.max.y-stats.min.y)/10;
	/* estimated value for the x coord */
	vstepx = (xmax-xmin)/10;

	for(i=10;i>=0;i--) 
	{
		p0x=Pt(stats.min.x+i*stepx,stats.min.y);
		p1x=Pt(stats.min.x+i*stepx,grid.max.y-10);
		p0y=Pt(grid.min.x+15,(stats.max.y-i*stepy));
		p1y=Pt(grid.max.x,(stats.max.y-i*stepy));
		memimageline(dst,p0x,p1x,0,0,0,Pallete[Grey].hl,ZP,SoverD);
		memimageline(dst,p0y,p1y,0,0,0,Pallete[Grey].hl,ZP,SoverD);
		xval = i*vstepx+xmin;
		if ( istime) {
			hms = xval % 86400L;
			if(hms < 0) 
				hms += 86400L;
			d1 = hms / 60;
			min = d1 % 60;
			d1 /= 60;
			hour = d1;
			str = smprint("%0.2d:%0.2d",hour,min);
		} else
			str=smprint("%3.0G",xval);

		drawtext(dst,Pt(p1x.x-10,p1x.y+5),Black,6,str);
		free(str);
		str=smprint("%G",(ymax*i)/10);
		drawtext(dst,Pt(p0y.x-25,p0y.y-5),Black,6,str);free(str);
		
	}

	drawtext(dst,Pt(stats.min.x-25,grid.max.y-7), Black,8,V[0].s);

}


void
usage(char *s)
{

	fprint(2,"%s [-T] -t title -s start -e end -m maxval  -v var1,var2,var3. . .\n",s);
	exits("usage");
}

void 
main(int argc, char *argv[]) 
{
	frectangle r,stats,grid,legend,resume,total,title;
	Memimage *m;
	char *varlist, *tstr;
	char *varnames[MAXVARS];
	int maxval,start,end,i;
	int istime=0;

	if (argc < 8 )
		usage(argv[0]);

	ARGBEGIN {
		case 's':
			start=strtod(ARGF(),0);
			break;
		case 'e':
			end=strtod(ARGF(),0);
			break;
		case 'm':
			maxval=strtod(ARGF(),0);
			break;
		case 'v':
			varlist=ARGF();
			break;
		case 't':
			tstr=ARGF();
			break;
		case 'T':
			istime=1;
			break;
		default:
			fprint(2,"unknown flag ('%c')",ARGC());
			exits("error in flags");
	} ARGEND

	if ( argc != 0 || tstr == nil )
		usage(argv[0]);
	
	memimageinit();
	

	Nvars = getfields(varlist, varnames, MAXVARS, 1, ",");
	if ( Nvars == 0 || Nvars > MAXVARS)
		sysfatal("Incorrect var number check -v option  (%d)\n",Nvars);

	V = emalloc(sizeof(Var)*Nvars);

	for(i=0;i<Nvars;i++) {
		V[i].s=smprint("%s",varnames[i]);
		V[i].c=i;
		V[i].fig.p = nil;
		V[i].max = V[i].min = V[i].sum = V[i].mean = V[i].fig.n = 0;
	}

	r = fRect(0,0,550,300);
	m = allocmemimage(frtor(r),RGB24);
	
	m->clipr = m->r;
	colinit(m->clipr);

	grid = fRect(r.min.x+20,r.min.y+30,r.max.x-20,r.max.y-80);
	stats= fRect(grid.min.x+20,grid.min.y,grid.max.x,grid.max.y-20);
	resume = fRect(grid.min.x,grid.max.y+15,grid.max.x,r.max.y-2);
	title = fRect(grid.min.x,r.min.y+2,grid.max.x,stats.min.y-2);

	getvals(stats, start, end, maxval);
	
	// draw the data!! 
	memfillcolor(m,DWhite);
	drawbox(m,stats,White,1);
	drawgrid(m,grid,stats,start,end,maxval, istime);
	for(i=1;i<Nvars;i++) {
		drawvalue(m,&V[i].fig, V[i].c, 1);
	}
	
	drawtext(m,fptop(title.min),Black,8,tstr);
	
	drawresume(m,resume);
	drawbox(m,stats,Black,0);
	r.max.x--; r.max.y--;
	drawbox(m,r,Grey,0);
	writememimage(1,m);
	
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.