where : ibrtses delphi

Delphi - simple multi graph plotting

disclaimer

the source code of this page may not appear correctly in certain browsers
due to special characters. Have a look at the source of this HTML page
with notepad instead

This class allows multiple graphs with different scaling to be drawn onto
same image.

a sample output

usage

be an existing image given :

var image1:TImage;

there is a class TMapwin, defined below, which does it all.

var mw1,mw2:TMapWin;	// define two graphs

 mw1:=TMapWin.create(image1);            // create in the image1 context
 mw1.left:=0; mw1.width:=image1.width;   // use the whole width of the image
 mw1.top:=0;  mw1.height:=image1.height; // use the full height of the image
 mw1.xlow:=0; mw1.xhigh:=2*pi;           // define the world [0..2pi,-1.1..1.1]
 mw1.ylow:=-1.1; mw1.yhigh:=1.1;

 for i:=0 to image1.width-1 do begin	// scan along X
   x:=mw1.getx(i);			// get the float of X
   y:=sin(x);				// calc the function
   mw1.putpixel(x,y,clBlack);            // display the point
  end;

and now a second graph :

 mw2:=TMapWin.create(image1);            // create in the image1 context
 mw2.left:=0; mw2.width:=image1.width;  // again the full image
 mw2.top:=0; mw2.height:=image1.height;
 mw2.xlow:=1e-6; mw2.xhigh:=1;		// a different world
 mw2.ylow:=-14; mw2.yhigh:=0;
 mw2.xlog:=true;			// logarithmic in X

 for i:=0 to image1.width-1 do begin	// as above ...
   x:=mw2.getx(i);
   y:=ln(x);
   mw2.putpixel(x,y,clred);
  end;

a cursor : // cursor predefined as cross on the image, label : mouselabel exists

procedure TForm1.ImageMouseMove(x,y:integer...);
var sx,sy:float;
begin
 mw1.screentofloat(x,y,sx,sy);
 mouselabel.caption:=format('%8.5g %8.5g',[sx,sy]);
end;


and now the class :

type
  float=extended;

  TMapWin = class(TObject)
  private
    { Private declarations }
   fimage:TImage;
   ftlx,ftly,fbrx,fbry,fwidth,fheight:integer;
   fxlow,fxhigh,fylow,fyhigh,fdx,fdy:float;
   fdrawclip,fxlog,fylog,fprotectlog:boolean;
  protected
    { Protected declarations }
   procedure setimage(i:TImage);
   procedure setTLX(u:integer);
   procedure setTLY(u:integer);
   procedure setWidth(u:integer);
   procedure setHeight(u:integer);
   procedure setxlow(z:float);
   procedure setxhigh(z:float);
   procedure setylow(z:float);
   procedure setyhigh(z:float);
   procedure setxlog(b:boolean);
   procedure setylog(b:boolean);
   function mapW2SxLin(xf:float):integer;
   function mapW2SyLin(yf:float):integer;
   function mapW2SxLog(xf:float):integer;
   function mapW2SyLog(yf:float):integer;
   function mapS2WxLin(xs:integer):float;
   function mapS2WyLin(ys:integer):float;
   function mapS2WxLog(xs:integer):float;
   function mapS2WyLog(ys:integer):float;
  public
    { Public declarations }
   constructor create(image:TImage);    // must exist or NIL
   destructor destroy; override;
   procedure FloatToScreen(xf,yf:float;var xs,ys:integer); virtual;
   procedure ScreenToFloat(xs,ys:integer;var xf,yf:float); virtual;
   procedure clear;
   procedure putpixel(x,y:float;color:TColor); virtual;
   procedure putline(x1,y1,x2,y2:float;color:TColor); virtual; // not yet
   procedure VLine(x:float;color:TColor); virtual; // vertical line
   procedure HLine(y:float;color:TColor); virtual; // horizontal line
   function getX(i:integer):float;             // i:=0..width-1
   function getY(i:integer):float;             // i:=0..height-1
  published
    { Published declarations }
   property image:TImage read fimage write setimage;
   property left:integer read ftlx write setTLX;     // with respect to image
   property top:integer read ftly write setTLY;     // with respect to image
   property width:integer read fwidth write setWidth;     // with respect to image
   property height:integer read fheight write setHeight;     // with respect to image
   property xlow:float read fxlow write setXLow;
   property ylow:float read fylow write setYLow;
   property xhigh:float read fxhigh write setXHigh;
   property yhigh:float read fyhigh write setYHigh;
   property dx:float read fdx;
   property dy:float read fdy;
   property drawclipped:boolean read fdrawclip write fdrawclip;
   property xlog:boolean read fxlog write setxlog;
   property ylog:boolean read fylog write setylog;
   property protectlog:boolean read fprotectlog write fprotectlog;
  end;

 


