How to make a Point 3D graph

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
Post Reply
IanF
Newbie
Newbie
Posts: 20
Joined: Tue Jul 04, 2017 12:00 am

How to make a Point 3D graph

Post by IanF » Wed May 16, 2018 7:38 am

I am trying to make a 3D view of a deviated well trace (using east, north and elevation), with the eventual hope of being able to rotate it on screen. I have created a test program and attached an image of my results.
3D_Chart.jpg
3D_Chart.jpg (195.25 KiB) Viewed 6886 times
I have a few queries:
1. I would have expected TeeChart to read the first three (comma-separated) columns as X, Y, Z and ignore any other fields but it seems to read the last three before an alphanumeric field. Why is this not the case?
2. When I make points invisible, I obtain symbols on the legend, which do not correspond to the point symbols. Why is this?
3. To make a "sensible" 3D graph, I need to input the data in east, elevation, north order. The only option in the Legend is the second column (Elevation). Is it possible to set different field(s) in the legend?
4. Is it possible to show each 25th point, say, in the legend, as can be set for marks?
5. I have a white rectangle on the screen which disappears only if I turn the axes off. What is this rectangle and how do I remove it?
6. I can rotate the graph at design time in 3D options. How can I rotate it at run time (preferably by using the mouse).
7. How do I round the marks to say 1 decimal place (without affecting the data).

I apologise for the lengthy list of queries.

Regards Errol

Yeray
Site Admin
Site Admin
Posts: 8971
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: How to make a Point 3D graph

Post by Yeray » Thu May 17, 2018 9:14 am

Hello Errol,
IanF wrote:1. I would have expected TeeChart to read the first three (comma-separated) columns as X, Y, Z and ignore any other fields but it seems to read the last three before an alphanumeric field. Why is this not the case?
There are some properties you could set to specify the separator and the index of each field in the rows:

Code: Select all

  With SeriesTextSource1 do
  begin
    FieldSeparator:=',';
    Fields.Clear;
    AddField('X',1);
    AddField('Y',2);
    AddField('Z',3);
  end;
IanF wrote:2. When I make points invisible, I obtain symbols on the legend, which do not correspond to the point symbols. Why is this?
How are you making points invisible?
Note the TPoint3DSeries has UseColorRange set to true by default. Setting it to false will make the legend to show an entry for each point in the series. With UseColorRange or UsePalette, the legend shows entries representing a palette, not the actual values in the series.
IanF wrote:3. To make a "sensible" 3D graph, I need to input the data in east, elevation, north order. The only option in the Legend is the second column (Elevation). Is it possible to set different field(s) in the legend?
Check the different lts* possibilities available for the Legend.TextStyle property. Ie:

Code: Select all

Chart1.Legend.TextStyle:=ltsXValue;
Alternatively, you could use the OnGetLegendText event as in this example:

Code: Select all

procedure TForm1.Chart1GetLegendText(Sender: TCustomAxisPanel;
  LegendStyle: TLegendStyle; Index: Integer; var LegendText: string);
begin
  if (Index>-1) and (Index<Series1.Count) then
    LegendText:=FormatFloat('#,##0.##', Series1.ZValue[Index]);
end;
IanF wrote:4. Is it possible to show each 25th point, say, in the legend, as can be set for marks?
I'm afraid the legend doesn't support this level of customization. However, you could draw your own legend manually at the OnAfterDraw event. Ie:

Code: Select all

const diff=25;

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var i, maxWidth, tmpX, tmpY, tmpH: Integer;
    legendItems: array of String;
const xoff = 4;
      yoff = 2;
      ypos = 10;
begin
  SetLength(legendItems, (Series1.Count div diff)+1);
  maxWidth:=0;

  with Chart1.Canvas do
  begin
    AssignBrush(Chart1.Legend.Brush);
    AssignVisiblePen(Chart1.Legend.Pen);
    AssignFont(Chart1.Legend.Font);
  end;

  for i:=0 to High(legendItems) do
  begin
    legendItems[i]:=FormatFloat('#,##0.##', Series1.ZValue[i*diff]);;
    maxWidth:=Max(maxWidth, Chart1.Canvas.TextWidth(legendItems[i]));
  end;

  tmpX:=Chart1.Width - maxWidth - 10;

  with Chart1.Canvas do
  begin
    tmpH:=TextHeight(legendItems[0]);
    Rectangle(tmpX - xoff, ypos, tmpX + maxWidth + xoff, tmpH * Length(legendItems) + ypos + yoff*2);

    for i:=0 to High(legendItems) do
    begin
      TextOut(tmpX, 12 + tmpH*i, legendItems[i]);
    end;
  end;
end;
IanF wrote:5. I have a white rectangle on the screen which disappears only if I turn the axes off. What is this rectangle and how do I remove it?
I'm not getting any strange rectangle. Could you please arrange a simple example project we can run as-is to reproduce the problem here?
Thanks in advance.
IanF wrote:6. I can rotate the graph at design time in 3D options. How can I rotate it at run time (preferably by using the mouse).
You can use the RotateTool:

