Horizontal axis with multi-level categories (like Excel)

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
Post Reply
MIKE
Newbie
Newbie
Posts: 1
Joined: Fri Mar 04, 2016 12:00 am

Horizontal axis with multi-level categories (like Excel)

Post by MIKE » Fri Sep 09, 2016 12:45 pm

Is it possible?
Attachments
2016-09-09_15-36-01.png
2016-09-09_15-36-01.png (38.26 KiB) Viewed 5070 times

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

Re: Horizontal axis with multi-level categories (like Excel)

Post by Yeray » Mon Sep 12, 2016 9:05 am

Hello,

You can use SubAxes as follows:

Code: Select all

uses Series, TeePNG;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D:=false;
  Chart1.Legend.Alignment:=laTop;
  Chart1.Legend.LegendStyle:=lsSeries;
  Chart1.MarginBottom:=12;

  with Chart1.AddSeries(TLineSeries) as TLineSeries do
  begin
    FillSampleValues(12);
    Pointer.Visible:=true;

    for i:=0 to Count-1 do
      Labels[i]:='label ' + InttoStr(i);
  end;

  with Chart1.Axes.Bottom do
  begin
    MinorTicks.Visible:=false;
    Grid.Visible:=false;

    with SubAxes.Add do
    begin
      Visible:=True;
      Axis.Hide;
      MinorTicks.Hide;
      Ticks.Hide;
      Texts.MarginToAxis:=300;
      Items.Add(5.5, 'subaxis 3, label 1');
    end;

    with SubAxes.Add do
    begin
      Visible:=True;
      Axis.Hide;
      MinorTicks.Hide;
      Ticks.Hide;
      Texts.MarginToAxis:=200;
      Items.Add(2.5, 'subaxis 2, label 1');
      Items.Add(8.5, 'subaxis 2, label 2');
    end;

    with SubAxes.Add do
    begin
      Visible:=True;
      Axis.Hide;
      MinorTicks.Hide;
      Ticks.Hide;
      Texts.MarginToAxis:=100;
      Items.Add(1, 'subaxis 1, label 1');
      Items.Add(4, 'subaxis 1, label 2');
      Items.Add(7, 'subaxis 1, label 3');
      Items.Add(10, 'subaxis 1, label 3');
    end;
  end;

  Chart1.OnBeforeDrawAxes:=Chart1BeforeDrawAxes;
  Chart1.Draw;
end;

procedure TForm1.Chart1BeforeDrawAxes(Sender: TObject);
var y0, y1, x, i: Integer;
begin
  y0:=Chart1.Axes.Bottom.PosAxis-3;

  with Chart1.Canvas do
  begin
    Pen.Assign(Chart1.Axes.Bottom.TicksInner);

    for i:=0 to Chart1.Axes.Bottom.Items.Count-2 do
    begin
      x:=Chart1.Axes.Bottom.CalcPosValue(Chart1.Axes.Bottom.Items[i].Value + (Chart1.Axes.Bottom.Items[i+1].Value - Chart1.Axes.Bottom.Items[i].Value) / 2);
      if (i=2) or (i=8) then
        y1:=Chart1.Axes.Bottom.SubAxes[1].PosAxis+17
      else if (i=5) then
        y1:=Chart1.Axes.Bottom.SubAxes[0].PosAxis+30
      else
        y1:=Chart1.Axes.Bottom.SubAxes[2].PosAxis+7;
      
      VertLine3D(x, y0, y1, 0);
    end;
  end;
end;
subaxes.png
subaxes.png (16.02 KiB) Viewed 5050 times
Note I had to manually draw some of the ticks.
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: 9533
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Horizontal axis with multi-level categories (like Excel)

Post by Yeray » Mon Sep 12, 2016 9:44 am

Yeray wrote:Note I had to manually draw some of the ticks.
I've modified the code to draw the ticks to do it a more generic:

Code: Select all

uses Series, TeePNG;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D:=false;
  Chart1.Legend.Alignment:=laTop;
  Chart1.Legend.LegendStyle:=lsSeries;
  Chart1.MarginBottom:=12;

  with Chart1.AddSeries(TLineSeries) as TLineSeries do
  begin
    FillSampleValues(12);
    Pointer.Visible:=true;

    for i:=0 to Count-1 do
      Labels[i]:='label ' + InttoStr(i);
  end;

  with Chart1.Axes.Bottom do
  begin
    MinorTicks.Visible:=false;
    Grid.Visible:=false;

    with SubAxes.Add do
    begin
      Visible:=True;
      Axis.Hide;
      MinorTicks.Hide;
      Ticks.Hide;
      Texts.MarginToAxis:=300;
      Items.Add(5.5, 'subaxis 3, label 1');
    end;

    with SubAxes.Add do
    begin
      Visible:=True;
      Axis.Hide;
      MinorTicks.Hide;
      Ticks.Hide;
      Texts.MarginToAxis:=200;
      Items.Add(2.5, 'subaxis 2, label 1');
      Items.Add(8.5, 'subaxis 2, label 2');
    end;

    with SubAxes.Add do
    begin
      Visible:=True;
      Axis.Hide;
      MinorTicks.Hide;
      Ticks.Hide;
      Texts.MarginToAxis:=100;
      Items.Add(1, 'subaxis 1, label 1');
      Items.Add(4, 'subaxis 1, label 2');
      Items.Add(7, 'subaxis 1, label 3');
      Items.Add(10, 'subaxis 1, label 3');
    end;
  end;

  Chart1.OnBeforeDrawAxes:=Chart1BeforeDrawAxes;
  Chart1.Draw;
end;

procedure TForm1.Chart1BeforeDrawAxes(Sender: TObject);
var y0, y1, x, i, j, k: Integer;

  function calcTickYPos(AAxis: TChartAxis): Integer;
  var k: Integer;
  begin
    result:=-1;

    for k:=0 to AAxis.Items.Count-1 do
      if AAxis.Items[k].LabelPos = x then
      begin
        result:=AAxis.PosAxis + Round(Abs(AAxis.LabelsFont.Height)*AAxis.Texts.MarginToAxis*0.01);
        break;
      end;
  end;

begin
  y0:=Chart1.Axes.Bottom.PosAxis-3;

  with Chart1.Canvas do
  begin
    Pen.Assign(Chart1.Axes.Bottom.TicksInner);

    for i:=0 to Chart1.Axes.Bottom.Items.Count-2 do
    begin
      x:=Chart1.Axes.Bottom.CalcPosValue(Chart1.Axes.Bottom.Items[i].Value + (Chart1.Axes.Bottom.Items[i+1].Value - Chart1.Axes.Bottom.Items[i].Value) / 2);
      y1:=-1;
      
      for j:=0 to Chart1.Axes.Bottom.SubAxes.Count-1 do
      begin
        y1:=calcTickYPos(Chart1.Axes.Bottom.SubAxes[j]);
        if y1<>-1 then
          break;
      end;

      if (y1=-1) and (Chart1.Axes.Bottom.SubAxes.Count>0) then
        y1:=Chart1.Axes.Bottom.SubAxes[Chart1.Axes.Bottom.SubAxes.Count-1].PosAxis+Round(Abs(Chart1.Axes.Bottom.SubAxes[Chart1.Axes.Bottom.SubAxes.Count-1].LabelsFont.Height)*Chart1.Axes.Bottom.SubAxes[Chart1.Axes.Bottom.SubAxes.Count-1].Texts.MarginToAxis*0.01);
      
      VertLine3D(x, y0, y1, 0);
    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

Post Reply