Page 1 of 1

MultiBar for TCandleSeries

Posted: Sat Apr 16, 2011 10:34 am
by 10547054
I would like to display multiple Candle series, but stagger them on the X axis, similar to MultiBar=mbSide
Is that possible?

I am really truing help my users visualize uncertainty.
AddCandle(X, u+1SD, u+2SD, u-2SD, u-1SD)

Multiple series overlap each other.

Thanks,
Steve

Re: MultiBar for TCandleSeries

Posted: Mon Apr 18, 2011 9:58 am
by 10050769
Hello Steve,

I have added your request as a feature request in wish-list with number [TV52015508] to be considered for inclusion in future releases. On the other hand,
I recommend you try to work with only one series and adding slightly different X values when you want values side and achieve the same effect as Multibar= mbSide.

Thanks,

Re: MultiBar for TCandleSeries

Posted: Mon Apr 18, 2011 10:30 am
by 10547054
I have five series that the users can enable/disable with a checkbox in the legends.

might there be any other series that allows mbSide, with a error-box that I can control both the upper and lower location of the box, as well as the upper and lower limits of the error bars?

Or is there a work-around I can make in the source code to emulate mbSide?

Re: MultiBar for TCandleSeries

Posted: Tue Apr 19, 2011 9:07 am
by 10050769
Hello Steve,
might there be any other series that allows mbSide, with a error-box that I can control both the upper and lower location of the box, as well as the upper and lower limits of the error bars?
Yes, you can try to do the same with error bar. I recommend take a look in Demo Project concretely in All features\Chart Style\Statistical .
Or is there a work-around I can make in the source code to emulate mbSide?
For now we don't have any work-around to it, but your request is in wish-list (TV52015508) to be considered inclusion in next versions, how I said previously.

Thanks,

Re: MultiBar for TCandleSeries

Posted: Tue Apr 19, 2011 11:32 am
by yeray
Hello Steve,

As an addition, I thought on a workaround.
You can inherit from the TBar3DSeries to create a new series that will have two errors.
Here you have a start point:

Code: Select all

uses Bar3D, Math;

type
  TBar3DErrorSeries = class(TBar3DSeries)
  private
    BarErrors, OffsetErrors: TChartValueList;
  protected
    procedure AddSample(Index: Integer; const Y: Double);
    procedure AddSampleValues(NumValues:Integer; OnlyMandatory:Boolean=False); override;
    procedure DrawBar(BarIndex,StartPos,EndPos:Integer); override;
  end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D:=false;

  for i:=0 to 4 do
  begin
    with Chart1.AddSeries(TBar3DErrorSeries) as TBar3DErrorSeries do
    begin
      BarErrors:=TChartValueList.Create(Chart1[i], 'BarErrors');
      OffsetErrors:=TChartValueList.Create(Chart1[i], 'OffsetErrors');

      FillSampleValues();
      Marks.Visible:=false;
    end;
  end;
end;

{ TBar3DErrorSeries }

procedure TBar3DErrorSeries.AddSampleValues(NumValues: Integer;
  OnlyMandatory: Boolean);
var t : Integer;
begin
  inherited;

  for t:=0 to NumValues-1 do
      AddSample(t, Max(YValues.MaxValue, OffsetValues.MaxValue) - Min(YValues.MinValue, OffsetValues.MinValue));
end;

procedure TBar3DErrorSeries.AddSample(Index: Integer; const Y: Double);

  function TempRandom:Double;
  begin
    result:=(20+RandomValue(4));
  end;

begin
  BarErrors.Value[Index]:=Y/TempRandom;
  OffsetErrors.Value[Index]:=Y/TempRandom;
end;

