aligning left axis of multiple charts

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
joepasquariello
Newbie
Newbie
Posts: 14
Joined: Thu Oct 09, 2014 12:00 am

aligning left axis of multiple charts

Post by joepasquariello » Mon Dec 01, 2014 5:49 am

Hello Yeray,

Was the change described above ever completed? I am using TeeChart Pro 2014 in RAD Studio XE7, and there is no "automatic" field of "ChartRect". In fact, ChartRect does not appear in the documentation at all.

I am trying to align left axes (by pixel) of multiple charts. The process I want to use is:

- enable automatic axis positioning
- find maximum X pixel position of multiple charts
- disable automatic axis positioning
- set X position of left axis for all charts

Is this possible? Is there an easier way?

Also, is there a diagram that shows the meaning of some of the various position values for TChart, TChartAxis, etc. A diagram would be very helpful to understand the relationships between all of these values.

Thank you.

Joe

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

Re: aligning left axis of multiple charts

Post by Yeray » Mon Dec 01, 2014 4:09 pm

Hello Joe,
joepasquariello wrote: Was the change described above ever completed? I am using TeeChart Pro 2014 in RAD Studio XE7, and there is no "automatic" field of "ChartRect". In fact, ChartRect does not appear in the documentation at all.
The question opening this thread refers to TeeChart Javascript / HTML5 version. Being a TeeChart VCL/FMX customer you'd better search and post on the according section of the forums:
http://www.teechart.net/support/viewforum.php?f=3
joepasquariello wrote:I am trying to align left axes (by pixel) of multiple charts. The process I want to use is:

- enable automatic axis positioning
- find maximum X pixel position of multiple charts
- disable automatic axis positioning
- set X position of left axis for all charts

Is this possible? Is there an easier way?
Take a look at the discussion that took place here:
http://www.teechart.net/support/viewtop ... =3&t=10620
joepasquariello wrote:Also, is there a diagram that shows the meaning of some of the various position values for TChart, TChartAxis, etc. A diagram would be very helpful to understand the relationships between all of these values.
I'm afraid there isn't such a diagram but I'd suggest you to read the Tutorials, the Help and to take a look at the Features demo program, both shipped with the binary installation.
If you still find any doubt, don't hesitate to ask us about any property or 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

joepasquariello
Newbie
Newbie
Posts: 14
Joined: Thu Oct 09, 2014 12:00 am

Re: aligning left axis of multiple charts

Post by joepasquariello » Tue Dec 02, 2014 7:57 am

Hello Yeray,

Thanks very much. Your example code for aligning left axes sets the width of the items to the left of the left axis (title, labels, ticks) to fixed sizes, so the left axis position (pixels) is always the same relative to the chart. This is okay. I would prefer to have a method that sets LabelsSize to the minimum value required for the data, and does not assume that the labels will fit within a specific number of pixels.

On the right side of the chart, I have a TChartLegend with a TLegendScrollBar on the right side. Currently I have no RightAxis. I was having trouble keeping the right end of the bottom axes aligned because the TChartLegend was resizing itself as the TLegendScrollBar was scrolled. I was able to prevent that by setting:

Legend->AutoScrollWidth = false;
Legend->ColumnWidths[0] = 80;

I also tried setting Legend->ResizeChart = false, but I still do not understand how to use ChartRect. There does not seem to be anything in the VCL help regarding ChartRect. Is ChartRect the rectangle bounded by the axes? The term "Chart" seems to sometimes be used to refer to the whole object, and other times to what I would call the "plot area".

So, I have something that works, but it uses fixed widths for LeftAxis->LabelsSize and Legend->ColumnWidth. If there is a way to "anchor" the ChartRect to some numbers of pixels relative to Top,Left and Bottom,Right, I think that's what I really want.

Joe

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

Re: aligning left axis of multiple charts

Post by Yeray » Tue Dec 02, 2014 9:38 am

Hello Joe,

