Axes and axes labeling


Q:How can I change the axis scales, so I can scroll or zoom a Chart ?


Use the corresponding axis "SetMinMax" method.
For datetime axes:

DELPHI CODE : 

  Chart1.BottomAxis.SetMinMax(EncodeDate(1997,1,1 ),EncodeDate(1997,12,31));

CBUILDER CODE

  Chart1->BottomAxis->SetMinMax(EncodeDate(1997,1,1 ),EncodeDate(1997,12,31));

For non-datetime axes:

DELPHI CODE : 

  Chart1.BottomAxis.SetMinMax(1234,5678);

CBUILDER CODE

 Chart1->BottomAxis->SetMinMax(1234.0,5678.0);

Q: How can I plot all axis labels ?


By default, axes try to avoid label overlapping by hiding some labels so there is enough space to plot the rest. You can disable this automatic "anti-overlapping" feature by setting the LabelsSeparation property to zero:

DELPHI CODE : 

  Chart1.BottomAxis.LabelsSeparation := 0 ;

CBuilder

  Chart1->BottomAxis->LabelsSeparation=0;

Other techniques to avoid overlapping could be setting the axis labels rotation angle to 90 degree to make them vertical:

DELPHI CODE : 

  Chart1.BottomAxis.LabelsAngle:=90;

CBUILDER CODE

  Chart1->BottomAxis->LabelsAngle=90;

Q: How can I set axis labels in exponential (scientific) format ?


Use Delphi's (or C++ Builder ) Formatting specifiers. Search help file for "Format" global method.

DELPHI CODE : 

 Chart1.BottomAxis.AxisValuesFormat := '0.0E+' ;

CBUILDER CODE

 Chart1->BottomAxis->AxisValuesFormat= "0.0E+";

Q: How to know the size in pixels of a certain range of values ?


Use the axes "CalcXSizeValue" (for horizontal pixels) or "CalcYSizeValue" (for vertical pixels) functions.

DELPHI CODE : 

  tmp := Chart1.BottomAxis.CalcXSizeValue(3.2);

CBUILDER CODE

 int tmp = Chart1->BottomAxis->CalcXSizeValue(3.2);

Q: Logarithmic Axis labels overlap


We have to fix this problem for future releases, but it's not as easy as it seems to fix.   A workaround is to use the same approach as in "loglabels.pas" example unit found at "TeeDemo.dpr" demo project. Using the OnGetNextAxisLabel event you can customize how many axis labels you want, and at which position you want them.


Q: Small values in axes do not show properly.


The default formatting string for axis labels is this:

#,##0.###

