Chart possible with Teechart?

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Chart possible with Teechart?

Post by vinc64 » Sun Jul 01, 2018 2:20 pm

Hi, can Teechart be used to create a "chart" like the image below? Basically just a series of squares with different colors and sorted by a specific value. I'm using Teechart 8.

Thanks in advance for any pointers.

Image: Image

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

Re: Chart possible with Teechart?

Post by Yeray » Mon Jul 02, 2018 7:58 am

Hello,

Here a simple example using TBarSeries:
Chart1.png
Chart1.png (32.65 KiB) Viewed 21868 times

Code: Select all

uses Series, TeeTools;

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var tmpX, tmpY0, tmpY1: Integer;
begin
  tmpX:=Chart1.ChartRect.Left+20;
  tmpY0:=Chart1.ChartRect.Top+50;
  tmpY1:=Chart1.ChartRect.Bottom-60;

  with Chart1.Canvas do
  begin
    VertLine3D(tmpX, tmpY0, tmpY1, 0);
    Line(tmpX, tmpY0, tmpX-5, tmpY0+5);
    Line(tmpX, tmpY0, tmpX+5, tmpY0+5);
    Line(tmpX, tmpY1, tmpX-5, tmpY1-5);
    Line(tmpX, tmpY1, tmpX+5, tmpY1-5);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i, j: Integer;
begin
  Chart1.View3D:=False;
  Chart1.Legend.Hide;
  Chart1.Axes.Top.LabelsFont.Style:=[fsBold];
  Chart1.Gradient.Visible:=False;
  Chart1.Color:=clWhite;
  Chart1.Walls.Hide;
  Chart1.Axes.Top.Grid.Hide;
  Chart1.Axes.Top.MinorTicks.Hide;
  Chart1.Axes.Top.Ticks.Hide;
  Chart1.Axes.Top.Axis.Hide;
  Chart1.Axes.Left.Hide;
  Chart1.Title.Hide;

  Chart1.Axes.Top.Items.Clear;
  for i:=0 to 9 do
  begin
    with Chart1.Axes.Top.Items.Add(i, IntToStr(2007+i)) do
    begin
      Format.Font.Style:=[fsBold];
      Format.Font.Name:='Verdana';
    end;

    with Chart1.AddSeries(TBarSeries) as TBarSeries do
    begin
      HorizAxis:=aTopAxis;
      MultiBar:=mbSelfStack;
      MarksOnBar:=True;
      MarksLocation:=mlCenter;
      Marks.Font.Color:=clWhite;
      Marks.Transparent:=True;
      Pen.Color:=clWhite;
      BarWidthPercent:=100;

      for j:=0 to 7 do
        AddBar(10,'s ' + IntToStr(i) + ', v ' + IntToStr(j), OperaPalette[(i*5+j) mod 12]);
    end;
  end;

  Chart1.Draw;

  with Chart1.Tools.Add(TRectangleTool) as TRectangleTool do
  begin
    Text:='Best';
    Shape.Angle:=90;
    Shape.Transparency:=0;
    Shape.Pen.Hide;
    Shape.AutoSize:=True;
    Shape.Font.Style:=[fsBold];
    Shape.Font.Name:='Verdana';
    AllowDrag:=False;
    AllowResize:=False;
    Left:=Chart1.ChartRect.Left;
    Top:=Chart1.ChartRect.Top+20;
  end;

  with Chart1.Tools.Add(TRectangleTool) as TRectangleTool do
  begin
    Text:='Worst';
    Shape.Angle:=90;
    Shape.Transparency:=0;
    Shape.Pen.Hide;
    Shape.AutoSize:=True;
    Shape.Font.Style:=[fsBold];
    Shape.Font.Name:='Verdana';
    AllowDrag:=False;
    AllowResize:=False;
    Left:=Chart1.ChartRect.Left-5;
    Top:=Chart1.ChartRect.Bottom-40;
  end;
end;
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

vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Re: Chart possible with Teechart?

Post by vinc64 » Mon Jul 02, 2018 8:01 am

Hi, thanks a lot, looks like exactly what I need.

Regards,
Vincenzo

vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Re: Chart possible with Teechart?

Post by vinc64 » Mon Jul 02, 2018 11:14 am

Does the sample code work with version 8? (VCL) When I compile it I get a few error messages of functions/fields not defined, e.g.

Chart1.Walls.Hide;
MarksOnBar:=True;
MarksLocation:=mlCenter;

vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Re: Chart possible with Teechart?

Post by vinc64 » Mon Jul 02, 2018 12:38 pm

I managed to compile the code by changing .hide to .visible := false (but had to remove MarksOnBar:=True; MarksLocation:=mlCenter;).
The chart I'm getting looks different from the example you provided, could it be because of the code I had to change or because I'm using a different Teechart version?

Image

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

Re: Chart possible with Teechart?

Post by Yeray » Tue Jul 03, 2018 7:20 am

Hello,

I see in TeeChart v8 the SelfStack MultiBar option doesn't work fine when using multiple TBarSeries, making this approach unusable in that version.
So I would try with a TPointSeries or a TShapeSeries to draw those squares.

If you still find problems with it, we'd need some extra information to try to prepare some example here.
Should all the squares be shown all the time or you'd allow to zoom (making the squares bigger) or scroll them? In the case of allowing to zoom, would you allow to modify their width/height relation?
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

vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Re: Chart possible with Teechart?

Post by vinc64 » Tue Jul 03, 2018 7:55 am

Hi,

Thanks for the reply. Not really sure how to implement this with TPoint/ShapeSeries hence an example would be appreciated. The squares should grow/shrink depending on the window size (holding the chart) but the dimension should remain proportionate (i.e. remain squares and not become rectangles). One additional "challenge" is that each data point in a series should retain the same color in all series (so that one can identify the position of an item in each series).

vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Re: Chart possible with Teechart?

Post by vinc64 » Tue Jul 03, 2018 8:22 am

I forgot to add that the squares should be always shown (no scrolling).

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

Re: Chart possible with Teechart?

Post by Yeray » Tue Jul 03, 2018 9:14 am

Hello,

You could create a class to store all the necessary information in a list. Ie:

Code: Select all

  TMyType=(macro, equity, futures, event, debt, conv_arbit, fix_arbit, market);

  TMyShape=class
    MyType: TMyType;
    Year: Integer;
    Value: Double;
    function GetColor: TColor;
    function GetText: String;
    constructor Create(AValue: Double; AYear: Integer; AType: TMyType);
  end;

function TMyShape.GetColor: TColor;
begin
  case MyType of
    macro: result:=$bab300;
    equity: result:=$67635e;
    futures: result:=$1e92f7;
    event: result:=$41BD81;
    debt: result:=$476800;
    conv_arbit: result:=$9f5105;
    fix_arbit: result:=$12b9fc;
    market: result:=$f1bd16;
  end;
end;

function TMyShape.GetText: String;
begin
  case MyType of
    macro: result:='Global'+sLineBreak+'macro';
    equity: result:='Long/short'+sLineBreak+'equity';
    futures: result:='Managed'+sLineBreak+'futures';
    event: result:='Event'+sLineBreak+'driven';
    debt: result:='Distressed'+sLineBreak+'debt';
    conv_arbit: result:='Convertible'+sLineBreak+'arbitrage';
    fix_arbit: result:='Fixed income'+sLineBreak+'arbitrage';
    market: result:='Equity market'+sLineBreak+'neutral';
  end;

  Result:=Result+sLineBreak+FormatFloat('#,##0.##', Value);
end;

constructor TMyShape.Create(AValue: Double; AYear: Integer; AType: TMyType);
begin
  Value:=AValue;
  Year:=AYear;
  MyType:=AType;
end;
I'm creating a list with all the items but it could be easier with a list for each column. Note I'm adding the data already sorted, so the sorting has still to be implemented. Also note I'm adding the same data from the second column.

Code: Select all

var i: Integer;
    myShapes: TList;
begin
  myShapes:=TList.Create;
  myShapes.Add(TMyShape.Create(-2.74, 2007, market));
  myShapes.Add(TMyShape.Create(3.32, 2007, fix_arbit));
  myShapes.Add(TMyShape.Create(3.37, 2007, conv_arbit));
  myShapes.Add(TMyShape.Create(3.69, 2007, debt));
  myShapes.Add(TMyShape.Create(3.77, 2007, event));
  myShapes.Add(TMyShape.Create(3.79, 2007, futures));
  myShapes.Add(TMyShape.Create(4.89, 2007, equity));
  myShapes.Add(TMyShape.Create(6.07, 2007, macro));

  for i:=0 to 8 do
  begin
    myShapes.Add(TMyShape.Create(-40.32, 2008+i, market));
    myShapes.Add(TMyShape.Create(-31.59, 2008+i, conv_arbit));
    myShapes.Add(TMyShape.Create(-28.82, 2008+i, fix_arbit));
    myShapes.Add(TMyShape.Create(-20.48, 2008+i, debt));
    myShapes.Add(TMyShape.Create(-19.76, 2008+i, equity));
    myShapes.Add(TMyShape.Create(-17.74, 2008+i, event));
    myShapes.Add(TMyShape.Create(-4.62, 2008+i, macro));
    myShapes.Add(TMyShape.Create(18.33, 2008+i, futures));
  end;