procedure Register;

implementation

uses math;

type TMyPlotException=Class(Exception);

//...........................................................................
procedure TMapWin.setimage(i:TImage);
begin fimage:=i; end;
procedure TMapWin.setTLX(u:integer);
begin ftlx:=u; end;
procedure TMapWin.setTLY(u:integer);
begin ftly:=u; end;
procedure TMapWin.setWidth(u:integer);
begin fbrx:=ftlx+u; fwidth:=u; end;
procedure TMapWin.setHeight(u:integer);
begin fbry:=ftly+u; fheight:=u; end;
procedure TMapWin.setxlow(z:float);
begin fxlow:=z; end;
procedure TMapWin.setxhigh(z:float);
begin fxhigh:=z; end;
procedure TMapWin.setylow(z:float);
begin fylow:=z; end;
procedure TMapWin.setyhigh(z:float);
begin fyhigh:=z; end;
procedure TMapWin.setxlog(b:boolean);
begin
 fxlog:=b;
 if b then begin // set log
  if xlow=0 then xlow:=1e-24;
  end;
end;
procedure TMapWin.setylog(b:boolean);
begin
 fylog:=b;
 if b then begin // set log
  if ylow=0 then ylow:=1e-24;
  end;
end;
function TMapWin.mapW2SxLin(xf:extended):integer;
begin
 result:=round(ftlx+(xf-fxlow)*(width)/(fxhigh-fxlow));
end;
function TMapWin.mapW2SyLin(yf:extended):integer;
begin
 result:=round(fbry-(yf-fylow)*(height)/(fyhigh-fylow));
end;
function TMapWin.mapW2SxLog(xf:extended):integer;
begin
 result:=round(ftlx+(ln(xf/fxlow)/ln(fxhigh/fxlow))*(width));
end;
function TMapWin.mapW2SyLog(yf:extended):integer;
begin
 result:=fbry-round((ln(yf/fylow)/ln(fyhigh/fylow))*(height));
end;
function TMapWin.mapS2WxLin(xs:integer):extended;
begin
 result:=fxlow+(xs-ftlx)*(fxhigh-fxlow)/(width);
end;
function TMapWin.mapS2WyLin(ys:integer):extended;
begin
 result:=fyhigh-(ys-ftly)*(fyhigh-fylow)/(height);
end;
function TMapWin.mapS2WxLog(xs:integer):extended;
begin
 result:=fxlow*exp(((xs-ftlx)/(width))*ln(fxhigh/fxlow));
end;
function TMapWin.mapS2WyLog(ys:integer):extended;
begin
 result:=fyhigh/exp(((ys-ftly)/(height)*ln(fyhigh/fylow)));
end;

constructor TMapWin.create(image:TImage);
begin
 inherited create;
 fimage:=image;
 fdrawclip:=true;
 fprotectlog:=true;
 xlow:=0; ylow:=0; xhigh:=1; yhigh:=1; xlog:=false; ylog:=false;
 ftlx:=0;ftly:=0;
 if image<>nil then begin
   width:=image.width;
   height:=image.height;
  end
 else begin
   width:=100; height:=100;
  end;
end;
destructor TMapWin.destroy;
begin
 inherited destroy;
end;



procedure TMapWin.FloatToScreen(xf,yf:float;var xs,ys:integer);
begin
 if ((fxlog)and(xf<0))or((fylog)and(yf<0)) then
   raise(TMyPlotException.create('TMapWin: Number for log axis smaller than zero'));
 if fxlog then xs:=mapW2SxLog(xf) else xs:=mapW2SxLin(xf);
 if fylog then ys:=mapW2SyLog(yf) else ys:=mapW2SyLin(yf);
