MODULE WMSimpleGraphs; (** AUTHOR "Patrick Hunziker"; PURPOSE "Minimum-overhead graph drawing and storing"; *) (** right-click on navigator thumbnail allows window storage as image file *) (*ToDo: ticks for Graph. labels on axes *) (*ToDo: catch NaN and Inf in data and other strategies to avoid erratic window sizes*) IMPORT Strings, WMGraphics, WMRectangles, Modules, Reals, WM:=WMWindowManager, MathL; CONST Colors=[WMGraphics.Red,WMGraphics.Blue,WMGraphics.Green,WMGraphics.Yellow, WMGraphics.Magenta, WMGraphics.Cyan, WMGraphics.Gray]; MinSize=30; TYPE Regressor=PROCEDURE{DELEGATE}(CONST data: ARRAY [*,*] OF LONGREAL; VAR slope,intercept: LONGREAL); TYPE Window=OBJECT(WM.Window); VAR width,height:LONGINT; END Window; Histogram* = OBJECT (Window); VAR data:ARRAY [*] OF LONGREAL; PROCEDURE &New*(CONST data: ARRAY [*] OF LONGREAL; CONST title: ARRAY OF CHAR); VAR max:LONGREAL; w0,h0:LONGINT; BEGIN SELF.data:=data; max:=MAX(data); width:=LEN(data,0); height:=ENTIER(max)+1; IF (width=0 THEN col:=WMGraphics.RGBAToColor(valI,valI,valI,255); ELSE col:=WMGraphics.RGBAToColor(-valI,0,0,255); END; canvas.Fill(WMRectangles.MakeRect(x*w DIV width, h-ENTIER(0.5+(y+1)*h/height), (x+1)*w DIV width, h-ENTIER(0.5+y*h/height)), col, WMGraphics.ModeCopy); END; END; INC(timestamp); END Draw; END Matrix; Graph* = OBJECT (Window); CONST border=5; VAR data:ARRAY [*] OF LONGREAL; max,min:LONGREAL; PROCEDURE &New*(CONST data: ARRAY [*] OF LONGREAL; CONST title: ARRAY OF CHAR); VAR w0,h0:LONGINT; BEGIN SELF.data:=data; max:=MAX(1, MAX(data)); min:=MIN(0, MIN(data)); width:=LEN(data,0); height:=ENTIER(max-min)+1; IF Reals.IsNaNL(width) THEN width:=100 END; IF Reals.IsNaNL(height) THEN height:=100 END; IF (width2 THEN (* vertical error bars*) ey:=ENTIER(0.5+data[2,i]*scaley); canvas.Line(x, y-ey, x, y+ey,WMGraphics.Blue, WMGraphics.ModeCopy); IF LEN(data,0)>3 THEN (*horizontal error bars*) ex:=ENTIER(0.5+data[3,i]*scalex); canvas.Line(x-ex, y, x+ex, y,WMGraphics.Red, WMGraphics.ModeCopy); END; END; END; Axes(canvas,w,h,mnw,mnh,scalex,scaley); INC(timestamp); END Draw; END Scatter; (** Regression plot. requires computation of slope,intercept by suited procedure, e.g. derived from /Matrix/StatisticsLinearRegression.SimpleRegression() *) TYPE Regression*= OBJECT (Scatter) VAR slope,intercept: LONGREAL; regressor:Regressor; PROCEDURE &Initialize*(CONST data: ARRAY [*,*] OF LONGREAL; CONST title: ARRAY OF CHAR; regress:Regressor); BEGIN regressor:=regress; regressor(data,slope,intercept); New(data,title); END Initialize; PROCEDURE NewData*(CONST data: ARRAY [*,*] OF LONGREAL); BEGIN regressor(data,slope,intercept); NewData^(data); END NewData; PROCEDURE Draw*(canvas : WMGraphics.Canvas; w, h, q : LONGINT); VAR mnw,mnh,x,y,xx,yy:LONGINT; scalex,scaley, x0, y0, x1, y1:LONGREAL; BEGIN Draw^(canvas,w,h,q); x0:= minx; y0:= x0*slope+intercept; IF (y0maxy THEN y0:=maxy; x0:=(y0-intercept)/slope; END; x1:=maxx; y1:=x1*slope+intercept; IF (y1maxy THEN y1:=maxy; x1:=(y1-intercept)/slope; END; scalex:=scaleRatio*w/width; scaley:=scaleRatio*h/height; mnw:=-border+ENTIER(0.5+minx* scalex); mnh:=-border+ENTIER(0.5+miny* scaley); x:=-mnw+ENTIER(0.5+x0*scalex); y:=h+mnh-ENTIER(0.5+y0*scaley); xx:=-mnw+ENTIER(0.5+x1*scalex); yy:=h+mnh-ENTIER(0.5+y1*scaley); canvas.Line(x,y,xx,yy,WMGraphics.Red, WMGraphics.ModeCopy); END Draw; END Regression; PROCEDURE NewWindowPos(dx:LONGINT); BEGIN INC(Pos,dx); PosX:=Pos MOD 700; PosY:=100+ (Pos DIV 700)*50 MOD 700; END NewWindowPos; PROCEDURE Log10(x:LONGREAL):LONGREAL; BEGIN RETURN MathL.ln(x)/MathL.ln(10); END Log10; PROCEDURE Exp10(x:LONGREAL):LONGREAL; BEGIN RETURN MathL.exp(ENTIER(x)*MathL.ln(10)); END Exp10; PROCEDURE DummyRegressor(CONST data: ARRAY [*,*] OF LONGREAL; VAR slope,intercept:LONGREAL); BEGIN slope:=1; intercept:=2; END DummyRegressor; VAR Pos, PosX,PosY: LONGINT; PROCEDURE Demo*; VAR h:Histogram; g:Graph; k: Graphs; gx:GraphXY; m:Matrix; s:Scatter; r:Regression; BEGIN {EXCLUSIVE} NEW(h, [4,7,8,4,5,9,6,5,3,2,12,17,3,0,2], "Histogram"); NEW(g, [4,7,8,4,5,9,6,5,3,2,12,17,3,-3,2], "Graph"); NEW(k, [[-2,7,8,4,5,9,6,4,7,8,4,5,9,6], [5,3,2,12,21,3,0,5,3,-2,12,17,4,1]], "MultiGraph"); NEW(gx, [[0.2,-1,0,1,5,9,6,4,7,3,4,5,9,6], [0.2,3,4,7,12,3,0,5,3,-2,12,17,4,1]], "GraphXY"); NEW(s, [ [0.2,-1,0,1,5,9,6,4,7,3,4,5,9,6], [0.2,3,4,7,12,3,0,5,3,-2,12,17,4,1], [1,0.6,1.1,1,1.4,1,1,1,0.7,1,1,0.8,1,1], [0.5,0.3,0.6,0.4,0.5,0.3,0.6,0.5,0.5,0.4,0.7,0.5,0.5,0.5]], "Scatter with x and y error bars"); NEW(r, [ [0.2,-1,0,1,5,9,6,4,7,3,4,5,9,6], [0.2,3,4,7,12,3,0,5,3,-2,12,17,4,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1]], "Regression with y error bars", DummyRegressor); NEW(m, [[1,2,3,4],[4,3,2,4],[5,4,-2,-6],[3,1,0,-1]], "Matrix"); END Demo; (*PROCEDURE Demo1*; (*associate new dataset with existing graph*) VAR h:Histogram; g:Graph; k: Graphs; gx:GraphXY; m:Matrix; s:Scatter; r:Regression; i:LONGINT; BEGIN {EXCLUSIVE} NEW(k, [[-2,7,8,4,5,9,6,4,7,8,4,5,9,6], [5,3,2,12,21,3,0,5,3,-2,12,17,4,1]], "MultiGraph"); NEW(g, [4,7,8,4,5,9,6,5,3,2,12,17,3,-3,2], "Graph"); FOR i:=0 TO 100000000 DO END; k.NewData( [[5,3,2,12,21,3,0,5,3,-2,12,17,4,1], [-2,7,8,4,5,9,6,4,7,8,4,5,9,6], [5-1,3,2-1,12,21-1,3,0,5-1,3,-2,12-1,17,4,1]] ); g.NewData([-2,7,8,4,5,9,6,4,7,8,4,5,9,6]); END Demo1;*) PROCEDURE Cleanup; VAR manager:WM.WindowManager; w,remove:WM.Window; BEGIN {EXCLUSIVE} manager:=WM.GetDefaultManager(); manager.lock.AcquireWrite; w:=manager.GetFirst(); WHILE w#NIL DO remove:=w; w:=manager.GetNext(w); IF (remove#NIL) & (remove IS Window) THEN manager.Remove(remove) END; END; manager.lock.ReleaseWrite; END Cleanup; BEGIN Modules.InstallTermHandler(Cleanup); Pos:=0; NewWindowPos(0); END WMSimpleGraphs. SystemTools.Free WMSimpleGraphs ~ SystemTools.FreeDownTo MatrixBase ~ Compiler.Compile -p=Win32G WMSimpleGraphs.Mod ~ WMSimpleGraphs.Demo1 ~