Code: Select all

uses TeeTools;
//...
ChartTool1:=Chart1.Tools.Add(TRotateTool) as TRotateTool;
IanF wrote:7. How do I round the marks to say 1 decimal place (without affecting the data).
You can change the series ValueFormat. Ie:

Code: Select all

Series1.ValueFormat:='#,##0.#';
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

IanF
Newbie
Newbie
Posts: 20
Joined: Tue Jul 04, 2017 12:00 am

Re: How to make a Point 3D graph

Post by IanF » Mon May 21, 2018 6:52 am

Hi Yeray
Thank you for your comprehensive answers to my queries. However, I still have some questions (see example project attached).
1. I would like to put labels on the Left Axis, Bottom Axis and Depth Right Axis. However, at present, labels display only on Depth Top Axis, or Depth Right Axis which also displays the white rectangle I mentioned in a previous post. Labels used to display on Left Axis and Bottom Axis but they now don't.
2. How do I use Measured Depth as Marks down the Well Trace?
3. Is there an easy way to keep Bottom Axis and Depth Right Axis titles parallel to the axis, rather than at a fixed angle?

I look forward to your comments
Best regards
Errol
Attachments
Well_3D.zip
(22.39 KiB) Downloaded 331 times

IanF
Newbie
Newbie
Posts: 20
Joined: Tue Jul 04, 2017 12:00 am

Re: How to make a Point 3D graph

Post by IanF » Mon May 21, 2018 9:34 pm

Hi Yeray
Sorry attached the wrong example project (again). Here is the correct one.
Regards
Errol
Attachments
Well_3D.zip
(84.7 KiB) Downloaded 335 times

Yeray
Site Admin
Site Admin
Posts: 8971
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: How to make a Point 3D graph

Post by Yeray » Tue May 22, 2018 10:05 am

Hello,
IanF wrote:1. I would like to put labels on the Left Axis, Bottom Axis and Depth Right Axis. However, at present, labels display only on Depth Top Axis, or Depth Right Axis which also displays the white rectangle I mentioned in a previous post. Labels used to display on Left Axis and Bottom Axis but they now don't.
I see in the dfm you are setting the Items property for both Left and Bottom axes. Note this is done when you uncheck the "Automatic" checkbox in the "Chart\Axis\Items" tab in the editor.
If I remove those lines I see the labels.

I also found this line in dfm. Removing it, the shape disappears:

Code: Select all

    DepthAxis.Shape.Visible = True
IanF wrote:2. How do I use Measured Depth as Marks down the Well Trace?
Using automatic labels I believe it gives the expected labels in the bottom axis. Is this what you want?
IanF wrote:3. Is there an easy way to keep Bottom Axis and Depth Right Axis titles parallel to the axis, rather than at a fixed angle?
I'm afraid not. You could try to calculate the angles that better fit your requirements at your TRotateTool OnRotate event.
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

IanF
Newbie
Newbie
Posts: 20
Joined: Tue Jul 04, 2017 12:00 am

Re: How to make a Point 3D graph

Post by IanF » Wed May 23, 2018 4:12 am

Hi Yeray
Thanks for your help. However I still have some problems.
1. By importing the Measured Depth as Text in the Series DataSource option, I can present Measured Depth values as Marks (see attached image). However, numbers are now presented with 15 decimal places. Can you indicate how I could round these values before using as Marks.
Well3DMarks.jpg
Well3DMarks.jpg (97.53 KiB) Viewed 6842 times
2.
You could try to calculate the angles that better fit your requirements at your TRotateTool OnRotate event.
How do I find the angle of an axis in a 3D chart at any point of the rotation?
3. If the Title angle for the Depth Right axis is set to 0, it displays at 270. A workaround is to specify an angle of 1.
4. Also, the Depth Right title position is displayed too close to the axis and interferes with the axis labels. Is there any way to position the title?
5. I get a floating point overflow when I strongly zoom in. How should I prevent this from happening?
6. The 3D Chart option offers a 3D option for some points, which is not very effective. The cube displays as a thin slab, rather than a cube. Is there any way to customise the presentation of the points?.
I look forward to your comments.
Thanks and regards Errol
Attachments
Well_3D.zip
(185.59 KiB) Downloaded 318 times

Yeray
Site Admin
Site Admin
Posts: 8971
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: How to make a Point 3D graph

Post by Yeray » Mon May 28, 2018 11:17 am

Hello Errol,