Assuming your inquiry is about TeeChart VCL and has nothing to do with Teechart Javascript, I've split your messages to a new thread in the according section on the forums.
This discussion was started replying this thread:
http://www.teechart.net/support/viewtop ... 18&t=13705
joepasquariello wrote:Thanks very much. Your example code for aligning left axes sets the width of the items to the left of the left axis (title, labels, ticks) to fixed sizes, so the left axis position (pixels) is always the same relative to the chart. This is okay. I would prefer to have a method that sets LabelsSize to the minimum value required for the data, and does not assume that the labels will fit within a specific number of pixels.
Then you could do something more similar to what was done for the right axis in the mentioned thread. In your case, you could calculate the maximum labels size for all the left axes and set all them the same LabelsSize.

Code: Select all

uses Series;

var myCharts: Array of TCustomChart;

procedure TForm1.FormCreate(Sender: TObject);

  function addChart: TChart;
  var AChart: TChart;
  begin
    AChart:=TChart.Create(Self);
    AChart.Parent:=Self;
    AChart.Align:=alTop;
    AChart.View3D:=false;

    with AChart.AddSeries(TLineSeries) as TLineSeries do
    begin
      Pointer.Visible:=true;
      Pointer.HorizSize:=2;
      Pointer.VertSize:=2;
      FillSampleValues(100);
    end;

    result:=AChart;
  end;

begin
  setLength(myCharts, 2);
  myCharts[0]:=addChart;
  myCharts[1]:=addChart;

  myCharts[0].Axes.Left.Title.Text:='my left axis';
  myCharts[0].Draw;
  myCharts[1].Draw;

  LeftAlignCharts(myCharts);
end;

procedure TForm1.LeftAlignCharts(Const Charts: Array of TCustomChart);
var i: Integer;
    maxTitleSize, maxLabelsWidth: Integer;
    titleSize: Array of Integer;
    labelsWidth: Array of Integer;
    leftAxis: TChartAxis;
begin
  setLength(titleSize, length(Charts));
  maxTitleSize:=0;
  setLength(labelsWidth, length(Charts));
  maxLabelsWidth:=0;

  for i:=Low(Charts) to High(Charts) do
  begin
    leftAxis:=Charts[i].Axes.Left;

    titleSize[i]:=0;
    if (leftAxis.Title.Visible) and (leftAxis.Title.Text <> '') then
      titleSize[i]:=leftAxis.Title.Height;

    labelsWidth[i]:=0;
    if leftAxis.Labels then
      labelsWidth[i]:=leftAxis.MaxLabelsWidth;

    if (maxTitleSize<titleSize[i]) then
      maxTitleSize:=titleSize[i];

    if (maxLabelsWidth<labelsWidth[i]) then
      maxLabelsWidth:=labelsWidth[i];
  end;

  for i:=Low(Charts) to High(Charts) do
    With Charts[i] do
    begin
      MarginUnits:=muPixels;
      if (maxTitleSize>0) and (Axes.Left.Title.Text = '') then
        Axes.Left.Title.Text:=' ';

      Axes.Left.TitleSize:=maxTitleSize;
      Axes.Left.LabelsSize:=maxLabelsWidth;
    end;
end;
joepasquariello wrote:On the right side of the chart, I have a TChartLegend with a TLegendScrollBar on the right side. Currently I have no RightAxis. I was having trouble keeping the right end of the bottom axes aligned because the TChartLegend was resizing itself as the TLegendScrollBar was scrolled. I was able to prevent that by setting:

Legend->AutoScrollWidth = false;
Legend->ColumnWidths[0] = 80;

I also tried setting Legend->ResizeChart = false, but I still do not understand how to use ChartRect. There does not seem to be anything in the VCL help regarding ChartRect. Is ChartRect the rectangle bounded by the axes? The term "Chart" seems to sometimes be used to refer to the whole object, and other times to what I would call the "plot area".
Yes, we call "Chart" to the whole object (the TChart object), we use to call "ChartRect" to the area within the axes.

joepasquariello wrote:So, I have something that works, but it uses fixed widths for LeftAxis->LabelsSize and Legend->ColumnWidth. If there is a way to "anchor" the ChartRect to some numbers of pixels relative to Top,Left and Bottom,Right, I think that's what I really want.
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