procedure TBar3DErrorSeries.DrawBar(BarIndex,StartPos,EndPos:Integer);
var XPos, BarPos, OffsetPos, BarErrPos, OffsetErrPos: Integer;
begin
  inherited;

  XPos:=CalcXPos(BarIndex) + BarWidth div 2;
  BarPos:=CalcYPosValue(YValue[BarIndex]);
  OffsetPos:=CalcYPosValue(OffsetValues[BarIndex]);

  if (YValues[BarIndex] > OffsetValues[BarIndex]) then
  begin
    BarErrPos:=CalcYPosValue(YValue[BarIndex] + BarErrors[BarIndex]);
    OffsetErrPos:=CalcYPosValue(OffsetValues[BarIndex] - OffsetErrors[BarIndex]);
  end
  else
  begin
    BarErrPos:=CalcYPosValue(YValue[BarIndex] - BarErrors[BarIndex]);
    OffsetErrPos:=CalcYPosValue(OffsetValues[BarIndex] + OffsetErrors[BarIndex]);
  end;

  if BarErrors[BarIndex]<>0 then
  begin
    if ParentChart.View3D then
      ParentChart.Canvas.VertLine3D(XPos, BarPos, BarErrPos, MiddleZ)
    else
      ParentChart.Canvas.DoVertLine(XPos, BarPos, BarErrPos);
  end;

  if OffsetErrors[BarIndex]<>0 then
  begin
    if ParentChart.View3D then
      ParentChart.Canvas.VertLine3D(XPos, OffsetPos, OffsetErrPos, MiddleZ)
    else
      ParentChart.Canvas.DoVertLine(XPos, OffsetPos, OffsetErrPos);
  end;
end;

Re: MultiBar for TCandleSeries

Posted: Wed Apr 20, 2011 2:19 pm
by 10547054
This is great, your sample code was very valuable.
I am down to a single issue, my left axis touches the left-most bar.

I am very appreciative of this level of support, including custom programming !

Re: MultiBar for TCandleSeries

Posted: Thu Apr 21, 2011 3:35 pm
by yeray
Hello Steve,

I'm happy to hear that! :D
vas wrote:I am down to a single issue, my left axis touches the left-most bar.
You could try setting some bottom axis MinimumOffset.

Re: MultiBar for TCandleSeries

Posted: Thu Apr 21, 2011 8:40 pm
by 10547054
I tried setting the MinimumOffset, which I really like, but failed.


Here is my feeble coding:

Code: Select all

unit EBar3D;

interface

uses
  Windows, Messages, SysUtils, Classes,
  Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
  Bar3D,TeEngine, TeeProcs, Chart, Series;

