Page 1 of 1

"Carpet Plot" Labels

Posted: Thu Nov 03, 2022 11:28 am
by 16592554
I am trying to build a "Carpet Plot" of 2 intersecting groups of "Iso Lines" with labels on the lines showing the Iso value of the line. As the data grid is based on the 2 Iso parameters, I can't plot them as contours in TeeChart, so I have created a grid of XY Line series. I could not find any way to add a single label to a line series, so I created an invisible grid of single point Point Series and used the point label to display the line Iso value. The problem with this approach was that the point series labels hijacked the bottom axis and I had to tie them to an invisible top axis. See attached screen shots.

My questions are:
Is there a better way to create the Carpet Plot?
Is there a way to add a label to an arbitrary position (preferably in XY coordinates) on a Line Series?
Is there a way to add labels to a series point that does not mess up the XY axis?
2022-11-03 09_36_19-Window.png
Layout as required
2022-11-03 09_36_19-Window.png (45.29 KiB) Viewed 7916 times
2022-11-03 09_54_20-Window.png
Messed up X Axis
2022-11-03 09_54_20-Window.png (41.9 KiB) Viewed 7916 times

Re: "Carpet Plot" Labels

Posted: Mon Nov 07, 2022 3:04 pm
by yeray
Hello,

You could use TAnnotationTools to draw your texts. Ie:

Code: Select all

uses Series, TeeTools;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D:=False;
  Chart1.Gradient.Visible:=False;
  Chart1.Color:=clWhite;
  Chart1.Walls.Back.Gradient.Visible:=False;
  Chart1.Walls.Back.Color:=clWhite;

  Chart1.AddSeries(TLineSeries).FillSampleValues;

  Chart1.Draw;

  with TAnnotationTool(Chart1.Tools.Add(TAnnotationTool)) do
  begin
    Text:='Text for ValueIndex 5';
    Left:=Chart1[0].CalcXPos(5);
    Top:=Chart1[0].CalcYPos(5);
    Shape.Transparent:=True;
  end;
end;

Re: "Carpet Plot" Labels

Posted: Tue Nov 08, 2022 11:54 am
by 16592554
Is there a best practice for managing Annotations created at run-time as in your example? The main problem I am having is coping with repaints/rebuilds creating multiple copies of the same thing. The annotations don't seem to have a fixed name and selective deletion from the Tools array would rely on knowing the array position. The Annotation Text is not generally known at design time, so I can't use that without keeping a shadow copy of text somewhere. Or maybe I need to keep a local pointer to the annotation? It would be much easier if I could delete/remove in design-time code with a known name.

Re: "Carpet Plot" Labels

Posted: Tue Nov 08, 2022 1:11 pm
by yeray
Hello,

Indeed, you could store the annotations in variables, or in an array. Or you could just use the Tools array.
Find here an example showing how to add an annotation tool every time the chart is clicked and how to remove the annotation that is right-clicked:

Code: Select all

uses Series, TeeTools;

var mouseDownPos: TPoint;

procedure TForm1.Chart1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  mouseDownPos:=Point(X,Y);
end;

procedure TForm1.Chart1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var i: Integer;
    annotation: TAnnotationTool;
begin
  if (mouseDownPos.X = X) and (mouseDownPos.Y = Y) then
    if Button = mbRight then
    begin
      for i:=Chart1.Tools.Count-1 downto 0 do
        if Chart1.Tools[i] is TAnnotationTool then
        begin
          annotation:=TAnnotationTool(Chart1.Tools[i]);

          if annotation.Clicked(X, Y) then
          begin
            Chart1.Tools.Delete(Chart1.Tools.IndexOf(annotation));
            Chart1.Draw;
            Exit;
          end;
        end;
    end
    else
    if Button = mbLeft then
      with TAnnotationTool(Chart1.Tools.Add(TAnnotationTool)) do
      begin
        Text:='Annotation at X: ' + IntToStr(X) + ', Y: ' + IntToStr(Y);
        Left:=X;
        Top:=Y;
      end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D:=False;
  Chart1.Gradient.Visible:=False;
  Chart1.Color:=clWhite;
  Chart1.Walls.Back.Gradient.Visible:=False;
  Chart1.Walls.Back.Color:=clWhite;
  Chart1.Legend.Hide;

  Chart1.AddSeries(TLineSeries).FillSampleValues;
end;

Re: "Carpet Plot" Labels

Posted: Tue Nov 08, 2022 2:14 pm
by 16592554
Thanks, but it isn't really what I need. I am now thinking of using the component Tag property to mark sets of annotations for deletion, which should work. But in some cases it would still be better to have a fixed annotation "Name" available rather than having to store a link to the annotation so that I can access it directly for edit/deletion. Is it possible to add this feature?

Re: "Carpet Plot" Labels

Posted: Wed Nov 09, 2022 12:14 pm
by yeray
Hello,

Since the TAnnotationTool is a TComponent, it already has a Name property you can use. Ie:

Code: Select all

uses TeeTools;

procedure TForm1.BDeleteCheckedClick(Sender: TObject);
var i, j: Integer;
begin
  for i:=CheckListBox1.Items.Count-1 downto 0 do
    if CheckListBox1.Checked[i] then
      for j:=Chart1.Tools.Count-1 downto 0 do
        if Chart1.Tools[j].Name=CheckListBox1.Items[i] then
        begin
          Chart1.Tools.Delete(j);
          CheckListBox1.Items.Delete(i);
          break;
        end;

  Chart1.Draw;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  for i:=0 to 9 do
  begin
    with TAnnotationTool(Chart1.Tools.Add(TAnnotationTool)) do
    begin
      Name:='Annotation'+IntToStr(i);
      Text:='Annotation'+IntToStr(i);
      Left:=20+(i div 5)*80;
      Top:=20+(i mod 5)*24;
    end;

    CheckListBox1.Items.Add(Chart1.Tools[i].Name);
  end;
end;