joepasquariello
Newbie
Newbie
Posts: 14
Joined: Thu Oct 09, 2014 12:00 am

Re: aligning left axis of multiple charts

Post by joepasquariello » Fri Dec 05, 2014 2:35 am

Yeray,

I am now trying to improve the left axis alignment so that it is based on the actual data for the left axes. The function below works correctly, but I'm trying to understand when I should call it. I am using TChartLegend (with checkboxes) for each chart. I want to re-align left axes each time the user selects a new Series (from the Legend) for any chart. There don't seem to be any events for TChartLegend. Is there an event for clicking a checkbox or radio button in a TChartLegend? There seems to a lot of information missing from the VCL help.

Thanks very much.

Joe

Code: Select all

void TSnapViewMainForm::LeftAlignPlots( TList *ChartList )
{
  int MaxLabelsWidth = 0;
  int MaxMaxLabelsWidth = 0;
  // Find max value of MaxLabelsWidth() when LabelsSize==0 (auto label sizing)
  for (int i=0; i<ChartList->Count; i++) {
    TDBChart *DBChart = (TDBChart*)ChartList->Items[i];
    DBChart->Axes->Left->LabelsSize = 0;
    MaxLabelsWidth = DBChart->Axes->Left->MaxLabelsWidth();
    if (MaxLabelsWidth > MaxMaxLabelsWidth)
      MaxMaxLabelsWidth = MaxLabelsWidth;
  }
  // Set LabelsSize to width required for widest labels (disables auto sizing)
  for (int i=0; i<ChartList->Count; i++) {
    TDBChart *DBChart = (TDBChart*)ChartList->Items[i];
    DBChart->MarginUnits = muPixels;
    DBChart->MarginLeft = 0;
    DBChart->Axes->Left->TitleSize = 15;
    DBChart->Axes->Left->LabelsSize = MaxMaxLabelsWidth;
    DBChart->Axes->Left->LabelsAlign = alDefault;
    //DBChart->Axes->Left->Title->Caption = "Units";
  }
}

joepasquariello
Newbie
Newbie
Posts: 14
Joined: Thu Oct 09, 2014 12:00 am

Re: aligning left axis of multiple charts

Post by joepasquariello » Fri Dec 05, 2014 3:14 am

I think what I want is to use a TChartSeriesEvent (seChangeActive), but I don't see this event, or any events of this type, in the TChartSeries, TChartLegend, or TChart.

How do I use this type of event? Is there any object for which I can create such an event at design time?

Joe

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

Re: aligning left axis of multiple charts

Post by Yeray » Fri Dec 05, 2014 2:22 pm

Hi Joe,

You can use the TChart OnClickLegend event to catch when the user clicks on the legend.
In Delphi:

Code: Select all

uses Series;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.Legend.CheckBoxes:=true;

  for i:=0 to 4 do
    Chart1.AddSeries(TLineSeries).FillSampleValues;
end;

