Page 1 of 1

3D Scatter Plots

Posted: Wed Dec 20, 2006 1:48 am
by 9241637
Is it possible to construct a scatter plot in which the points are located in 3-dimensional space, and have a certain depth?

I would like to be able to plot concentration data associated with soil samples (located by x,y) from specfic depth intervals (z-z') and then color code by concentration.

Thanks

Posted: Wed Dec 20, 2006 7:04 am
by Marjan
Hi.

Try using TPoint3DSeries. It more less does exactly what you need (gives you control over individual point z=z(x,y) coordinate).

Posted: Wed Dec 20, 2006 1:46 pm
by 9241637
Thanks....I also looked briefly at the TTeeCanvas3D.Cylinder

Cylinder(Vertical: Boolean; Left, Top, Right, Bottom, Z0, Z1: Integer; Dark3D: Boolean); override;

I'm guessing that the cylinder will work perfectly in my situation. I would also guess that if I set vertical to true, then Left and Right will be my X and Y; Z0 and Z1 would size my cylinder and set it in 3D space, but I am a little confused about Top and Bottom.

Any guidance would be appreciated.
Thanks
Craig

Posted: Thu Dec 21, 2006 11:58 am
by Marjan
Hi.

Hmm... I don't think this drawing method will mimic true 3d scatter plot.

The Cylinder canvas method will draw a vertical or horizontal cylinder using Left,Right,Top,Bottom as bounds in x-y (2d projection) plane and Z0 and Z1 as bounds in z plane. That is, the Z0 and Z1 (if not equal) define the "depth", Left, Right define left and right bounds of the cylinder (x coordinates) and Bottom, Top define bottom and top bounds (y coordinates) of cylinder.

Posted: Thu Dec 21, 2006 1:18 pm
by 9241637
Would "TCanvas3D.ZLine3D" work? I was thinking if I made the line heavy enough it may mimic a cylinder in 3D space, and a round point in 2D.

Posted: Fri Dec 22, 2006 9:16 am
by Marjan
Hi.

It should give you similar, but not the same look. The same could be achieved using MoveTo3D and LineTo3D methods.

To get a true 3d feel and look I'd stick with Cylinder method. Using it it'd be a lot easier to control the z coordinate (concentration). For example, the following code will draw a cylinder at specific z=z(x,y) coordinate:

Code: Select all

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var z0,z1: Integer;
    xc,yc: Integer;
    x,y,concentration: double;
begin
  With Chart1.Canvas, Chart1 do
  begin
    x := 2.2;
    y := 3.3;
    concentration := 1.5;
    xc := Axes.Bottom.CalcXPosValue(x);
    yc := Axes.Left.CalcYPosValue(y);
    z0 := Axes.Depth.CalcPosValue(0.0);
    z1 := Axes.Depth.CalcPosValue(1.5);
    Cylinder(true,xc-3,yc-3,xc+3,yc+3,z0,z1,false);
  end;
end;
IMHO, similarly you could also use the Cube method to describe concentration=concentration(x,y) relation:

Code: Select all

    Cube(xc-3,xc+3,yc-3,yc+3,z0,z1,false);

Posted: Fri Dec 22, 2006 12:56 pm
by 9241637
Marjan,

Thanks so much for all your help.

Craig

Posted: Tue Dec 26, 2006 2:55 pm
by 9241637
Marjan,

I got your example code to work! You suggestion of using the cube is a better approach.

Now, how do I get multiple cubes to show up? I have made line graphs using AddXY to a series. I think I want to have each cube be it's own Series that's color is based on concentration.

Thanks
Craig

Posted: Wed Dec 27, 2006 8:42 am
by Marjan
Hi, Craigh.

I'd derive new series type from one of 3d series and do the drawing in overriden DrawValue method. Bellow is a simple implementation:

Code: Select all

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, TeeSurfa, Series, ExtCtrls, TeeProcs, TeEngine, Chart;

type
  TForm1 = class(TForm)
    Chart1: TChart;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TConcentrationSeries = class (TCustom3DSeries)
    protected
      procedure DrawValue(ValueIndex: Integer); override;
    published
      property Brush;
      property Pen;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TConcentrationSeries }
procedure TConcentrationSeries.DrawValue(ValueIndex: Integer);
var z0,z1: Integer;
    xc,yc: Integer;
    tmpColor: TColor;
begin
  With ParentChart do
  begin
    xc := Axes.Bottom.CalcXPosValue(XValues[ValueIndex]);
    yc := Axes.Left.CalcYPosValue(YValues[ValueIndex]);
    z0 := Axes.Depth.CalcPosValue(0.0);
    z1 := Axes.Depth.CalcPosValue(ZValues[ValueIndex]);

    tmpColor := ValueColor[ValueIndex];
    Canvas.AssignVisiblePen(Pen);
    Canvas.Brush.Style := bsSolid;
    Canvas.Brush.Color := tmpColor;
    Canvas.Cube(xc-3,xc+3,yc-3,yc+3,z0,z1,false);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var ser1: TConcentrationSeries;
begin
  ser1 := TConcentrationSeries.Create(Chart1);
  ser1.ParentChart := Chart1;
  ser1.AddXYZ(2,3,1.5,'',clRed);
  ser1.AddXYZ(1,1,2.5,'',clWhite);
end;

end.