And finally the chart:

Code: Select all

var Chart1: TChart;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1:=TChart.Create(Self);
  Chart1.Parent:=Self;
  Chart1.Align:=alClient;

  Chart1.View3D:=False;
  Chart1.Legend.Hide;
  Chart1.Axes.Top.LabelsFont.Style:=[fsBold];
  Chart1.Gradient.Visible:=False;
  Chart1.Color:=clWhite;
  Chart1.Walls.Visible:=False;
  Chart1.Axes.Top.Grid.Hide;
  Chart1.Axes.Top.MinorTicks.Hide;
  Chart1.Axes.Top.Ticks.Hide;
  Chart1.Axes.Top.Axis.Hide;
  Chart1.Axes.Left.Visible:=False;
  Chart1.Title.Hide;
  Chart1.AllowZoom:=False;
  Chart1.AllowPanning:=pmNone;


  Chart1.Axes.Top.Items.Clear;
  for i:=2007 to 2016 do
  begin
    with Chart1.Axes.Top.Items.Add(i, IntToStr(i)) do
    begin
      Font.Style:=[fsBold];
      Font.Name:='Verdana';
    end;
  end;

  for i:=0 to myShapes.Count-1 do
    with Chart1.AddSeries(TChartShape) as TChartShape do
    begin
      HorizAxis:=aTopAxis;
      Font.Color:=clWhite;
      Pen.Color:=clWhite;
      Style:=chasRectangle;

      X0:=TMyShape(myShapes.Items[i]).Year-0.5;
      X1:=TMyShape(myShapes.Items[i]).Year+0.5;
      Y0:=MaxValueForYear(TMyShape(myShapes.Items[i]).Year);
      Y1:=Y0+1;
      Color:=TMyShape(myShapes.Items[i]).GetColor;
      Text.Text:=TMyShape(myShapes.Items[i]).GetText;
    end;

  Chart1.OnAfterDraw:=Chart1AfterDraw;
end;

function TForm1.MaxValueForYear(AYear: Integer): Double;
var i: Integer;
begin
  result:=0;

  for i:=0 to Chart1.SeriesCount-1 do
    with Chart1[i] as TChartShape do
      if (AYear > X0) and (AYear < X1) then
         Result:=Result+1;
end;

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var tmpX, tmpY0, tmpY1: Integer;
begin
  tmpX:=Chart1[0].CalcXPos(0) - 10;
  tmpY0:=Chart1.ChartRect.Top+50;
  tmpY1:=Chart1.ChartRect.Bottom-60;

  with Chart1.Canvas do
  begin
    RotateLabel(tmpX-7, tmpY0-10, 'Best', 90);
    RotateLabel(tmpX-7, tmpY1+45, 'Worst', 90);

    VertLine3D(tmpX, tmpY0, tmpY1, 0);
    Line(tmpX, tmpY0, tmpX-5, tmpY0+5);
    Line(tmpX, tmpY0, tmpX+5, tmpY0+5);
    Line(tmpX, tmpY1, tmpX-5, tmpY1-5);
    Line(tmpX, tmpY1, tmpX+5, tmpY1-5);
  end;
end;
This is how it looks with TeeChart v8:
Project3_2018-07-03_11-20-42.png
Project3_2018-07-03_11-20-42.png (24.07 KiB) Viewed 21846 times
However, resizing the Chart also resizes the squares to rectangles. This isn't a trivial feature.
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

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

Re: Chart possible with Teechart?

Post by Yeray » Tue Jul 03, 2018 9:37 am

Yeray wrote:However, resizing the Chart also resizes the squares to rectangles. This isn't a trivial feature.
An option would be to set the scales of the axes at OnResize event, with the MakeIsoAxis. As follows:

Code: Select all

procedure TForm1.ChartResize(Sender: TObject);
begin
  MakeIsoAxis(Chart1.Axes.Left, Chart1.Axes.Top);
end;