I haven't been able to make the attached project to look as in your screenshot. The txt files may be wrong.
IanF wrote:1. By importing the Measured Depth as Text in the Series DataSource option, I can present Measured Depth values as Marks (see attached image). However, numbers are now presented with 15 decimal places. Can you indicate how I could round these values before using as Marks.
You are loading the Labels (text) from the column 1 of the Well_Devi_AT-203_Rel.txt file, and your series (Series1) has Marks.Style property set to smsLabelValue (Label Or Value) which means "show labels if present; otherwise show values". That's why it is drawing the strings you are loading from the first column of the file.
You could fix it by capturing the series OnGetMarkText, convert the mark strings to doubles and format them as you wish. Here I'm formatting them using the Series Valueformat:

Code: Select all

procedure TForm2.Series1GetMarkText(Sender: TChartSeries; ValueIndex: Integer;
  var MarkText: string);
var value: Double;
begin
  value:=StrToFloat(MarkText);
  MarkText:=FormatFloat(Sender.ValueFormat, value);
end;
IanF wrote:2.
You could try to calculate the angles that better fit your requirements at your TRotateTool OnRotate event.
How do I find the angle of an axis in a 3D chart at any point of the rotation?
There may be a better way, but you could calculate the start&end points for both axes and get the angle from them. Ie:

Code: Select all

procedure Tform2.ChartTool1Rotate(Sender: TObject);
var aStart, aEnd: TPoint;
    aStart2D, aEnd2D: TPoint3D;
    aAngle: Double;
begin
  aStart2D.x:=DBChart1.Axes.Bottom.IStartPos;
  aStart2D.y:=DBChart1.ChartRect.Bottom;
  aStart2D.z:=Round(DBChart1.Aspect.ZOffset);
  aStart:=DBChart1.Canvas.Calculate3DPosition(aStart2D);

  aEnd2D.x:=DBChart1.Axes.Bottom.IEndPos;
  aEnd2D.y:=DBChart1.ChartRect.Bottom;
  aEnd2D.z:=Round(DBChart1.Aspect.ZOffset);
  aEnd:=DBChart1.Canvas.Calculate3DPosition(aEnd2D);

  aAngle:=ArcTan2(aEnd.Y-aStart.Y, aEnd.X-aStart.X);
  DBChart1.Axes.Bottom.Title.Angle:=360-Round(aAngle/TeePiStep);

  aStart2D.x:=DBChart1.Axes.Depth.PosAxis;
  aStart2D.y:=DBChart1.ChartRect.Bottom;
  aStart2D.z:=DBChart1.Axes.Depth.IStartPos;
  aStart:=DBChart1.Canvas.Calculate3DPosition(aStart2D);

  aEnd2D.x:=DBChart1.Axes.Depth.PosAxis;
  aEnd2D.y:=DBChart1.ChartRect.Bottom;
  aEnd2D.z:=DBChart1.Axes.Depth.IEndPos;
  aEnd:=DBChart1.Canvas.Calculate3DPosition(aEnd2D);

  aAngle:=ArcTan2(aEnd.Y-aStart.Y, aEnd.X-aStart.X);
  DBChart1.Axes.Depth.Title.Angle:=360-Round(aAngle/TeePiStep);
end;
IanF wrote:3. If the Title angle for the Depth Right axis is set to 0, it displays at 270. A workaround is to specify an angle of 1.
I can't reproduce this one. If you still find problems here, please arrange a simple example project we can run as-is to reproduce the problem here.
IanF wrote:4. Also, the Depth Right title position is displayed too close to the axis and interferes with the axis labels. Is there any way to position the title?
I'm afraid the only way to control the margin between the axis title and the axes labels is to hide it and draw it manually at OnAfterDraw event:

Code: Select all

procedure TForm2.FormShow(Sender: TObject);
//...
  DBChart1.Axes.Depth.Title.Hide;
end;
procedure TForm2.DBChart1AfterDraw(Sender: TObject);
const off=20;
begin
  DBChart1.Canvas.RotateLabel3D(DBChart1.Axes.Depth.PosAxis+off*2,
           DBChart1.ChartRect.Bottom-Round(DBChart1.ChartHeight*DBChart1.Axes.Depth.ZPosition*0.01)+off,
           (DBChart1.Width3D div 2) + off,
           DBChart1.Axes.Depth.Title.Caption,DBChart1.Axes.Depth.Title.Angle,
           DBChart1.Axes.Depth.Title.TextFormat=ttfHtml);
end;
IanF wrote:5. I get a floating point overflow when I strongly zoom in. How should I prevent this from happening?
You can impede the user to keep zooming forcing a limit at OnMouseWheelUp. Ie:

Code: Select all

procedure TForm2.DBChart1MouseWheelUp(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  if DBChart1.Aspect.Zoom > 300 then
     DBChart1.Aspect.Zoom := 300;
end;
IanF wrote:6. The 3D Chart option offers a 3D option for some points, which is not very effective. The cube displays as a thin slab, rather than a cube. Is there any way to customise the presentation of the points?
I'm not sure what exact option do you mean. Could you please precise?
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Post Reply