type
  TBar3DErrorSeries = class(TBar3DSeries)
  public
    Constructor Create(AOwner: TComponent); override;
    Function AddEBar( Const AX,ABHi,AEHi,AElo,ABLo:Double;
                      Const AXLabel:String='';
                      AColor:TColor=clTeeColor):Integer;
  private
     ErrValHi, ErrValLo: TChartValueList;
  protected
    procedure DrawBar(BarIndex,StartPos,EndPos:Integer); override;
  end;


  TBarChForm = class(TForm)
    Chart1: TChart;
    procedure CreateForm(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


var
  BarChForm: TBarChForm;

implementation

{$R *.dfm}

    { TBar3DErrorSeries }

    Constructor TBar3DErrorSeries.Create(AOwner: TComponent);
    begin
      inherited;
      ErrValHi := TChartValueList.Create(Self, 'ErrValHi');
      ErrValLo := TChartValueList.Create(Self, 'ErrValLo');
    end;

    Function TBar3DErrorSeries.AddEBar( Const AX,ABHi,AEHi,AElo,ABLo:Double;
                                        Const AXLabel:String='';
                                        AColor:TColor=clTeeColor):Integer;
    begin
      Marks.Visible:=false;
      XValues.DateTime := true;

      ErrValHi.TempValue := AEHi;
      ErrValLo.TempValue := AELo;
      Result := AddBar( AX, ABHi, ABLo, AXLabel, AColor );
    end;

    procedure TBar3DErrorSeries.DrawBar(BarIndex,StartPos,EndPos:Integer);
    var XPos, BarHiPos, BarLoPos, ErrHiPos, ErrLoPos: Integer;
    begin
      inherited;

      XPos:=CalcXPos(BarIndex) + BarWidth div 2;
      BarHiPos:=CalcYPosValue(YValue[BarIndex]);
      BarLoPos:=CalcYPosValue(OffsetValues[BarIndex]);

      ErrHiPos:=CalcYPosValue(ErrValHi[BarIndex]);
      ErrLoPos:=CalcYPosValue(ErrValLo[BarIndex]);

      if ErrValHi[BarIndex]<>0 then with ParentChart.Canvas do begin
        DoVertLine(XPos-1, BarHiPos, ErrHiPos);
        DoVertLine(XPos,   BarHiPos, ErrHiPos);  // make thicker error bars
        DoVertLine(XPos+1, BarHiPos, ErrHiPos);
        end;

      if ErrValLo[BarIndex]<>0 then with ParentChart.Canvas do begin
        DoVertLine(XPos-1, BarLoPos, ErrLoPos);
        DoVertLine(XPos,   BarLoPos, ErrLoPos);
        DoVertLine(XPos+1, BarLoPos, ErrLoPos);
        end;
    end;



procedure TBarChForm.CreateForm(Sender: TObject);
begin

  with Chart1 do begin
    AddSeries(TBar3DErrorSeries.Create(Chart1));
    AddSeries(TBar3DErrorSeries.Create(Chart1));
    BottomAxis.MinimumOffset := 10;
    BottomAxis.MaximumOffset := 10;

    View3D := false;
    with Series[0] as TBar3DErrorSeries do begin
      AddEBar(30000,20,25,10,15);
      AddEBar(30020,25,30,15,20);
      AddEBar(30040,30,35,20,25);
      AddEBar(30060,35,40,25,30);
      end;

    with Series[1] as TBar3DErrorSeries do begin
      AddEBar(30000,40,50,25,30);
      AddEBar(30020,35,45,20,25);
      AddEBar(30040,30,40,15,20);
      AddEBar(30060,25,35,10,15);
      end;

    ShowModal;
    end;
end;

end.

Re: MultiBar for TCandleSeries

Posted: Fri Apr 22, 2011 8:07 am
by yeray
Hello Steve,

Here's what I get with your code.
chart.png
chart.png (9.83 KiB) Viewed 20140 times
It seems that the left axis needs some adjustment, more than the bottom. You could calculate the min and max values and set them with the SetMinMax method or, alternatively, you could override the CalcVerticalMargins and CalcHorizontalMargins. Here you have the heathers:

Code: Select all

Procedure CalcVerticalMargins(Var TopMargin,BottomMargin:Integer); override;
Procedure CalcHorizMargins(var LeftMargin,RightMargin:Integer); override;
FYI:
- You may want to change is the Bar series CustomBarWidth to make the bars a little thiner.

- To make the error lines wider you could change the Pen.Width instead of drawing three lines:

Code: Select all

      ParentChart.Canvas.Pen.Width:=3;

      if ErrValHi[BarIndex]<>0 then with ParentChart.Canvas do
        DoVertLine(XPos,   BarHiPos, ErrHiPos);

      if ErrValLo[BarIndex]<>0 then with ParentChart.Canvas do
        DoVertLine(XPos,   BarLoPos, ErrLoPos);

Re: MultiBar for TCandleSeries

Posted: Fri Apr 22, 2011 12:48 pm
by 10547054
This service is beyond fantastic.
I implemented your suggestions about CustomBarWidth and PenWidth.

But my chart results differs from yours. I suspect I have an install error in Delphi,
so I am likely linked to an earlier version. I cannot see TeeChart Help either.

In any case, I am close enough.

Thank you very much.

Steve

Re: MultiBar for TCandleSeries

Posted: Fri Apr 22, 2011 7:28 pm
by 10547054
Here are my results.
I am guessing I have an install failure somewhere.
EBarFail.png
EBarFail.png (5.88 KiB) Viewed 20166 times

Re: MultiBar for TCandleSeries

Posted: Tue Apr 26, 2011 10:00 am
by narcis
Hi Steve,

Thank you very much for your compliments, much appreciated!

Which TeeChart version are you using? Have you tried using the latest version available at the client download area?

Thanks in advance.