procedure TForm1.Chart1ClickLegend(Sender: TCustomChart;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  ShowMessage('Legend clicked');
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

joepasquariello
Newbie
Newbie
Posts: 14
Joined: Thu Oct 09, 2014 12:00 am

Re: aligning left axis of multiple charts

Post by joepasquariello » Fri Dec 05, 2014 8:28 pm

Hi Yeray,

OnLegendClick occurs on any click. What I am trying to detect is that a checkbox on the TChartLegend has changed state, so I know that the TChartSeries on the chart have changed. Is there a TChartSeries event that occurs when its Active field changes state? There must be some event that occurs when a TChartLegend checkbox changes state or a TChartSeries Active field changes True/False.

Can you please also direct me some information on TChartSeriesEvent? I don't find anything in the forum on that topic.

Joe

joepasquariello
Newbie
Newbie
Posts: 14
Joined: Thu Oct 09, 2014 12:00 am

Re: aligning left axis of multiple charts

Post by joepasquariello » Fri Dec 05, 2014 11:23 pm

Hi Yeray,

You were right. The OnClickLegend helps a lot because clicking on the legend almost always causes a TChartSeries to change Active = true/false. I can use the code shown below to identify the item that was clicked.

void __fastcall TSnapViewMainForm::DBChart1ClickLegend(TCustomChart *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
TDBChart *DBChart = (TDBChart*)Sender;
SeriesName = DBChart->Series[DBChart->Legend->Clicked(X,Y)]->Name;
}

Now I am trying to find an event associated with redrawing the chosen Series. If I use the OnBeforeDrawAxes event, the event occurs any time the mouse moves over the Legend. Is this the expected behavior?

Joe

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

Re: aligning left axis of multiple charts

Post by Yeray » Tue Dec 09, 2014 12:05 pm

Hi Joe,
joepasquariello wrote:You were right. The OnClickLegend helps a lot because clicking on the legend almost always causes a TChartSeries to change Active = true/false. I can use the code shown below to identify the item that was clicked.

void __fastcall TSnapViewMainForm::DBChart1ClickLegend(TCustomChart *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
TDBChart *DBChart = (TDBChart*)Sender;
SeriesName = DBChart->Series[DBChart->Legend->Clicked(X,Y)]->Name;
}
I'd consider handling the possibility that the Clicked function may return -1, if no series has been clicked. Ie:

Code: Select all

void __fastcall TSnapViewMainForm::DBChart1ClickLegend(TCustomChart *Sender, TMouseButton Button,  TShiftState Shift, int X, int Y)
{
  TDBChart *DBChart = (TDBChart*)Sender;
  index = DBChart->Legend->Clicked(X,Y);
  if (index > -1) {
    SeriesName = DBChart->Series[index]->Name;
  }
}
joepasquariello wrote:Now I am trying to find an event associated with redrawing the chosen Series. If I use the OnBeforeDrawAxes event, the event occurs any time the mouse moves over the Legend. Is this the expected behavior?
If you have the Hover feature active, then yes, the chart is repainted every time the mouse passes over a label, over a series and over a legend item.
You could use a global variable to store the index of the series being clicked in the legend and check it at OnBeforeDrawAxes. Ie, in Delphi:

Code: Select all

uses Series;

var seriesClicked: Integer;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.Legend.CheckBoxes:=true;

  for i:=0 to 4 do
    Chart1.AddSeries(TLineSeries).FillSampleValues;

  Chart1.OnClickLegend:=Chart1ClickLegend;
  Chart1.OnBeforeDrawAxes:=Chart1BeforeDrawAxes;

  seriesClicked:=-1;
end;

procedure TForm1.Chart1ClickLegend(Sender: TCustomChart;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  seriesClicked:=Sender.Legend.Clicked(X,Y);
end;

procedure TForm1.Chart1BeforeDrawAxes(Sender: TObject);
begin
  if seriesClicked > -1 then
  begin
    ShowMessage('Series Clicked: ' + IntToStr(seriesClicked));
    seriesClicked:=-1;
  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

joepasquariello
Newbie
Newbie
Posts: 14
Joined: Thu Oct 09, 2014 12:00 am

Re: aligning left axis of multiple charts

Post by joepasquariello » Tue Dec 09, 2014 4:26 pm

Thanks, Yeray. I will add the logic to test for Index > -1.

When you say "Hover is active", do you mean Hover->Visible = true?

Is there somewhere I can find a description of Hover?

Joe

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

Re: aligning left axis of multiple charts

Post by Yeray » Wed Dec 10, 2014 11:47 am

Hello Joe,
joepasquariello wrote:Is there somewhere I can find a description of Hover?
Yes, in the What's New page:
Mouse Hovering
When moving the mouse over some parts of a Chart, they are now highlighted.
This includes Series points, Legend, Axis labels and Annotation objects.

To disable hovering completely for a given chart, set the Hover.Visible property to False:

Code: Select all

Chart1.Hover.Visible := False;
When the above is True (the default), hovering can still be deactivated for individual items:

Code: Select all

// Series
Series1.Selected.Hover.Visible := False;

// Chart Legend
Chart1.Legend.Selected.Hover.Visible:=False;

// Axis labels
Chart1.Axes.Left.Texts.Selected.Visible:=False;
New tabs at editor dialogs allow customizing the new Selected and Hover properties.
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

joepasquariello
Newbie
Newbie
Posts: 14
Joined: Thu Oct 09, 2014 12:00 am

Re: aligning left axis of multiple charts

Post by joepasquariello » Wed Dec 10, 2014 6:39 pm

Thanks again, Yeray. That is good information. I don't understand why moving the mouse over the Legend should cause a redraw of the axes, and the entire chart, but for now I have it disabled completely. Since Hover is a new feature, I can understand why it is not in the Help file, but there seem to be a lot of other properties, functions, and whole classes missing from the Help. Does Steema have plans to at least mention all published properties in the Help?

When I click on a checkbox in the Legend, Series->Active changes between true and false. The LegendClick event occurs before Active changes value, and before the chart is redrawn, so I can't use that event directly to determine the width of axis labels. According to your suggestion, I am recording the index of the Series clicking in a global variable, and using that in OnBeforeDrawAxes(). It would be much simpler, though, to use an event directly associated with the change in Series->Active. There does seem to be such an event type (TChartSeriesEvent), but I can't find any way to use it. Is it possible to use these events in my own code?

Joe

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

Re: aligning left axis of multiple charts

Post by Yeray » Thu Dec 11, 2014 9:24 am

Hello Joe,
joepasquariello wrote:I don't understand why moving the mouse over the Legend should cause a redraw of the axes, and the entire chart, but for now I have it disabled completely.
Having the Hover active on the legend changes the series Pen. The chart needs to be repainted to apply these changes in the series Pen.
joepasquariello wrote:Since Hover is a new feature, I can understand why it is not in the Help file, but there seem to be a lot of other properties, functions, and whole classes missing from the Help. Does Steema have plans to at least mention all published properties in the Help?
What properties or methods do you find to be missing?
Note an online documentation is currently under development (preview here).
joepasquariello wrote:When I click on a checkbox in the Legend, Series->Active changes between true and false. The LegendClick event occurs before Active changes value, and before the chart is redrawn, so I can't use that event directly to determine the width of axis labels. According to your suggestion, I am recording the index of the Series clicking in a global variable, and using that in OnBeforeDrawAxes(). It would be much simpler, though, to use an event directly associated with the change in Series->Active. There does seem to be such an event type (TChartSeriesEvent), but I can't find any way to use it. Is it possible to use these events in my own code?
In the help, if I search for TChartSeriesEvent I get this (or here in the online docs):
TChartSeriesEvent

type TChartSeriesEvent = (seAdd, seRemove, seChangeTitle, seChangeColor, seSwap, seChangeActive, seDataChanged, seAfterRemove);

Unit
TeEngine

Description
TeeChart internal use. Event called when one of the above changes occurs with a Series.
If I check Chart1[seriesClicked].Active in OnBeforeDrawAxes event, I see it already has the updated value so I guess you mean you'd like to find an event where the chart has been drawn with the series list updated. Have you tried using OnAfterDraw event instead of OnBeforeDrawAxes 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

joepasquariello
Newbie
Newbie
Posts: 14
Joined: Thu Oct 09, 2014 12:00 am

Re: aligning left axis of multiple charts

Post by joepasquariello » Thu Dec 11, 2014 10:18 pm

Hi Yeray,

I think OnBeforeDrawAxes is better than OnAfterDraw for my purpose. The label widths are known in OnBeforeDrawAxes, and they can be modified before the draw occurs.

Some examples where Help is missing or incomplete are ChartRect (no Help), CloneChart (no description), and TLegendScrollBar (no Help).

I am trying to use CloneChart() to make a copy of a chart. The two charts will have the same set of series (with different names), but the Series in chart 1 and chart 2 will share the same data from a single TDataSet. Both charts have a Legend (lsSeries) and a TLegendScrollBar. In the first chart, as I move the scroll bar slider up and down, the slider remains the same size, and there are no problems. In the 2nd chart, as I move the slider down, it gets smaller and smaller, until an exception occurs. The problem only occurs if use CloneChart() or CloneChartSeries(). If I create the series for the two charts independently (not cloned), then both TLegendScrollBars work okay. Do you have any idea what I'm doing wrong?

Joe

Post Reply