end;
procedure TMapWin.ScreenToFloat(xs,ys:integer;var xf,yf:float);
begin
 if fxlog then xf:=mapS2WxLog(xs) else xf:=mapS2WxLin(xs);
 if fylog then yf:=mapS2WyLog(ys) else yf:=mapS2WyLin(ys);
end;
procedure TMapWin.clear;
begin
 if assigned(fimage) then begin
  fimage.canvas.Pen.color:=clWhite;
  fimage.canvas.brush.color:=clWhite;
  fimage.canvas.rectangle(ftlx,ftly,fbrx,fbry);
  end;
end;
procedure TMapWin.putpixel(x,y:float;color:TColor);
var ix,iy:integer;
var cx,cy:boolean;
begin
 if ((fxlog)and(x < 0))or((fylog)and(y < 0)) then begin
  if fprotectlog then
   exit
  else
   raise(TMyPlotException.create('Number for log axis smaller than zero'));
  end;
 cx:=false; cy:=false;  ix:=0; iy:=0;
 if (x < fxlow) then begin ix:=ftlx; cx:=true; end;
 if (x > fxhigh) then begin ix:=fbrx-1;  cx:=true; end;
 if (y < fylow) then begin iy:=fbry-1; cy:=true; end;
 if (y > fyhigh) then begin iy:=ftly; cy:=true; end;
 if not cx then begin
   if fxlog then ix:=mapW2SxLog(x)  else ix:=mapW2SxLin(x);
  end;
 if (not cy) then begin
  if fylog then iy:=mapW2SyLog(y) else iy:=mapW2SyLin(y);
 end;
 if (cx or cy)and(not fdrawclip) then exit;
 if assigned(fimage) then fimage.canvas.pixels[ix,iy]:=color;
end;

procedure TMapWin.putline(x1,y1,x2,y2:float;color:TColor);
 var cx1,cx2,cy1,cy2:integer;
begin

end;

procedure TMapWin.VLine(x:float;color:TColor); // vertical line
var ix,iy:integer;
cx:boolean;
begin
 if ((fxlog)and(x < 0))then begin
  if fprotectlog then
   exit
  else
   raise(TMyPlotException.create('Number for log axis smaller than zero'));
  end;
 cx:=false;  ix:=0; iy:=0;
 if (x < fxlow) then begin ix:=ftlx; cx:=true; end;
 if (x > fxhigh) then begin ix:=fbrx-1;  cx:=true; end;
 if not cx then begin
   if fxlog then ix:=mapW2SxLog(x)  else ix:=mapW2SxLin(x);
  end;
 if (cx)and(not fdrawclip) then exit;
 if assigned(fimage) then begin
  fimage.canvas.pen.color:=color;
  fimage.canvas.moveto(ix,ftly);
  fimage.canvas.lineto(ix,fbry);
  end;
end;

procedure TMapWin.HLine(y:float;color:TColor);  // horizontal line
var ix,iy:integer;
cy:boolean;
begin
 if ((fylog)and(y < 0))then begin
  if fprotectlog then
   exit
  else
   raise(TMyPlotException.create('Number for log axis smaller than zero'));
  end;
 cy:=false;  ix:=0; iy:=0;
 if (y < fylow) then begin iy:=fbry; cy:=true; end;
 if (y > fyhigh) then begin iy:=ftly-1;  cy:=true; end;
 if not cy then begin
   if fylog then iy:=mapW2SyLog(y)  else iy:=mapW2SyLin(y);
  end;
 if (cy)and(not fdrawclip) then exit;
 if assigned(fimage) then begin
  fimage.canvas.pen.color:=color;
  fimage.canvas.moveto(ftlx,iy);
  fimage.canvas.lineto(fbrx,iy);
  end;
end;

function TMapWin.getX(i:integer):float;             // i:=0..width-1
begin
 if fxlog then result:=mapS2WxLog(i) else result:=mapS2WxLin(i);
end;

function TMapWin.getY(i:integer):float;             // i:=0..height-1
begin
 if fylog then result:=mapS2WyLog(i) else result:=mapS2WyLin(i);
end;

findings

This class allows multiple graphs on top of and beside each other on just one TImage. TImage was choosen for its self redraw properties. It serves the purpose to display a multiple graphs and is not optimized.
This is a base class and may be extended to :


Feedback is welcome





sponsored links




Delphi
home

last updated: 26.may.00

Copyright (99,2000) Ing.Büro R.Tschaggelar