procedure TForm1.MakeIsoAxis(Vertical, Horizontal: TChartAxis);
var tmpX,
    tmpY,
    XRange,
    YRange,
    Offset,
    XYScreen,
    XMin,
    XMax,
    YMin,
    YMax : Double;
begin
  with Vertical.ParentChart do
  if (ChartHeight>0) and (ChartWidth>0) then
  begin
    XMin:=Chart1.MinXValue(Horizontal);
    XMax:=Chart1.MaxXValue(Horizontal);
    YMin:=Chart1.MinYValue(Vertical);
    YMax:=Chart1.MaxYValue(Vertical);

    XRange:=XMax-XMin;

    tmpX:=(XRange/ChartWidth);

    {$IFDEF CLX}
    XYScreen:=1024.0/768.0;  //TODO
    {$ELSE}
    XYScreen:=1.0*(GetDeviceCaps(Canvas.Handle,HORZSIZE)/Screen.Width)/
                  (GetDeviceCaps(Canvas.Handle,VERTSIZE)/Screen.Height);
    {$ENDIF}

    YRange:=YMax-YMin;

    tmpY:=(YRange/ChartHeight)*XYScreen;

    if tmpX>tmpY then
    begin
      if tmpY<>0 then
      begin
        Offset:=((YRange*tmpX/tmpY)-YRange)/2.0;
        With Vertical do SetMinMax(YMin-Offset,YMax+Offset);
      end;
    end
    else
    if tmpX<tmpY then
    begin
      if tmpX<>0 then
      begin
        Offset:=((XRange*tmpY/tmpX)-XRange)/2.0;
        With Horizontal do SetMinMax(XMin-Offset,XMax+Offset);
      end;
    end;
  end;
end;
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

vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Re: Chart possible with Teechart?

Post by vinc64 » Tue Jul 03, 2018 10:46 am

Thanks a lot for the example code! (Noted about the sorting and rectangles).

If I upgrade to the latest version would then the original code achieve the same? (Since it looks more compact than than the v8 code).

vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Re: Chart possible with Teechart?

Post by vinc64 » Tue Jul 03, 2018 11:45 am

I integrated your example code into my project and it looks good, thanks for all the help!

Vincenzo

vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Re: Chart possible with Teechart?

Post by vinc64 » Tue Jul 03, 2018 1:40 pm

Sorry one more question... in determining at which position which square should be drawn it seems to be driven by the following code:

Code: Select all

      X0:=TMyShape(myShapes.Items[i]).Year-0.5;
      X1:=TMyShape(myShapes.Items[i]).Year+0.5;
      Y0:=MaxValueForYear(TMyShape(myShapes.Items[i]).Year);
      Y1:=Y0+1;
Other than years I might show monthly data (e.g. Jan to October), or 3-year periods (2000, 2003, 2006 etc), how would I then need to change the X0/X1 values? (are those coordinates within the chart?)

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

Re: Chart possible with Teechart?

Post by Yeray » Thu Jul 05, 2018 7:22 am

Hello,
vinc64 wrote:Other than years I might show monthly data (e.g. Jan to October), or 3-year periods (2000, 2003, 2006 etc), how would I then need to change the X0/X1 values? (are those coordinates within the chart?)
Yes, they are values in the axis scale.
Note the labels in the top axis are directly showing the axis values. I populate the shapes with "X0:=Year-05" and "X1:=Year+0.5" to have those Years in the Top axis.
If you want to show months, you could store them also as integers, populate the shapes with Month-05 and Month+05 and then use the OnGetAxisLabel event to convert those values to month names. Something like this:

Code: Select all

procedure TForm1.Chart1GetAxisLabel(Sender: TChartAxis; Series: TChartSeries;
  ValueIndex: Integer; var LabelText: string);
begin
  if (Sender = Chart1.Axes.Bottom) then
  begin
    ValueIndex:=StrToIntDef(LabelText, -1)+1;
    if ValueIndex>0 then
       LabelText:=LongMonthNames[ValueIndex mod 12];
  end;
end;
Regarding "3-year periods (2000, 2003, 2006 etc)", you could still store the Year and then populate the shapes with "X0:=Year-1.5" and "X1:=Year+1.5".
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

vinc64
Newbie
Newbie
Posts: 30
Joined: Fri Jan 23, 2009 12:00 am

Re: Chart possible with Teechart?

Post by vinc64 » Thu Jul 05, 2018 7:48 am

Thanks for the reply, will try it out.

Post Reply