When you have very small values ( like for example : 1E-09 ), the above formatting string returns always the same format, as the values precision is more than 3 decimals ( ### ).

So, changing it to a suitable formatting specifier (like 0.################## ) or setting it to empty will show the labels correctly
.

DELPHI CODE : 

 Chart1.LeftAxis.AxisValuesFormat := '0.###################' ;

CBUILDER CODE : 

 Chart1->LeftAxis->AxisValuesFormat = "0.###################";

Q: Using TeeChart 3, I have problems with DateTime axis labels


There is a bug in TeeChart 3.0 that might hide date-time labels, depending on the series date ranges and axis Increment values. Usually, setting the axis ExactDateTime property to False solves this problem. This bug has been fixed in TeeChart Pro 4.0

DELPHI CODE : 

 Chart1.BottomAxis.ExactDateTime := False;

CBUILDER CODE

 Chart1->BottomAxis->ExactDateTime=false;

Q: How do I set the spacing between axis and axis title?


Depending on rotation or label values, label size is not calculated totally perfect. You can set the Chart1.LeftAxis.LabelsSize property to make this space a fixed value of pixels.


Q: When I am using values smaller than E-12, labeling fails. What am I doing wrong ?


There is a limit for Axis increment set at E-12 and a limit for minimal Axis range at E-11.
These constant are defined in TeEngine.pas. If you set range or increment to less than these
limits, then label values are automatically reset to Increment=1E-12 and Range=1E-11.
If you want to use smaller values, you can modify these constants in TeEngine.pas:

 minAxisIncrement:=0.000000000001; {<-1E-12, you can change it to smaller value}
 minAxisRange:=0.00000000001; {1E-11, you can change it to smaller value}

and then recompile packages with these new values.


Q: I'm using custom axis. Is there a way to clip points outside this axis?

All points outside the Chart1.ChartRect rectangle are clipped. You can change ChartRect() value to any Rect() value in the Series OnBeforeDrawValues event

DELPHI CODE : 

 Chart1.ChartRect:=Rect(100,100,250,250); {clip all points outside this rect}

CBUILDER CODE

 Chart1->ChartRect=Rect(100,100,250,250);

Q: When using small time increments, axis labeling does not work properly. How can I fix this?

First, convert TTime values to double, plot them, and in OnGetAxisLabel event change those values back to TTime format. Actually, you are plotting double values. They are converted to TTime format when axis labels are drawn (see the code bellow):

DELPHI CODE : 

procedure TForm1.FormCreate(Sender: TObject);
begin
// Add data
  Series1.AddXY(1,EncodeTime(0,0,2,0));
  Series1.AddXY(2,EncodeTime(0,0,2,250));
  Series1.AddXY(4,EncodeTime(0,0,2,500));
  Series1.AddXY(12,EncodeTime(0,0,2,600));
  Chart1.LeftAxis.AxisValuesFormat:='#0.000000'; 
	// Show 6 digits, you can do more if you like
  Chart1.LeftAxis.Title.Caption:='time (ss:mmm)';
end;

procedure TForm1.Chart1GetAxisLabel(Sender: TChartAxis;
Series: TChartSeries; ValueIndex: Integer; var LabelText: String);
var tmpTime:TTime;
h,m,s,ms:Word;
begin
  If Sender=Chart1.LeftAxis then // If labels from bottom axis
  begin
    tmpTime:=StrToFloat(LabelText); //First create TTime
    DecodeTime(tmpTime,h,m,s,ms);
    LabelText:=IntToStr(s)+':'+IntToStr(ms); // Rewrite label
  end;
end;

CBUILDER CODE

void __fastcall TForm1::FormCreate(TObject *Sender)
{
   Series1->AddXY(1,EncodeTime(0,0,2,0),"",clTeeColor);
   Series1->AddXY(2,EncodeTime(0,0,2,250),"",clTeeColor);
   Series1->AddXY(4,EncodeTime(0,0,2,500),"",clTeeColor);
   Series1->AddXY(12,EncodeTime(0,0,2,600),"",clTeeColor);
   Chart1->LeftAxis->AxisValuesFormat="#0.000000";
	// Show 6 digits, you can do more if you like
   Chart1->LeftAxis->Title->Caption="time (ss:mmm)";


}
//---------------------------------------------------------------------------

void __fastcall TForm1::Chart1GetAxisLabel(TChartAxis *Sender,
      TChartSeries *Series, int ValueIndex, AnsiString &LabelText)
{
   float tmpTime;
   Word h,m,s,ms;
   if (Sender==Chart1->LeftAxis) // If labels from left axis
   {
     tmpTime=StrToFloat(LabelText); //First create TTime
     DecodeTime(tmpTime,h,m,s,ms);
     LabelText=IntToStr(s)+":"+IntToStr(ms); // Rewrite label
   }
}
//---------------------------------------------------------------------------

Q: I cannot find a way to remove custom axis from a Chart

There is a bug in the TCustomChartAxis.Destroy destructor. The simplest solution is to call Chart.AxesList.Remove(cust_axis); method prior/after destroying it:

DELPHI CODE : 

tmpSer : TLineSeries;
tmpAxis : TChartAxis;

// create new stuff

tmpSer:=TLineSeries.Create(Self);
tmpSer.FillSampleValues(20);
tmpAxis:=TChartAxis.Create(Chart1);
tmpAxis.PositionPercent:=20;
tmpSer.CustomVertAxis:=tmpAxis;

tmpSer.ParentChart:=Chart1;

// now remove it

tmpSer.CustomVertAxis:=nil;
TChart(tmpSer.ParentChart).AxesList.Remove(tmpAxis);
tmpAxis.Destroy;
tmpSer.ParentChart:=nil;
tmpSer.Free;

CBUILDER CODE

void __fastcall TForm1::FormCreate(TObject *Sender)
{
  TLineSeries *tmpSer=new TLineSeries(this);
  TChartAxis *tmpAxis=new TChartAxis(Chart1);

  // create new stuff
  tmpSer->FillSampleValues(20);
  tmpAxis->PositionPercent=20;
  tmpSer->CustomVertAxis=tmpAxis;

  tmpSer->ParentChart=Chart1;

  // now remove it

  tmpSer->CustomVertAxis=NULL;
  dynamic_cast<TChart*>(tmpSer->ParentChart)->AxesList->Remove(tmpAxis);
  delete tmpAxis;
  tmpSer->ParentChart=NULL;
  delete tmpSer;

}

Q: How can I change the exponential format "E" to "10^" ?

Well, you can use Chart OnGetAxisLabel event to change "E" (or "e") to "10^"

DELPHI CODE : 

procedure TForm1.Chart1GetAxisLabel(Sender: TChartAxis;
Series: TChartSeries; ValueIndex: Integer; var LabelText: String);
var tmp:string;
begin
  if sender=Sender.ParentChart.BottomAxis then
  begin
    tmp:=LabelText;
    LabelText:=StringReplace(tmp,'E','10^',[rfIgnoreCase]);
  end;
end;

CBUILDER CODE

void __fastcall TForm1::Chart1GetAxisLabel(TChartAxis *Sender,
      TChartSeries *Series, int ValueIndex, AnsiString &LabelText)
{
   AnsiString label = LabelText;

   if (Sender==Chart1->BottomAxis)
   {
     int curPos=label.Pos("E");
     if (curPos)
     {
      label.Delete(curPos,1);
      label.Insert(" 10^",curPos);

      LabelText=label;
     }
   }

}

Q:Can an axis have a Log 2 base ?

Yes, sure. You can use the LogarithmicBase property to change the logarithmic base:

DELPHI CODE : 

 Chart1.BottomAxis.LogarithmicBase:=2;

CBUILDER CODE

 Chart1->BottomAxis->LogarithmicBase=2;

Q:Custom axes do not zoom. Any solutions?

Yes. custom axes do not zoom automatically. But you can zoom in and out (i.e. change the axis scale) in the Chart OnZoom and OnUndoZoom events:

DELPHI CODE : 

procedure TForm1.FormCreate(Sender: TObject);
var tmp: TChartAxis;
begin
        Series1.FillSampleValues(20);
        tmp:=TChartAxis.Create(Chart1);
        tmp.OtherSide:=true;
        tmp.PositionPercent:=20;
        Series1.CustomVertAxis:=tmp;
end;

procedure TForm1.Chart1Zoom(Sender: TObject);
begin
  With Series1.GetVertAxis do
    SetMinMax(CalcPosPoint(Chart1.IZoom.Y1),CalcPosPoint(Chart1.IZoom.Y0));
end;

procedure TForm1.Chart1UndoZoom(Sender: TObject);
begin
        Series1.GetVertAxis.Automatic:=true;
end;

CBUILDER CODE

//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
        TChartAxis* tmp=new TChartAxis(Chart1);

        tmp->OtherSide =true;
        tmp->PositionPercent=20;
        Series1->FillSampleValues(20);
        Series1->CustomVertAxis=tmp;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Chart1Zoom(TObject *Sender)
{
 Series1->GetVertAxis->SetMinMax(Series1->GetVertAxis->CalcPosPoint(Chart1->IZoom->Y1),
                                 Series1->GetVertAxis->CalcPosPoint(Chart1->IZoom->Y0));
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Chart1UndoZoom(TObject *Sender)
{
        Series1->GetVertAxis->Automatic=true;
}
//---------------------------------------------------------------------------